63 changed files with 180355 additions and 0 deletions
-
14xd-file-preview/.editorconfig
-
21xd-file-preview/.gitignore
-
42xd-file-preview/.npmignore
-
201xd-file-preview/LICENSE
-
207xd-file-preview/README.md
-
10xd-file-preview/alias.config.js
-
5xd-file-preview/babel.config.js
-
103xd-file-preview/build/autoload.js
-
40xd-file-preview/build/clog.js
-
70xd-file-preview/build/commands/copy.js
-
35xd-file-preview/build/entries.create.page.js
-
182xd-file-preview/build/fileHepler.js
-
9xd-file-preview/build/path.js
-
19xd-file-preview/build/plugins/CreatedComponentsPlugin.js
-
53xd-file-preview/build/template/api.js
-
5xd-file-preview/build/template/autoload.txt
-
11xd-file-preview/build/template/entry.js
-
60xd-file-preview/build/template/module.js
-
7xd-file-preview/build/template/sub-component.txt
-
20xd-file-preview/build/template/test-data.js
-
39xd-file-preview/devServer.js
-
2xd-file-preview/index.js
-
8xd-file-preview/lib/demo.html
-
74080xd-file-preview/lib/gxd.common.js
-
74090xd-file-preview/lib/gxd.umd.js
-
27xd-file-preview/lib/gxd.umd.min.js
-
27096xd-file-preview/package-lock.json
-
101xd-file-preview/package.json
-
BINxd-file-preview/public/favicon.ico
-
18xd-file-preview/public/index.html
-
BINxd-file-preview/public/static/999.ofd
-
BINxd-file-preview/public/static/PlayerAPI_v1.0.6.pdf
-
8xd-file-preview/public/static/helper.css
-
321xd-file-preview/public/static/helper.js
-
17xd-file-preview/public/static/index.html
-
17xd-file-preview/public/static/index.txt
-
44xd-file-preview/settings.js
-
182xd-file-preview/src/App.vue
-
BINxd-file-preview/src/assets/water-bg.png
-
250xd-file-preview/src/components/XdFileListPreview.vue
-
60xd-file-preview/src/components/XdLoadPdfScript.vue
-
131xd-file-preview/src/components/XdPdf.vue
-
48xd-file-preview/src/components/contact.js
-
350xd-file-preview/src/components/preview/helper.js
-
18xd-file-preview/src/components/preview/image.js
-
554xd-file-preview/src/components/preview/imageView.vue
-
143xd-file-preview/src/components/preview/index.js
-
17xd-file-preview/src/components/preview/json.js
-
309xd-file-preview/src/components/preview/jsonView.vue
-
55xd-file-preview/src/components/preview/loading.vue
-
17xd-file-preview/src/components/preview/ofd.js
-
18xd-file-preview/src/components/preview/office.js
-
198xd-file-preview/src/components/preview/officeView.vue
-
17xd-file-preview/src/components/preview/pdf.js
-
305xd-file-preview/src/components/preview/pdfView.vue
-
88xd-file-preview/src/components/preview/style.css
-
17xd-file-preview/src/components/preview/text.js
-
397xd-file-preview/src/components/preview/textView.vue
-
5xd-file-preview/src/directives/index.js
-
56xd-file-preview/src/directives/waterMark.js
-
31xd-file-preview/src/install.js
-
18xd-file-preview/src/main.js
-
89xd-file-preview/vue.config.js
@ -0,0 +1,14 @@ |
|||
# https://editorconfig.org |
|||
root = true |
|||
|
|||
[*] |
|||
charset = utf-8 |
|||
indent_style = space |
|||
indent_size = 2 |
|||
end_of_line = lf |
|||
insert_final_newline = true |
|||
trim_trailing_whitespace = true |
|||
|
|||
[*.md] |
|||
insert_final_newline = false |
|||
trim_trailing_whitespace = false |
@ -0,0 +1,21 @@ |
|||
.DS_Store |
|||
node_modules |
|||
/dist |
|||
|
|||
# local env files |
|||
.env.local |
|||
.env.*.local |
|||
|
|||
# Log files |
|||
npm-debug.log* |
|||
yarn-debug.log* |
|||
yarn-error.log* |
|||
|
|||
# Editor directories and files |
|||
.idea |
|||
.vscode |
|||
*.suo |
|||
*.ntvs* |
|||
*.njsproj |
|||
*.sln |
|||
*.sw? |
@ -0,0 +1,42 @@ |
|||
.DS_Store |
|||
node_modules |
|||
/dist |
|||
|
|||
/src/assets |
|||
/src/data |
|||
/src/styles |
|||
/src/utils |
|||
/src/view |
|||
/src/App.vue |
|||
/src/main.js |
|||
|
|||
/build |
|||
/public |
|||
/alias.config.js |
|||
/babel.config.js |
|||
/devServer.js |
|||
/settings.js |
|||
/vue.config.js |
|||
/lib/dome.html |
|||
/lib/gxd.umd.js |
|||
/lib/gxd.common.js |
|||
|
|||
|
|||
|
|||
# local env files |
|||
.env.local |
|||
.env.*.local |
|||
|
|||
# Log files |
|||
npm-debug.log* |
|||
yarn-debug.log* |
|||
yarn-error.log* |
|||
|
|||
# Editor directories and files |
|||
.idea |
|||
.vscode |
|||
*.suo |
|||
*.ntvs* |
|||
*.njsproj |
|||
*.sln |
|||
*.sw? |
@ -0,0 +1,201 @@ |
|||
Apache License |
|||
Version 2.0, January 2004 |
|||
http://www.apache.org/licenses/ |
|||
|
|||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION |
|||
|
|||
1. Definitions. |
|||
|
|||
"License" shall mean the terms and conditions for use, reproduction, |
|||
and distribution as defined by Sections 1 through 9 of this document. |
|||
|
|||
"Licensor" shall mean the copyright owner or entity authorized by |
|||
the copyright owner that is granting the License. |
|||
|
|||
"Legal Entity" shall mean the union of the acting entity and all |
|||
other entities that control, are controlled by, or are under common |
|||
control with that entity. For the purposes of this definition, |
|||
"control" means (i) the power, direct or indirect, to cause the |
|||
direction or management of such entity, whether by contract or |
|||
otherwise, or (ii) ownership of fifty percent (50%) or more of the |
|||
outstanding shares, or (iii) beneficial ownership of such entity. |
|||
|
|||
"You" (or "Your") shall mean an individual or Legal Entity |
|||
exercising permissions granted by this License. |
|||
|
|||
"Source" form shall mean the preferred form for making modifications, |
|||
including but not limited to software source code, documentation |
|||
source, and configuration files. |
|||
|
|||
"Object" form shall mean any form resulting from mechanical |
|||
transformation or translation of a Source form, including but |
|||
not limited to compiled object code, generated documentation, |
|||
and conversions to other media types. |
|||
|
|||
"Work" shall mean the work of authorship, whether in Source or |
|||
Object form, made available under the License, as indicated by a |
|||
copyright notice that is included in or attached to the work |
|||
(an example is provided in the Appendix below). |
|||
|
|||
"Derivative Works" shall mean any work, whether in Source or Object |
|||
form, that is based on (or derived from) the Work and for which the |
|||
editorial revisions, annotations, elaborations, or other modifications |
|||
represent, as a whole, an original work of authorship. For the purposes |
|||
of this License, Derivative Works shall not include works that remain |
|||
separable from, or merely link (or bind by name) to the interfaces of, |
|||
the Work and Derivative Works thereof. |
|||
|
|||
"Contribution" shall mean any work of authorship, including |
|||
the original version of the Work and any modifications or additions |
|||
to that Work or Derivative Works thereof, that is intentionally |
|||
submitted to Licensor for inclusion in the Work by the copyright owner |
|||
or by an individual or Legal Entity authorized to submit on behalf of |
|||
the copyright owner. For the purposes of this definition, "submitted" |
|||
means any form of electronic, verbal, or written communication sent |
|||
to the Licensor or its representatives, including but not limited to |
|||
communication on electronic mailing lists, source code control systems, |
|||
and issue tracking systems that are managed by, or on behalf of, the |
|||
Licensor for the purpose of discussing and improving the Work, but |
|||
excluding communication that is conspicuously marked or otherwise |
|||
designated in writing by the copyright owner as "Not a Contribution." |
|||
|
|||
"Contributor" shall mean Licensor and any individual or Legal Entity |
|||
on behalf of whom a Contribution has been received by Licensor and |
|||
subsequently incorporated within the Work. |
|||
|
|||
2. Grant of Copyright License. Subject to the terms and conditions of |
|||
this License, each Contributor hereby grants to You a perpetual, |
|||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable |
|||
copyright license to reproduce, prepare Derivative Works of, |
|||
publicly display, publicly perform, sublicense, and distribute the |
|||
Work and such Derivative Works in Source or Object form. |
|||
|
|||
3. Grant of Patent License. Subject to the terms and conditions of |
|||
this License, each Contributor hereby grants to You a perpetual, |
|||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable |
|||
(except as stated in this section) patent license to make, have made, |
|||
use, offer to sell, sell, import, and otherwise transfer the Work, |
|||
where such license applies only to those patent claims licensable |
|||
by such Contributor that are necessarily infringed by their |
|||
Contribution(s) alone or by combination of their Contribution(s) |
|||
with the Work to which such Contribution(s) was submitted. If You |
|||
institute patent litigation against any entity (including a |
|||
cross-claim or counterclaim in a lawsuit) alleging that the Work |
|||
or a Contribution incorporated within the Work constitutes direct |
|||
or contributory patent infringement, then any patent licenses |
|||
granted to You under this License for that Work shall terminate |
|||
as of the date such litigation is filed. |
|||
|
|||
4. Redistribution. You may reproduce and distribute copies of the |
|||
Work or Derivative Works thereof in any medium, with or without |
|||
modifications, and in Source or Object form, provided that You |
|||
meet the following conditions: |
|||
|
|||
(a) You must give any other recipients of the Work or |
|||
Derivative Works a copy of this License; and |
|||
|
|||
(b) You must cause any modified files to carry prominent notices |
|||
stating that You changed the files; and |
|||
|
|||
(c) You must retain, in the Source form of any Derivative Works |
|||
that You distribute, all copyright, patent, trademark, and |
|||
attribution notices from the Source form of the Work, |
|||
excluding those notices that do not pertain to any part of |
|||
the Derivative Works; and |
|||
|
|||
(d) If the Work includes a "NOTICE" text file as part of its |
|||
distribution, then any Derivative Works that You distribute must |
|||
include a readable copy of the attribution notices contained |
|||
within such NOTICE file, excluding those notices that do not |
|||
pertain to any part of the Derivative Works, in at least one |
|||
of the following places: within a NOTICE text file distributed |
|||
as part of the Derivative Works; within the Source form or |
|||
documentation, if provided along with the Derivative Works; or, |
|||
within a display generated by the Derivative Works, if and |
|||
wherever such third-party notices normally appear. The contents |
|||
of the NOTICE file are for informational purposes only and |
|||
do not modify the License. You may add Your own attribution |
|||
notices within Derivative Works that You distribute, alongside |
|||
or as an addendum to the NOTICE text from the Work, provided |
|||
that such additional attribution notices cannot be construed |
|||
as modifying the License. |
|||
|
|||
You may add Your own copyright statement to Your modifications and |
|||
may provide additional or different license terms and conditions |
|||
for use, reproduction, or distribution of Your modifications, or |
|||
for any such Derivative Works as a whole, provided Your use, |
|||
reproduction, and distribution of the Work otherwise complies with |
|||
the conditions stated in this License. |
|||
|
|||
5. Submission of Contributions. Unless You explicitly state otherwise, |
|||
any Contribution intentionally submitted for inclusion in the Work |
|||
by You to the Licensor shall be under the terms and conditions of |
|||
this License, without any additional terms or conditions. |
|||
Notwithstanding the above, nothing herein shall supersede or modify |
|||
the terms of any separate license agreement you may have executed |
|||
with Licensor regarding such Contributions. |
|||
|
|||
6. Trademarks. This License does not grant permission to use the trade |
|||
names, trademarks, service marks, or product names of the Licensor, |
|||
except as required for reasonable and customary use in describing the |
|||
origin of the Work and reproducing the content of the NOTICE file. |
|||
|
|||
7. Disclaimer of Warranty. Unless required by applicable law or |
|||
agreed to in writing, Licensor provides the Work (and each |
|||
Contributor provides its Contributions) on an "AS IS" BASIS, |
|||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
|||
implied, including, without limitation, any warranties or conditions |
|||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A |
|||
PARTICULAR PURPOSE. You are solely responsible for determining the |
|||
appropriateness of using or redistributing the Work and assume any |
|||
risks associated with Your exercise of permissions under this License. |
|||
|
|||
8. Limitation of Liability. In no event and under no legal theory, |
|||
whether in tort (including negligence), contract, or otherwise, |
|||
unless required by applicable law (such as deliberate and grossly |
|||
negligent acts) or agreed to in writing, shall any Contributor be |
|||
liable to You for damages, including any direct, indirect, special, |
|||
incidental, or consequential damages of any character arising as a |
|||
result of this License or out of the use or inability to use the |
|||
Work (including but not limited to damages for loss of goodwill, |
|||
work stoppage, computer failure or malfunction, or any and all |
|||
other commercial damages or losses), even if such Contributor |
|||
has been advised of the possibility of such damages. |
|||
|
|||
9. Accepting Warranty or Additional Liability. While redistributing |
|||
the Work or Derivative Works thereof, You may choose to offer, |
|||
and charge a fee for, acceptance of support, warranty, indemnity, |
|||
or other liability obligations and/or rights consistent with this |
|||
License. However, in accepting such obligations, You may act only |
|||
on Your own behalf and on Your sole responsibility, not on behalf |
|||
of any other Contributor, and only if You agree to indemnify, |
|||
defend, and hold each Contributor harmless for any liability |
|||
incurred by, or claims asserted against, such Contributor by reason |
|||
of your accepting any such warranty or additional liability. |
|||
|
|||
END OF TERMS AND CONDITIONS |
|||
|
|||
APPENDIX: How to apply the Apache License to your work. |
|||
|
|||
To apply the Apache License to your work, attach the following |
|||
boilerplate notice, with the fields enclosed by brackets "[]" |
|||
replaced with your own identifying information. (Don't include |
|||
the brackets!) The text should be enclosed in the appropriate |
|||
comment syntax for the file format. We also recommend that a |
|||
file or class name and description of purpose be included on the |
|||
same "printed page" as the copyright notice for easier |
|||
identification within third-party archives. |
|||
|
|||
Copyright [yyyy] [name of copyright owner] |
|||
|
|||
Licensed under the Apache License, Version 2.0 (the "License"); |
|||
you may not use this file except in compliance with the License. |
|||
You may obtain a copy of the License at |
|||
|
|||
http://www.apache.org/licenses/LICENSE-2.0 |
|||
|
|||
Unless required by applicable law or agreed to in writing, software |
|||
distributed under the License is distributed on an "AS IS" BASIS, |
|||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
See the License for the specific language governing permissions and |
|||
limitations under the License. |
@ -0,0 +1,207 @@ |
|||
# Gxd-vue-file-preview |
|||
|
|||
#### 介绍 |
|||
```text |
|||
vue 文件在线预览展示功能,支持文件(PDF,PNG,JPEG,JPG,GIF,DOC,DOCX,PPT,PPTX,ELXS,ELX) |
|||
``` |
|||
|
|||
#### 预览 |
|||
```markdown |
|||
 |
|||
``` |
|||
|
|||
|
|||
#### 安装 |
|||
```bash |
|||
npm i gxd-file-preview --save --registry https://registry.npm.taobao.org |
|||
``` |
|||
|
|||
#### 插件全局引用 |
|||
``` javascript |
|||
|
|||
import vueFilePreview from 'gxd-file-preview'; |
|||
|
|||
//初始化自定义插件,(pdf.js,worker.js文件建议放在本地服务器),cdn有可能不稳定 |
|||
Vue.use(vueFilePreview,{ |
|||
pdf: 'https://cdn.jsdelivr.net/npm/pdfjs-dist@2.0.288/build/pdf.min.js', //pdf插件 |
|||
worker:'https://cdn.jsdelivr.net/npm/pdfjs-dist@2.0.288/build/pdf.worker.min.js',//pdf.work插件 |
|||
}); |
|||
|
|||
``` |
|||
|
|||
|
|||
#### 插件使用 |
|||
```vue |
|||
<template> |
|||
<div id="app"></div> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
name: 'app', |
|||
components: {}, |
|||
data(){ |
|||
return {} |
|||
}, |
|||
created() { |
|||
setTimeout(()=>{ |
|||
this.$preview({ |
|||
//url: 'https://testimg.tiangongy.com/100601/a024b86760bb1ff3b38f25ae2e0b9bdf', //图片 |
|||
//url: 'https://testimg.tiangongy.com/100601/9958ff80d202f91b347b14b5c56f14e8', // xlsx |
|||
//url: 'https://testimg.tiangongy.com/100601/12d7e6a9b0b9169b800fbb29061212c2', //pptx |
|||
//url: 'https://testimg.tiangongy.com/100601/ce44c69f3075334e6c624b8180a42804', //doc, |
|||
//url: 'https://testimg.tiangongy.com/100601/3b85b4f1c3accdb4bb9f7e42e1f9070e', |
|||
url:'http://storage.xuetangx.com/public_assets/xuetangx/PDF/PlayerAPI_v1.0.6.pdf', |
|||
fid: '12121212' |
|||
}) |
|||
}, 2000); |
|||
|
|||
}, |
|||
methods:{ |
|||
|
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style> |
|||
</style> |
|||
``` |
|||
|
|||
```vue |
|||
<template> |
|||
<div id="app"> |
|||
<h1>列表展示</h1> |
|||
<xd-file-list-preview |
|||
:show-close="showClose" |
|||
:list="list" @remove="handleRemoveClick" |
|||
:is-pagination="isPagination" |
|||
></xd-file-list-preview> |
|||
<hr> |
|||
<h1>文件预览模式</h1> |
|||
<a @click="handleClick" style="color: #4285f4">9958ff80d202f91b347b14b5c56f14e811</a> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
interface FileItemFormat { |
|||
url:string; //文件路径(绝对路径) |
|||
name?: string; //文件名称 |
|||
fid?: string; //文件ID |
|||
download?: string; //预览页面是否显示下载按钮 |
|||
} |
|||
export default { |
|||
name: 'app', |
|||
components: {}, |
|||
data() { |
|||
return { |
|||
showClose: true, //是否开启删除功能 |
|||
isPagination: true, //列表启动翻页功能 |
|||
/**@type FileItemFormat **/ |
|||
list: [ |
|||
{url: 'http://storage.xuetangx.com/public_assets/xuetangx/PDF/PlayerAPI_v1.0.6.pdf'}, |
|||
{url: 'https://jfb-public-images.oss-cn-qingdao.aliyuncs.com/admin-upload/202111081034429231.png?x-oss-process=style/common'}, |
|||
{url: 'http://static.e56buy.com/XdgfsqR2INp7uFxTuLQtnMstYLY4K8rr.蛋糕缺少内容.docx', name: 'aaaa'}, |
|||
{ |
|||
url: 'http://storage.xuetangx.com/public_assets/xuetangx/PDF/PlayerAPI_v1.0.6.pdf', |
|||
name: 'aaaa', |
|||
fid: 'aadadads', |
|||
download: false ,//是否展示下载按钮 |
|||
}, |
|||
] |
|||
} |
|||
}, |
|||
created() { |
|||
}, |
|||
methods: { |
|||
/** |
|||
* @description 删除图片事件 |
|||
* @param item {Object} 当前被删除的文件对象 |
|||
* @param done {function} 删除文件完成回调函数 |
|||
*/ |
|||
handleRemoveClick(item, done) { |
|||
setTimeout(() => { |
|||
console.log('handleRemoveClick', item); |
|||
done() |
|||
}, 2000); |
|||
}, |
|||
|
|||
/** |
|||
* @description 点击查看预览功能 |
|||
*/ |
|||
handleClick() { |
|||
this.$preview({ |
|||
url: 'http://storage.xuetangx.com/public_assets/xuetangx/PDF/PlayerAPI_v1.0.6.pdf', |
|||
fid: 'aadadads', |
|||
download: false ,//是否展示下载按钮 |
|||
}) |
|||
}, |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style> |
|||
</style> |
|||
``` |
|||
|
|||
##### 项目开发下载与初始化 |
|||
|
|||
```bash |
|||
# 克隆项目 |
|||
git clone git@gitee.com:e56buy/xd-file-preview.git |
|||
|
|||
# 进入项目目录 |
|||
cd xd-file-preview |
|||
|
|||
# 安装依赖 |
|||
npm install |
|||
|
|||
# 建议不要直接使用 cnpm 安装依赖,会有各种诡异的 bug。 |
|||
建议通过npm按照,通过如下操作解决 npm 下载速度慢的问题 |
|||
npm install --save --registry=https://registry.npm.taobao.org |
|||
``` |
|||
##### Nginx配置静态资源可以跨域访问(注意访问静态资源需要做跨域处理) |
|||
```text |
|||
|
|||
#全局模式 |
|||
|
|||
server { |
|||
listen 80; |
|||
add_header 'Access-Control-Allow-Origin' '*'; |
|||
location /Roboto/ { |
|||
root /home/images; |
|||
autoindex on; |
|||
} |
|||
} |
|||
|
|||
#文件路径配置访问 |
|||
|
|||
#访问路径拼接img访问本地绝对路径下的某图片 |
|||
location /img/ { |
|||
#跨域配置,如果不生效请先清除浏览器缓存数据 |
|||
add_header 'Access-Control-Allow-Origin' '*'; |
|||
add_header 'Access-Control-Allow-Credentials' 'true'; |
|||
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; |
|||
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type'; |
|||
expires 30d; |
|||
#当访问https://server_name/img/路径时,就会访问本的/Users/chokshen/Desktop/img/文件夹 |
|||
root /Users/chokshen/Desktop/; |
|||
error_log off; |
|||
access_log /dev/null; |
|||
autoindex on; |
|||
} |
|||
|
|||
``` |
|||
|
|||
```text |
|||
版本日志 |
|||
1.2.0 |
|||
1、新增JSON,TXT,JS,HTML,CSS预览功能 |
|||
2、列表展示功能新增 预览模式时候 左右翻页功能 |
|||
|
|||
1.1.18 |
|||
优化文档显示 |
|||
|
|||
1.1.17 |
|||
修复预览offic系列访问不成功问题 |
|||
``` |
|||
|
@ -0,0 +1,10 @@ |
|||
'use strict'; |
|||
const resolve = dir => require('path').join(__dirname, dir); |
|||
|
|||
module.exports = { |
|||
resolve: { |
|||
alias: { |
|||
'@': resolve('src'), |
|||
} |
|||
} |
|||
}; |
@ -0,0 +1,5 @@ |
|||
module.exports = { |
|||
presets: [ |
|||
'@vue/app' |
|||
] |
|||
} |
@ -0,0 +1,103 @@ |
|||
'use strict'; |
|||
|
|||
const path = require('path'); |
|||
const basePath = require('./path'); |
|||
const fileHandle = require('./fileHepler'); |
|||
const fs = require("fs"); |
|||
const clog = require('./clog'); |
|||
|
|||
/** |
|||
* 递归创建目录 |
|||
* @param dirname |
|||
* @returns {boolean} |
|||
*/ |
|||
const mkdirsSync = dirname => { |
|||
if (fs.existsSync(dirname)) { |
|||
return true; |
|||
} else { |
|||
if (mkdirsSync(path.dirname(dirname))) { |
|||
fs.mkdirSync(dirname); |
|||
return true; |
|||
} |
|||
} |
|||
}; |
|||
|
|||
|
|||
let autoload = { |
|||
|
|||
|
|||
/** |
|||
* @description 自动加载模块 |
|||
* @param dir 加载路径 |
|||
* @param desc 描述 |
|||
* @param flieType 加载文件类型 |
|||
* @param type 加载返回数据类型(Object|Array) |
|||
*/ |
|||
createAutoload: function (dir, flieType=['js'], type = "object", desc='Utils',) { |
|||
let autoladFile = fileHandle.getDirFiles(dir, flieType, ['.bak','autoload']), |
|||
importStr = '', |
|||
exportStr = '', |
|||
count = 0; |
|||
|
|||
Object.keys(autoladFile).forEach((file) => { |
|||
/**多层关系加载**/ |
|||
if (file.indexOf('bak') === -1) { |
|||
let moduleName = this.handleFile(file); |
|||
let modulePath = file; |
|||
|
|||
let str = ''; |
|||
if (count === 0) { |
|||
str = `import ${moduleName} from './${modulePath}';`; |
|||
exportStr += `${moduleName}`; |
|||
} else { |
|||
str = `
|
|||
import ${moduleName} from './${modulePath}';`;
|
|||
exportStr += `,
|
|||
${moduleName}`;
|
|||
} |
|||
importStr += str; |
|||
count++; |
|||
} |
|||
}); |
|||
|
|||
/**读取文件,并替换文件内容**/ |
|||
let buffer = fs.readFileSync(path.join(basePath.buildTemplateDirectory, 'autoload.txt')); |
|||
let content = String(buffer); |
|||
if(type === 'object') { |
|||
exportStr = `{
|
|||
${exportStr} |
|||
}`;
|
|||
} |
|||
if (type === 'array') { |
|||
exportStr = `[
|
|||
${exportStr} |
|||
]`;
|
|||
} |
|||
content = content.replace(/@import_modules@/g, importStr); |
|||
content = content.replace(/@modules_name@/g, exportStr); |
|||
|
|||
/**写文件**/ |
|||
let fd = fs.openSync(path.join(dir, 'autoload.js'), 'w'); |
|||
fs.writeFileSync(fd, content); |
|||
fs.closeSync(fd); |
|||
clog(`\n\n\n${desc} 加载完成,path:${path.join(dir, 'autoload.js')}`,'green'); |
|||
}, |
|||
|
|||
handleFile(path) { |
|||
if (path.indexOf('/') !== -1) { |
|||
let temp = ''; |
|||
let arr = path.split('/'); |
|||
let len = arr.length; |
|||
for (let i = 0; i < len; i++) { |
|||
if (i === 0) temp = arr[i]; |
|||
else temp += arr[i].replace(arr[i][0], arr[i][0].toLocaleUpperCase()); |
|||
} |
|||
return temp; |
|||
} else { |
|||
return path; |
|||
} |
|||
}, |
|||
}; |
|||
|
|||
module.exports = autoload; |
|||
|
@ -0,0 +1,40 @@ |
|||
'use strict'; |
|||
|
|||
let styles = { |
|||
'nomarl':['',''], |
|||
'bold': ['\x1B[1m', '\x1B[22m'], |
|||
'italic': ['\x1B[3m', '\x1B[23m'], |
|||
'underline': ['\x1B[4m', '\x1B[24m'], |
|||
'inverse': ['\x1B[7m', '\x1B[27m'], |
|||
'strikethrough': ['\x1B[9m', '\x1B[29m'], |
|||
'white': ['\x1B[37m', '\x1B[39m'], |
|||
'grey': ['\x1B[90m', '\x1B[39m'], |
|||
'black': ['\x1B[30m', '\x1B[39m'], |
|||
'blue': ['\x1B[34m', '\x1B[39m'], |
|||
'cyan': ['\x1B[36m', '\x1B[39m'], |
|||
'green': ['\x1B[32m', '\x1B[39m'], |
|||
'magenta': ['\x1B[35m', '\x1B[39m'], |
|||
'red': ['\x1B[31m', '\x1B[39m'], |
|||
'yellow': ['\x1B[33m', '\x1B[39m'], |
|||
'whiteBG': ['\x1B[47m', '\x1B[49m'], |
|||
'greyBG': ['\x1B[49;5;8m', '\x1B[49m'], |
|||
'blackBG': ['\x1B[40m', '\x1B[49m'], |
|||
'blueBG': ['\x1B[44m', '\x1B[49m'], |
|||
'cyanBG': ['\x1B[46m', '\x1B[49m'], |
|||
'greenBG': ['\x1B[42m', '\x1B[49m'], |
|||
'magentaBG': ['\x1B[45m', '\x1B[49m'], |
|||
'redBG': ['\x1B[41m', '\x1B[49m'], |
|||
'yellowBG': ['\x1B[43m', '\x1B[49m'] |
|||
}; |
|||
|
|||
function clog(obj, key='black') { |
|||
if (typeof obj === 'string') { |
|||
console.log(styles[key][0] + '%s' + styles[key][1], obj) |
|||
} else if (typeof obj === 'object') { |
|||
console.log(styles[key][0] + '%o' + styles[key][1], obj) |
|||
} else { |
|||
console.log(styles[key][0] + '%s' + styles[key][1], obj) |
|||
} |
|||
} |
|||
|
|||
module.exports = clog; |
@ -0,0 +1,70 @@ |
|||
'use strict'; |
|||
|
|||
const fileHepler = require('./../fileHepler'); |
|||
const basePath = require('./../path'); |
|||
const clog = require('./../clog'); |
|||
// const path = require('path');
|
|||
let cssContentArray = []; |
|||
|
|||
clog('\n\n\n'); |
|||
clog('---开始拷贝--------------', 'red'); |
|||
|
|||
|
|||
/** |
|||
* 替换文件index |
|||
* @param content |
|||
* @param item |
|||
* @returns {*} |
|||
*/ |
|||
function replaceHash(content, item){ |
|||
let cssReg = /((\..*?)\.css)$/; |
|||
let contentarr = item.match(cssReg); |
|||
let version = `.css?version=${Math.floor(new Date().getTime() / 1000)}`; |
|||
let replce = { |
|||
oldPath: item, |
|||
newPath : item.replace(new RegExp(contentarr[2]),''), |
|||
}; |
|||
cssContentArray.push(replce); |
|||
return content.replace(new RegExp(contentarr[1]), version); |
|||
} |
|||
|
|||
function init(){ |
|||
fileHepler.readFile(basePath.indexHtmlFilePath) |
|||
.then((res) => { |
|||
let cssReg = /\/static\/.*?(\..*?)\.css/ig; |
|||
let contentarr = res.match(cssReg); |
|||
if (!contentarr) { |
|||
clog('文件无更新', 'black'); |
|||
return; |
|||
} |
|||
for (let i = 0; i < contentarr.length; i++) { |
|||
res = replaceHash(res, contentarr[i]); |
|||
} |
|||
|
|||
fileHepler.writeFile(basePath.indexHtmlFilePath, res) |
|||
.then(() => { |
|||
clog('更新首页样式路径成功!', 'green'); |
|||
}) |
|||
.catch(); |
|||
|
|||
for (let k = 0; k < cssContentArray.length; k++) { |
|||
let olpPath = basePath.cssOutputRoot + cssContentArray[k]['oldPath']; |
|||
let newPath = basePath.cssOutputRoot + cssContentArray[k]['newPath']; |
|||
fileHepler.renameFile(olpPath, newPath) |
|||
.then(() => { |
|||
clog(cssContentArray[k], 'green'); |
|||
}) |
|||
.catch() |
|||
} |
|||
}); |
|||
} |
|||
|
|||
setTimeout(() => { |
|||
init() |
|||
}, 2000); |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
@ -0,0 +1,35 @@ |
|||
'use strict'; |
|||
|
|||
const path = require('path'); |
|||
|
|||
module.exports = { |
|||
init(conf) { |
|||
return this.pages(conf); |
|||
}, |
|||
|
|||
commonParamter() { |
|||
let time = new Date(); |
|||
let version = String(time.getTime() / 1000); |
|||
return { |
|||
version: version, |
|||
}; |
|||
|
|||
}, |
|||
pages(conf) { |
|||
console.log('\n'); |
|||
let entries = conf.getDirJsFile(conf.entryDirectory); |
|||
let pages = {}; |
|||
Object.keys(entries).forEach((entry) => { |
|||
console.log(`cretae entry, path:${entry} file:${entry}.html`); |
|||
pages[entry] = {}; |
|||
pages[entry]['entry'] = path.resolve(conf['entryDirectory'], `${entry}.js`); |
|||
pages[entry]['template'] = path.resolve(conf['packingTemplatesPath'], 'index.html'); |
|||
pages[entry]['filename'] = `${entry}.html`; |
|||
pages[entry]['title'] = entry; |
|||
pages[entry]['paramters'] = this.commonParamter(); |
|||
pages[entry]['chunks'] = ['chunk-vendors', 'chunk-common', entry]; |
|||
}); |
|||
|
|||
return pages; |
|||
} |
|||
}; |
@ -0,0 +1,182 @@ |
|||
'use strict'; |
|||
|
|||
const requireContext = require('require-context'); |
|||
const fs = require('fs'); |
|||
|
|||
class FileHepler { |
|||
checkVarType(obj) { |
|||
let toString = Object.prototype.toString; |
|||
let map = { |
|||
'[object Boolean]': 'boolean', |
|||
'[object Number]': 'number', |
|||
'[object String]': 'string', |
|||
'[object Function]': 'function', |
|||
'[object Array]': 'array', |
|||
'[object Date]': 'date', |
|||
'[object RegExp]': 'regExp', |
|||
'[object Undefined]': 'undefined', |
|||
'[object Null]': 'null', |
|||
'[object Object]': 'object' |
|||
} |
|||
|
|||
return map[toString.call(obj)]; |
|||
} |
|||
|
|||
inArray(sourceArray = [], findArray = []) { |
|||
if (this.checkVarType(sourceArray) === 'array' && this.checkVarType(findArray) === 'array') { |
|||
let sourceArraylen = sourceArray.length; |
|||
let find = JSON.parse(JSON.stringify(findArray)); |
|||
let temp = []; |
|||
for (let i = 0; i < sourceArraylen; i++) { |
|||
let sourceVal = sourceArray[i]; |
|||
for (let k = 0; k < find.length; k++) { |
|||
if (find[k] === sourceVal) { |
|||
temp.push(true); |
|||
find.splice(k, 1); |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
return findArray.length === temp.length; |
|||
} else { |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
getDirFiles(directory, fileType = [], ignoreFileName = []) { |
|||
/** |
|||
* @description |
|||
* @type {RegExp} |
|||
*/ |
|||
let reg = new RegExp(`\.(${fileType.join('|')})$`); |
|||
let regFile = new RegExp(`^(.*)\.(${fileType.join('|')})$`); |
|||
let modulesFiles = requireContext(directory, true, reg); |
|||
let modules = modulesFiles.keys().reduce((modules, modulePath) => { |
|||
const moduleName = modulePath.replace(regFile, '$1'); |
|||
const extName = modulePath.replace(regFile, '$2'); |
|||
const moduleNameArr = moduleName.split('/'); |
|||
modules[moduleName] = { |
|||
path: moduleName, |
|||
fileName: moduleNameArr[moduleNameArr.length - 1], |
|||
ext: extName, |
|||
fullName: `${moduleName}.${extName}` |
|||
}; |
|||
return modules; |
|||
}, {}); |
|||
|
|||
//过滤忽略文件
|
|||
let temp = {}; |
|||
Object.keys(modules).map((key) => { |
|||
let item = modules[key]; |
|||
if (!this.inArray(ignoreFileName, [item['fileName']])) { |
|||
temp[key] = modules[key]; |
|||
} |
|||
}); |
|||
return temp; |
|||
|
|||
} |
|||
|
|||
/*** |
|||
* @description 复制文件到新位置 |
|||
* @param currentFilePath |
|||
* @param targetFliePath |
|||
*/ |
|||
copyFile(currentFilePath, targetFliePath) { |
|||
return new Promise((resolve,reject)=>{ |
|||
if (!fs.existsSync(currentFilePath)) { |
|||
reject(`复制文件路径不存在:${currentFilePath}`); |
|||
} |
|||
let readStream = fs.createReadStream(currentFilePath); |
|||
readStream.once('error', (err) => { |
|||
reject(err); |
|||
}); |
|||
readStream.once('end', () => { |
|||
resolve(); |
|||
}); |
|||
readStream.pipe(fs.createWriteStream(targetFliePath)); |
|||
}) |
|||
} |
|||
|
|||
/*** |
|||
* @description 删除文件 |
|||
* @param FilePath |
|||
* @returns {Promise<unknown>} |
|||
*/ |
|||
removeFile(FilePath){ |
|||
return new Promise((resolve, reject)=>{ |
|||
fs.unlink(FilePath, (err) => { |
|||
if (err) { |
|||
reject(err); |
|||
return; |
|||
} |
|||
resolve('ok'); |
|||
}); |
|||
}) |
|||
} |
|||
|
|||
/** |
|||
* @description 修改文件名字 |
|||
* @param FilePath |
|||
* @param newPath |
|||
* @returns {Promise<unknown>} |
|||
*/ |
|||
renameFile(FilePath,newPath){ |
|||
return new Promise((resolve, reject) => { |
|||
fs.rename(FilePath, newPath ,(err) => { |
|||
if (err) { |
|||
reject(err); |
|||
return; |
|||
} |
|||
resolve('ok'); |
|||
}); |
|||
}) |
|||
} |
|||
|
|||
/** |
|||
* @description 判断文件是否存在 |
|||
* @param FilePath |
|||
* @returns {Promise<unknown>} |
|||
*/ |
|||
existFile(FilePath){ |
|||
return new Promise((resolve, reject) => { |
|||
fs.access(FilePath, fs.constants.F_OK, (err) => { |
|||
if (err) { |
|||
reject(err); |
|||
return; |
|||
} |
|||
resolve('ok'); |
|||
}); |
|||
}) |
|||
} |
|||
|
|||
readFile(FilePath){ |
|||
return new Promise((resolve, reject) => { |
|||
fs.readFile(FilePath,(err, data) => { |
|||
if (err) { |
|||
reject(err); |
|||
return; |
|||
} |
|||
resolve(String(data)); |
|||
}); |
|||
}); |
|||
} |
|||
|
|||
writeFile(FilePath,data){ |
|||
return new Promise((resolve, reject) => { |
|||
fs.writeFile(FilePath, data, (err) => { |
|||
if (err) { |
|||
reject(err); |
|||
return; |
|||
} |
|||
resolve('ok'); |
|||
}); |
|||
}); |
|||
} |
|||
|
|||
|
|||
} |
|||
|
|||
module.exports = new FileHepler(); |
|||
|
|||
|
|||
|
@ -0,0 +1,9 @@ |
|||
'use strict'; |
|||
const resolve = dir => require('path').join(__dirname, dir); |
|||
|
|||
|
|||
|
|||
module.exports = { |
|||
buildTemplateDirectory: resolve( './template'), |
|||
buildComponentsDirectory: resolve('../src/components'), |
|||
}; |
@ -0,0 +1,19 @@ |
|||
'use strict'; |
|||
const autoload = require('./../autoload'); |
|||
const basePath = require('./../path'); |
|||
let time = null; |
|||
|
|||
class CreatedComponentsPlugin { |
|||
constructor() {} |
|||
apply(compiler) { |
|||
if (time) { |
|||
clearTimeout(time); |
|||
time = null; |
|||
} |
|||
time = setTimeout(() => { |
|||
autoload.createAutoload(basePath.buildComponentsDirectory, ['vue'], 'array', 'Components'); |
|||
}, 30); |
|||
} |
|||
} |
|||
|
|||
module.exports = CreatedComponentsPlugin; |
@ -0,0 +1,53 @@ |
|||
'use strict'; |
|||
|
|||
import request from '@/utils/request' |
|||
const {apiUrl, isTestData } = require('@/setting'); |
|||
import { getTestDataList } from "@/test-data/@pathname@"; |
|||
|
|||
/** |
|||
* @description 描述 |
|||
* @param params { Object } |
|||
* @returns {AxiosPromise} |
|||
*/ |
|||
export function getTestList(params) { |
|||
|
|||
/**测试数据**/ |
|||
if (isTestData) { |
|||
return getTestDataList(data) |
|||
} |
|||
|
|||
let url = apiUrl.demoUrl; |
|||
return request({ |
|||
url, |
|||
method: 'get', |
|||
params |
|||
}) |
|||
} |
|||
|
|||
/** |
|||
* @description 描述 |
|||
* @param data { Object } |
|||
* @returns {AxiosPromise} |
|||
*/ |
|||
export function postTestList(data) { |
|||
/**测试数据**/ |
|||
if (isTestData) { |
|||
return getTestDataList(data) |
|||
} |
|||
|
|||
let url = apiUrl.demoUrl; |
|||
data = request.formDataSendParam(data); |
|||
return request({ |
|||
url, |
|||
method: 'post', |
|||
data |
|||
}) |
|||
} |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
@ -0,0 +1,5 @@ |
|||
'use strict'; |
|||
|
|||
@import_modules@ |
|||
|
|||
export default @modules_name@ |
@ -0,0 +1,11 @@ |
|||
'use strict'; |
|||
|
|||
import app from '@/main'; |
|||
import page from '@/views/@entryname@'; |
|||
import store from "@/store"; |
|||
|
|||
store.commit('changePage', '@pathname@'); |
|||
store['dispatch']('appInit', function () { |
|||
app.mount(page); |
|||
}); |
|||
|
@ -0,0 +1,60 @@ |
|||
'use strict'; |
|||
|
|||
import { |
|||
getTestList, |
|||
postTestList |
|||
} from '@/api/@pathname@'; |
|||
|
|||
const state = {}; |
|||
|
|||
const actions = { |
|||
/** |
|||
* @description postTestList |
|||
* @param commit |
|||
* @param params |
|||
* @returns {Promise<unknown>} |
|||
*/ |
|||
getTestList({commit}, params) { |
|||
return new Promise((resolve, reject) => { |
|||
getTestList(params) |
|||
.then((res) => { |
|||
console.log('getTestList.res', res.data); |
|||
resolve(res.data); |
|||
}) |
|||
.catch((error) => { |
|||
reject(error); |
|||
}) |
|||
}) |
|||
}, |
|||
|
|||
/** |
|||
* @description 描述 |
|||
* @param commit |
|||
* @param params |
|||
* @returns {Promise<unknown>} |
|||
*/ |
|||
postTestList({commit}, params) { |
|||
return new Promise((resolve, reject) => { |
|||
postTestList(params) |
|||
.then((res) => { |
|||
console.log('postTestList.res', res.data); |
|||
resolve(res.data); |
|||
}) |
|||
.catch((error) => { |
|||
reject(error); |
|||
}) |
|||
}) |
|||
}, |
|||
}; |
|||
|
|||
const getters = {}; |
|||
|
|||
const mutations = {}; |
|||
|
|||
export default { |
|||
namespaced: true, |
|||
state, |
|||
getters, |
|||
actions, |
|||
mutations |
|||
}; |
@ -0,0 +1,7 @@ |
|||
'use strict'; |
|||
|
|||
import Vue from 'vue'; |
|||
@import_modules@ |
|||
|
|||
@use_sub_components@ |
|||
|
@ -0,0 +1,20 @@ |
|||
'use strict'; |
|||
|
|||
/** |
|||
* @description 测试数可以使用faker |
|||
* @description https://github.com/Marak/faker.js
|
|||
*/ |
|||
import helper from "@/utils/helper"; |
|||
|
|||
/** |
|||
* @description 描述 |
|||
* @param data |
|||
* @returns {Promise<unknown>} |
|||
*/ |
|||
export function getTestDataList(data) { |
|||
return new Promise((resolve) => { |
|||
setTimeout(() => { |
|||
resolve(helper.callback([])); |
|||
}, 1000) |
|||
}); |
|||
} |
@ -0,0 +1,39 @@ |
|||
'use strict'; |
|||
|
|||
const proxy = { |
|||
'/api/admin': { |
|||
target: 'https://sandbox-c.jufubao.cn', |
|||
pathRewrite: {"^/api/admin": "/api/admin"}, |
|||
changeOrigin: true, |
|||
secure: false, |
|||
}, |
|||
'/oauth': { |
|||
target: 'https://sandbox-c.jufubao.cn', |
|||
pathRewrite: {"^/oauth": "/oauth"}, |
|||
changeOrigin: true, |
|||
secure: false, |
|||
} |
|||
}; |
|||
|
|||
const defaultSettings = require('./settings.js'); |
|||
|
|||
// If your port is set to 80,
|
|||
// use administrator privileges to execute the command line.
|
|||
// For example, Mac: sudo npm run
|
|||
// You can change the port by the following method:
|
|||
// port = 9527 npm run dev OR npm run dev --port = 9527
|
|||
const port = process.env.port || process.env.npm_config_port || defaultSettings.port || 9527; // dev port
|
|||
|
|||
const devServer = { |
|||
port: defaultSettings.port, |
|||
open: true, |
|||
//host:'192.168.0.4',
|
|||
overlay: { |
|||
warnings: true, |
|||
errors: true |
|||
}, |
|||
//proxy, //proxy与before不能共用,before优先于proxy
|
|||
//before: ()=> {}
|
|||
}; |
|||
|
|||
module.exports = devServer; |
@ -0,0 +1,2 @@ |
|||
module.exports = require('./lib/gxd.umd.min'); |
|||
|
@ -0,0 +1,8 @@ |
|||
<meta charset="utf-8"> |
|||
<title>gxd demo</title> |
|||
<script src="./gxd.umd.js"></script> |
|||
|
|||
|
|||
<script> |
|||
console.log(gxd) |
|||
</script> |
74080
xd-file-preview/lib/gxd.common.js
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
74090
xd-file-preview/lib/gxd.umd.js
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
27
xd-file-preview/lib/gxd.umd.min.js
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
27096
xd-file-preview/package-lock.json
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,101 @@ |
|||
{ |
|||
"name": "gxd-file-preview", |
|||
"version": "1.2.1", |
|||
"private": false, |
|||
"description": "vue 文件在线预览展示功能,支持文件(PDF,PNG,JPEG,JPG,GIF,DOC,DOCX,PPT,PPTX,XLS,XLSX,JSON,TXT,JS,HTML,CSS)", |
|||
"scripts": { |
|||
"library": "vue-cli-service build --no-clean --target lib --name gxd --dest lib --entry src/install.js", |
|||
"library:dev": "vue-cli-service build --no-clean --target lib --name gxdSource --dest lib --entry src/install.js", |
|||
"remove": " rm ./lib/gxd.common.js && rm ./lib/gxd.umd.js && rm ./lib/demo.html", |
|||
"build": "npm run library && npm run remove", |
|||
"dev": "vue-cli-service serve", |
|||
"lint": "vue-cli-service lint" |
|||
}, |
|||
"dependencies": { |
|||
"core-js": "^2.6.10", |
|||
"dl-watermark": "^1.0.0", |
|||
"downloadjs": "^1.4.7", |
|||
"md5.js": "^1.3.5", |
|||
"vue": "^2.6.10", |
|||
"vue-highlightjs": "1.3.3", |
|||
"vue-json-viewer": "2.2.22", |
|||
"vue-pdf": "^4.2.0" |
|||
}, |
|||
"repository": { |
|||
"type": "git", |
|||
"url": "git@gitee.com:e56buy/xd-file-preview.git" |
|||
}, |
|||
"devDependencies": { |
|||
"@vue/cli-plugin-babel": "^3.12.0", |
|||
"@vue/cli-plugin-eslint": "^3.12.0", |
|||
"@vue/cli-service": "^3.12.0", |
|||
"babel-eslint": "^10.0.1", |
|||
"eslint": "^5.16.0", |
|||
"eslint-plugin-vue": "^5.0.0", |
|||
"less": "^3.12.2", |
|||
"less-loader": "^7.0.1", |
|||
"require-context": "^1.1.0", |
|||
"sass": "^1.28.0", |
|||
"sass-loader": "^10.0.5", |
|||
"script-ext-html-webpack-plugin": "^2.1.5", |
|||
"uglifyjs-webpack-plugin": "^1.1.1", |
|||
"vue-template-compiler": "^2.6.10" |
|||
}, |
|||
"keywords": [ |
|||
"gxd", |
|||
"gxd-file-preview", |
|||
"vue-pdf", |
|||
"vue pdf", |
|||
"pdf", |
|||
"pdf-vue", |
|||
"pdf-vue-preview", |
|||
"pdf", |
|||
"pdf vue", |
|||
"pdf vue preview", |
|||
"pdf在线预览", |
|||
"file", |
|||
"file-preview", |
|||
"file-vue-preview", |
|||
"docx", |
|||
"doc", |
|||
"vue-docx", |
|||
"vue-doc", |
|||
"ppt", |
|||
"pptx", |
|||
"vue-ppt", |
|||
"vue-pptx", |
|||
"xls", |
|||
"xlsx", |
|||
"vue-xls", |
|||
"vue-xlsx", |
|||
"doc在线预览", |
|||
"docx在线预览", |
|||
"ppt在线预览", |
|||
"pptx在线预览", |
|||
"xls在线预览", |
|||
"xlsx在线预览" |
|||
], |
|||
"eslintConfig": { |
|||
"root": true, |
|||
"env": { |
|||
"node": true |
|||
}, |
|||
"extends": [ |
|||
"plugin:vue/essential", |
|||
"eslint:recommended" |
|||
], |
|||
"rules": {}, |
|||
"parserOptions": { |
|||
"parser": "babel-eslint" |
|||
} |
|||
}, |
|||
"postcss": { |
|||
"plugins": { |
|||
"autoprefixer": {} |
|||
} |
|||
}, |
|||
"browserslist": [ |
|||
"> 1%", |
|||
"last 2 versions" |
|||
] |
|||
} |
@ -0,0 +1,18 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="en"> |
|||
<head> |
|||
<meta charset="utf-8"> |
|||
<meta http-equiv="X-UA-Compatible" content="IE=edge"> |
|||
<meta name="viewport" content="width=device-width,initial-scale=1.0"> |
|||
<link rel="stylesheet" href="//unpkg.com/@highlightjs/cdn-assets@11.6.0/styles/atom-one-dark.css"> |
|||
<link rel="icon" href="<%= BASE_URL %>favicon.ico"> |
|||
<title>文件预览功能</title> |
|||
</head> |
|||
<body> |
|||
<noscript> |
|||
<strong>We're sorry but xd-editer doesn't work properly without JavaScript enabled. Please enable it to continue.</strong> |
|||
</noscript> |
|||
<div id="app"></div> |
|||
<!-- built files will be auto injected --> |
|||
</body> |
|||
</html> |
@ -0,0 +1,8 @@ |
|||
#app { |
|||
font-family: 'Avenir', Helvetica, Arial, sans-serif; |
|||
-webkit-font-smoothing: antialiased; |
|||
-moz-osx-font-smoothing: grayscale; |
|||
text-align: left; |
|||
color: #2c3e50; |
|||
margin-top: 60px; |
|||
} |
@ -0,0 +1,321 @@ |
|||
'use strict'; |
|||
|
|||
const MD5 = require('md5.js'); |
|||
import {iconData, typeHeader } from "./../contact"; |
|||
|
|||
class Helper { |
|||
hideScroll(type){ |
|||
let body = document.getElementsByTagName('body')[0]; |
|||
if (type === 1) { |
|||
body.style.overflowY = 'hidden'; |
|||
body.style.height = '100%'; |
|||
} else { |
|||
body.style.overflowY = ''; |
|||
body.style.height = ''; |
|||
} |
|||
}; |
|||
|
|||
/** |
|||
* @description 字符串截取 |
|||
* @param val |
|||
* @param len |
|||
*/ |
|||
cutStringLen(val, len = 10) { |
|||
let fix = '...'; |
|||
let newLength = 0; |
|||
let newStr = ""; |
|||
let chineseRegex = /[^\x00-\xff]/g; |
|||
let singleChar = ""; |
|||
let strLength = val.replace(chineseRegex, "**").length; |
|||
for (let i = 0; i < strLength; i++) { |
|||
singleChar = val.charAt(i).toString(); |
|||
if (singleChar.match(chineseRegex) != null) { |
|||
newLength += 2; |
|||
} else { |
|||
newLength++; |
|||
} |
|||
if (newLength > len) { |
|||
break; |
|||
} |
|||
newStr += singleChar; |
|||
} |
|||
if (strLength > len) { |
|||
newStr += fix; |
|||
} |
|||
return newStr; |
|||
} |
|||
|
|||
checkVarType(obj) { |
|||
let toString = Object.prototype.toString; |
|||
let map = { |
|||
'[object Boolean]': 'boolean', |
|||
'[object Number]': 'number', |
|||
'[object String]': 'string', |
|||
'[object Function]': 'function', |
|||
'[object Array]': 'array', |
|||
'[object Date]': 'date', |
|||
'[object RegExp]': 'regExp', |
|||
'[object Undefined]': 'undefined', |
|||
'[object Null]': 'null', |
|||
'[object Object]': 'object', |
|||
'[object Blob]' : 'blob' |
|||
}; |
|||
return map[toString.call(obj)]; |
|||
} |
|||
|
|||
getID() { |
|||
return this.random(1111111, 9999999); |
|||
} |
|||
|
|||
md5Fn(str, hex = 'hex'){ |
|||
return new MD5()['update'](str)['digest'](hex); |
|||
} |
|||
|
|||
random(min, max) { |
|||
let Range = max - min; |
|||
let Rand = Math.random(); |
|||
return (min + Math.round(Rand * Range)); |
|||
} |
|||
|
|||
parseURL(url) { |
|||
if (!url) { |
|||
url = window.location.href; |
|||
} |
|||
let a = document.createElement('a'); |
|||
a.href = url; |
|||
return { |
|||
source: url, |
|||
protocol: a.protocol.replace(':', ''), |
|||
host: a.hostname, |
|||
port: a.port, |
|||
query: a.search, |
|||
params: (function() { |
|||
let ret = {}, |
|||
seg = a.search.replace(/^\?/, '').split('&'), |
|||
len = seg.length, i = 0, s; |
|||
for (; i < len; i++) { |
|||
if (!seg[i]) { |
|||
continue; |
|||
} |
|||
s = seg[i].split('='); |
|||
if (s[1]) { |
|||
ret[s[0]] = s[1]; |
|||
} |
|||
} |
|||
return ret; |
|||
})(), |
|||
file: (a.pathname.match(/\/([^\/?#]+)$/i) || [, ''])[1], |
|||
hash: a.hash.replace('#', ''), |
|||
path: a.pathname.replace(/^([^\/])/, '/$1'), |
|||
relative: (a.href.match(/tps?:\/\/[^\/]+(.+)/) || [, ''])[1], |
|||
segments: a.pathname.replace(/^\//, '').split('/') |
|||
}; |
|||
} |
|||
|
|||
/*** |
|||
* @description 获取文件类型 |
|||
* @param blob |
|||
*/ |
|||
checkFileType(blob){ |
|||
let type = typeHeader['unkown']; |
|||
if(typeHeader[blob.type]) { |
|||
type = typeHeader[blob.type]; |
|||
} |
|||
return type; |
|||
} |
|||
|
|||
/** |
|||
* @description 获取文件base64流 |
|||
* @param blob |
|||
* @param file |
|||
* @returns {Promise<unknown>} |
|||
*/ |
|||
fileReaderBase64(blob, file){ |
|||
return new Promise((resolve, reject)=>{ |
|||
let reader = new FileReader(); |
|||
reader.onload = (e)=> { |
|||
resolve(e.target['result']); |
|||
}; |
|||
reader.onerror = ()=>{ |
|||
reject('读取文件错误') |
|||
}; |
|||
|
|||
reader.readAsDataURL(blob); |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* @description 获取文件相关信息 |
|||
* @param url |
|||
* @param name |
|||
* @returns {Promise<unknown>} |
|||
*/ |
|||
getFileBase64(url='',name = '') { |
|||
return new Promise((resolve, reject) => { |
|||
let getName = (type)=> { |
|||
let str = url; |
|||
if(str.indexOf('?')) str = url.split('?')[0]; |
|||
let arr = str.split('/'); |
|||
return arr[arr.length - 1]; |
|||
}; |
|||
|
|||
let x = new XMLHttpRequest(); |
|||
x.open("GET", url, true); |
|||
x.responseType = "blob"; |
|||
x.onload = (e) => { |
|||
console.log('XMLHttpRequest',e); |
|||
if (e.target['status'] === 200) { |
|||
//console.log('this.checkFileType(e.target[\'response\'])',url,this.checkFileType(e.target['response']));
|
|||
let temp = { |
|||
type: this.checkFileType(e.target['response']), |
|||
size: e.target['response']['size'], |
|||
name: name ? name: getName(this.checkFileType(e.target['response'])), |
|||
}; |
|||
|
|||
this.fileReaderBase64(e.target['response'], temp) |
|||
.then(res=>{ |
|||
temp['url'] = res; |
|||
temp['icon'] = this.getIcon(temp['type']); |
|||
temp['response'] = e.target['response']; |
|||
resolve(temp); |
|||
}) |
|||
.catch(res=>{ |
|||
reject(res) |
|||
}) |
|||
} else if (e.target['status'] === 404) { |
|||
console.error('error', e); |
|||
reject('您下载的文件不存在!'); |
|||
} else { |
|||
console.error('error', e); |
|||
reject('网络错误!'); |
|||
} |
|||
}; |
|||
x.onerror = (e) => { |
|||
console.log('onerror') |
|||
console.log('error', e); |
|||
reject('网络错误!'); |
|||
} |
|||
x.send(); |
|||
}) |
|||
|
|||
} |
|||
|
|||
/** |
|||
* @description 获取图片相应的图片 |
|||
* @param type |
|||
* @returns {string} |
|||
*/ |
|||
getIcon(type='') { |
|||
let temp = ''; |
|||
if(iconData[type.toLocaleLowerCase()]) { |
|||
temp = iconData[type.toLocaleLowerCase()]; |
|||
} |
|||
return temp; |
|||
} |
|||
|
|||
|
|||
/** |
|||
* @description 判断俩个需要处理的数字谁的小数点后位数多, |
|||
* 以多的为准,值乘以10的小数位的幂数,相加以后,再除以10的小数位的幂数 |
|||
* @param currentNum |
|||
* @param targetNum |
|||
*/ |
|||
checkFloatMore(currentNum, targetNum){ |
|||
let sq1, sq2; |
|||
try {sq1 = currentNum.toString().split(".")[1].length;} |
|||
catch (e) {sq1 = 0;} |
|||
try {sq2 = targetNum.toString().split(".")[1].length;} |
|||
catch (e) {sq2 = 0;} |
|||
return Math.pow(10, Math.max(sq1, sq2)); |
|||
} |
|||
|
|||
/** |
|||
* @description 两个小数相加 |
|||
* @param currentNum |
|||
* @param targetNum |
|||
* @return number |
|||
*/ |
|||
addFloatNumber(currentNum, targetNum){ |
|||
let power = this.checkFloatMore(currentNum, targetNum); |
|||
return (currentNum * power + targetNum * power) / power; |
|||
} |
|||
|
|||
/** |
|||
* @description 两个小数减 |
|||
* @param currentNum |
|||
* @param targetNum |
|||
* @return number |
|||
*/ |
|||
cutFloatNumber(currentNum, targetNum) { |
|||
let power = this.checkFloatMore(currentNum, targetNum); |
|||
return (currentNum * power - targetNum * power) / power; |
|||
} |
|||
|
|||
/** |
|||
* @description 计算两个小数相乘 |
|||
* @param currentNum |
|||
* @param targetNum |
|||
* @returns {number} |
|||
*/ |
|||
multiplyFloatNumber(currentNum, targetNum){ |
|||
let m = 0, s1 = currentNum.toString(), s2 = targetNum.toString(); |
|||
try {m += s1.split(".")[1].length;} catch (e) {} |
|||
try {m += s2.split(".")[1].length;} catch (e) {} |
|||
return Number(s1.replace(".", "")) * Number(s2.replace(".", "")) / Math.pow(10, m); |
|||
} |
|||
|
|||
/** |
|||
* @description 计算两个小数相除 |
|||
* @param currentNum |
|||
* @param targetNum |
|||
* @returns {number} |
|||
*/ |
|||
divisionFloatNumber(currentNum, targetNum){ |
|||
let t1 = 0, t2 = 0, r1, r2; |
|||
try {t1 = currentNum.toString().split(".")[1].length} catch (e) {} |
|||
try {t2 = targetNum.toString().split(".")[1].length} catch (e) {} |
|||
r1 = Number(currentNum.toString().replace(".", "")) |
|||
r2 = Number(targetNum.toString().replace(".", "")) |
|||
return (r1 / r2) * Math.pow(10, t2 - t1); |
|||
} |
|||
|
|||
/** |
|||
* @description 创建node节点 |
|||
* @param options {object} |
|||
* @param options.fid 文件ID,唯一id(必填) |
|||
* @param options.name 文件名称(选填) |
|||
* @param options.url //文件地址(必填)
|
|||
* @param Vue Vue类 (必填) |
|||
* @param view vue文件(必填) |
|||
*/ |
|||
createElement(options, Vue, view){ |
|||
console.log('PDF预览功能', options); |
|||
let str = `${options.name}${options['fid']}`; |
|||
let elId = `img-${this.md5Fn(str)}`; |
|||
let ele = document.getElementById(elId); |
|||
|
|||
if (ele) { |
|||
ele.style.display = "block"; |
|||
this.hideScroll(1); |
|||
return ele; |
|||
} |
|||
|
|||
const View = Vue.extend(view); |
|||
let $view = new View({ |
|||
el: document.createElement('div') |
|||
}); |
|||
options['ele'] = elId; |
|||
$view.options = options; |
|||
$view.close = (id) => { |
|||
let ele = document.getElementById(id); |
|||
ele.style.display = "none"; |
|||
this.hideScroll(-1); |
|||
}; |
|||
|
|||
document.body.appendChild($view.$el); |
|||
this.hideScroll(1); |
|||
} |
|||
|
|||
} |
|||
|
|||
export default new Helper(); |
@ -0,0 +1,17 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="en"> |
|||
<head> |
|||
<meta charset="utf-8"> |
|||
<meta http-equiv="X-UA-Compatible" content="IE=edge"> |
|||
<meta name="viewport" content="width=device-width,initial-scale=1.0"> |
|||
<link rel="icon" href="<%= BASE_URL %>favicon.ico"> |
|||
<title>文件预览功能</title> |
|||
</head> |
|||
<body> |
|||
<noscript> |
|||
<strong>We're sorry but xd-editer doesn't work properly without JavaScript enabled. Please enable it to continue.</strong> |
|||
</noscript> |
|||
<div id="app"></div> |
|||
<!-- built files will be auto injected --> |
|||
</body> |
|||
</html> |
@ -0,0 +1,17 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="en"> |
|||
<head> |
|||
<meta charset="utf-8"> |
|||
<meta http-equiv="X-UA-Compatible" content="IE=edge"> |
|||
<meta name="viewport" content="width=device-width,initial-scale=1.0"> |
|||
<link rel="icon" href="<%= BASE_URL %>favicon.ico"> |
|||
<title>文件预览功能</title> |
|||
</head> |
|||
<body> |
|||
<noscript> |
|||
<strong>We're sorry but xd-editer doesn't work properly without JavaScript enabled. Please enable it to continue.</strong> |
|||
</noscript> |
|||
<div id="app"></div> |
|||
<!-- built files will be auto injected --> |
|||
</body> |
|||
</html> |
@ -0,0 +1,44 @@ |
|||
'use strict'; |
|||
|
|||
const settings = { |
|||
/** |
|||
* @type {string} |
|||
* @description 项目名称 |
|||
*/ |
|||
title: '', |
|||
|
|||
/** |
|||
* @type {string} |
|||
* @description 系统版本 |
|||
*/ |
|||
version: 'v1.0.0', |
|||
|
|||
/** |
|||
* @type {boolean} |
|||
* @description 是否关闭eslint语法检测 |
|||
*/ |
|||
isCloseEslint: false, |
|||
|
|||
/** |
|||
* @type {boolean} true | false |
|||
* @description 开发环境与生产环境 |
|||
*/ |
|||
isDebug: false, |
|||
|
|||
/** |
|||
* @type {boolean} true | false |
|||
* @description 是否加载模拟数据 |
|||
*/ |
|||
isTestData: false, |
|||
|
|||
/** |
|||
* @type {number} |
|||
* @description 开发环境端口号 |
|||
*/ |
|||
port: 8057, |
|||
|
|||
} |
|||
|
|||
module.exports = settings; |
|||
|
|||
|
@ -0,0 +1,182 @@ |
|||
<template> |
|||
<div id="app"> |
|||
<h1>列表展示</h1> |
|||
<xd-file-list-preview :show-close="true" :list="list" @remove="handleRemoveClick" is-pagination></xd-file-list-preview> |
|||
<hr> |
|||
<h1>文件预览模式</h1> |
|||
<a @click="handleClick" style="color: #4285f4">9958ff80d202f91b347b14b5c56f14e811</a> |
|||
<h1>基于 Canvas 实现水印效果(前端)加水印</h1> |
|||
<!-- <a @click="handleClick2" style="color: #4285f4">9958ff80d202f91b347b14b5c56f14e811</a> --> |
|||
<div> |
|||
<img v-watermark="1+1" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/6f9190aa805144858810da50b4aca13b~tplv-k3u1fbpfcp-zoom-in-crop-mark:3024:0:0:0.awebp?" alt="上海鲜花港 - 郁金香"> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import XdFileListPreview from "@/components/XdFileListPreview"; |
|||
|
|||
export default { |
|||
name: 'app', |
|||
components: { XdFileListPreview }, |
|||
data() { |
|||
return { |
|||
list: [ |
|||
{ |
|||
url: 'http://storage.xuetangx.com/public_assets/xuetangx/PDF/PlayerAPI_v1.0.6.pdf', |
|||
name: 'test.pdf', |
|||
fid: 'test.pdf', |
|||
download: false |
|||
}, |
|||
|
|||
{ |
|||
url: 'https://jfb-public-images.oss-cn-qingdao.aliyuncs.com/admin-upload/202111081034429231.png?x-oss-process=style/common', |
|||
name: 'test.png', |
|||
fid: 'test.png', |
|||
download: false |
|||
}, |
|||
{ |
|||
url: 'https://jfb-public-images.oss-cn-qingdao.aliyuncs.com/uploads/20220407/7e11e47b25c1048edb6eb82c2445aa13.pconline.com.cn_images_upload_upc_tx_photoblog_1511_15_c4_15264230_15264230_1447554198988.jpg&refer=http___img.pconline.com.jpeg', |
|||
name: 'test.jpg', |
|||
fid: 'test.jpg', |
|||
download: false |
|||
}, |
|||
{ |
|||
url: 'http://static.e56buy.com/Xd9EfP1YFgdaYbI6H3RBiG6E3HAF6udj.PlayerAPI_v1.0.6.pdf', |
|||
name: 'Xd9EfP1YFgdaYbI6H3RBiG6E3HAF6udj.pdf', |
|||
fid: 'Xd9EfP1YFgdaYbI6H3RBiG6E3HAF6udj.pdf', |
|||
download: false |
|||
}, |
|||
{ |
|||
url: 'http://static.e56buy.com/XdgfsqR2INp7uFxTuLQtnMstYLY4K8rr.蛋糕缺少内容.docx', |
|||
name: 'Xd9EfP1YFgdaYbI6H3RBiG6E3HAF6udj.docx', |
|||
fid: 'Xd9EfP1YFgdaYbI6H3RBiG6E3HAF6udj.docx', |
|||
download: false |
|||
}, |
|||
{ |
|||
url: 'http://static.e56buy.com/XdU9Tmy2x6OGydRUQpWmThRaZKL1gkbd.ceshiyo.xlsx', |
|||
name: 'ka.xlsx', |
|||
fid: 'ka.xlsx', |
|||
download: false |
|||
}, |
|||
{ |
|||
url: 'https://sandbox-editx-website.oss-cn-qingdao.aliyuncs.com/sandbox-website-01.jufubao.cn/store/20221009153933/config/pages/pg_cn4THNcGvif-SDvN9A.json', |
|||
name: 'PlayerAPI_v1.0.6.json', |
|||
fid: 'PlayerAPI_v1.0.6.json', |
|||
download: true |
|||
}, |
|||
{ |
|||
url: 'http://localhost:8057/static/helper.js', |
|||
name: 'PlayerAPI_v1.0.6.js', |
|||
fid: 'PlayerAPI_v1.0.6.js', |
|||
download: false |
|||
}, |
|||
{ |
|||
url: 'http://localhost:8057/static/index.html', |
|||
name: 'PlayerAPI_v1.0.6.html', |
|||
fid: 'PlayerAPI_v1.0.6.html', |
|||
download: false |
|||
}, |
|||
{ |
|||
url: 'http://localhost:8057/static/index.txt', |
|||
name: 'PlayerAPI_v1.0.6.txt', |
|||
fid: 'PlayerAPI_v1.0.6.txt', |
|||
download: false |
|||
}, |
|||
{ |
|||
url: 'http://localhost:8057/static/helper.css', |
|||
name: 'PlayerAPI_v1.0.6.css', |
|||
fid: 'PlayerAPI_v1.0.6.css', |
|||
download: false |
|||
}, |
|||
{ |
|||
url: 'http://localhost:8057/static/999.ofd', |
|||
name: '999.ofd', |
|||
fid: '999.ofd', |
|||
download: false |
|||
}, |
|||
] |
|||
} |
|||
}, |
|||
created() { |
|||
}, |
|||
methods: { |
|||
/** |
|||
* @description 删除图片事件 |
|||
* @param item {Object} 当前被删除的文件对象 |
|||
* @param done {function} 删除文件完成回调函数 |
|||
*/ |
|||
handleRemoveClick(item, done) { |
|||
setTimeout(() => { |
|||
console.log('handleRemoveClick', item); |
|||
done() |
|||
}, 100); |
|||
}, |
|||
|
|||
/** |
|||
* @description 点击查看预览功能 |
|||
*/ |
|||
handleClick() { |
|||
this.$preview({ |
|||
//url: 'http://static.e56buy.com/XdU9Tmy2x6OGydRUQpWmThRaZKL1gkbd.ceshiyo.xlsx', // xlsx |
|||
//url: 'http://static.e56buy.com/XdgfsqR2INp7uFxTuLQtnMstYLY4K8rr.蛋糕缺少内容.docx', //doc, |
|||
url: 'http://storage.xuetangx.com/public_assets/xuetangx/PDF/PlayerAPI_v1.0.6.pdf', |
|||
fid: 'aadadads', |
|||
download: false |
|||
}) |
|||
}, |
|||
// handleClick1() { |
|||
// const dlWaterMark = new DlWaterMark({ |
|||
// el: showImage, // 绑定节点 |
|||
// width: 500, // 显示水印范围的宽度,最好与显示的图片一致 |
|||
// height: 300, // 显示水印范围的高度,最好与显示的图片一致 |
|||
// toggleShow: false, // 水印文本是否交错显示 |
|||
// rotate: -25, // 显示水印文本的倾斜角度 |
|||
// fillStyle: '#000', // 显示水印文本的颜色 |
|||
// fontSize: '20px', // 显示水印文本的字体大小 |
|||
// context: '婷婷小可爱' // 显示水印的文本内容 |
|||
// }); |
|||
// dlWaterMark.draw('https://jfb-public-images.oss-cn-qingdao.aliyuncs.com/admin-upload/202111081034429231.png?x-oss-process=style/common') |
|||
// } |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style> |
|||
#app { |
|||
font-family: "Avenir", Helvetica, Arial, sans-serif; |
|||
-webkit-font-smoothing: antialiased; |
|||
-moz-osx-font-smoothing: grayscale; |
|||
text-align: left; |
|||
color: #2c3e50; |
|||
margin-top: 60px; |
|||
} |
|||
|
|||
/********* css 部分代码如下 ***********/ |
|||
/* .water-mark { |
|||
display: inline-block; |
|||
overflow: hidden; |
|||
position: relative; |
|||
} */ |
|||
/* .water-mark::after { |
|||
pointer-events: none; |
|||
position: absolute; |
|||
content: " "; |
|||
width: 100%; |
|||
height: 100%; |
|||
opacity: 0.2; |
|||
background-image: url("../assets/water-bg.png"); |
|||
background-repeat: repeat; |
|||
} */ |
|||
.water-mark { |
|||
display: inline-block; |
|||
overflow: hidden; |
|||
position: absolute; |
|||
left: 0; |
|||
top: 0; |
|||
width: 100%; |
|||
height: 100%; |
|||
pointer-events: none; |
|||
background-repeat: repeat; |
|||
} |
|||
</style> |
After Width: 45 | Height: 80 | Size: 1.4 KiB |
@ -0,0 +1,250 @@ |
|||
<template> |
|||
<div class="xd-file-list__body"> |
|||
<div class="xd-file-list__item" v-if="item" v-for="(item,index) in dataList" :key="item.fid"> |
|||
<div class="xd-file-list__item-icon"> |
|||
<img v-if="item['icon']" :src="item['icon']" alt="icon"> |
|||
<div v-else><i class="fileIconfont iconwenjian"></i></div> |
|||
</div> |
|||
<div class="xd-file-list__item-text"> |
|||
<div class="xd-file-list__item-text-title" :title="getName(item)">{{getFileName(item)}}</div> |
|||
<div class="xd-file-list__item-text-link" @click="handleClick(item,index)" :style="`color: ${linkColor}`">点击查看</div> |
|||
</div> |
|||
<i class="fileIconfont iconyduicuowushixin" v-if="showClose" @click.stop="handleRemoveClick(item,index)"></i> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import helper from "@/components/preview/helper"; |
|||
import {iconData} from "@/components/contact"; |
|||
|
|||
export default { |
|||
name: "XdFileListPreview", |
|||
props: { |
|||
list: { |
|||
type: Object | Array, |
|||
default() { |
|||
return [] |
|||
} |
|||
}, |
|||
showClose: { |
|||
type: Boolean, |
|||
default: false, |
|||
}, |
|||
linkColor: { |
|||
type: String, |
|||
default: '#4285F4', |
|||
}, |
|||
|
|||
isPagination: { |
|||
type: Boolean, |
|||
default: false, |
|||
} |
|||
}, |
|||
|
|||
data() { |
|||
return { |
|||
dataList: [], |
|||
} |
|||
}, |
|||
watch: { |
|||
list(val) { |
|||
this.setDataValue(val) |
|||
} |
|||
}, |
|||
|
|||
created() { |
|||
this.setDataValue(this.list); |
|||
}, |
|||
|
|||
methods: { |
|||
setDataValue(val) { |
|||
if (val.length > 0) { |
|||
//未加载过 |
|||
let temp = []; |
|||
val.map((item, index) => { |
|||
|
|||
if (item[status]) { |
|||
temp[index] = item; |
|||
} else { |
|||
helper.getFileBase64(item.url, item.name ? item.name : '') |
|||
.then(res => { |
|||
res['status'] = true; |
|||
temp[index] = Object.assign({source: item['url']}, item, res, ); |
|||
console.log(temp[index]) |
|||
}) |
|||
.catch(res => { |
|||
temp[index] = { |
|||
src: iconData.loadicon, |
|||
status: false, |
|||
url: item['url'], |
|||
source: item['url'], |
|||
} |
|||
}); |
|||
} |
|||
}); |
|||
let timeer = setInterval(() => { |
|||
if (temp.length === val.length) { |
|||
this.dataList = temp; |
|||
this.$emit('change', this.dataList, 'add'); |
|||
clearInterval(timeer); |
|||
console.log('setInterval', temp) |
|||
} |
|||
}, 50); |
|||
} |
|||
}, |
|||
|
|||
getName(item) { |
|||
if (!item.url) return '文件不存在'; |
|||
|
|||
if (item.name) { |
|||
return item.name; |
|||
} |
|||
let arr = item.url.split('/'); |
|||
return arr[arr.length - 1]; |
|||
}, |
|||
|
|||
getFileName(item) { |
|||
if (!item.url) return '文件不存在'; |
|||
if (item.name) { |
|||
return helper.cutStringLen(item.name, 23); |
|||
} |
|||
let arr = item.url.split('/'); |
|||
return helper.cutStringLen(arr[arr.length - 1], 23); |
|||
}, |
|||
|
|||
/** |
|||
* @description 启动自动翻页功能 |
|||
* @param index |
|||
*/ |
|||
callback(index){ |
|||
return (status)=>{ |
|||
let idx = 0; |
|||
if (status === 'prev') { |
|||
idx = (index - 1) < 0 ? (this.dataList.length -1) : (index - 1); |
|||
this.handleClick(this.dataList[idx], idx) |
|||
} |
|||
if (status === 'next') { |
|||
idx = (index + 1) === this.dataList.length ? 0 :(index + 1); |
|||
this.handleClick(this.dataList[idx], idx) |
|||
} |
|||
} |
|||
|
|||
}, |
|||
|
|||
handleClick(item,index) { |
|||
let calback = null; |
|||
if(this.isPagination) { |
|||
calback = this.callback(index); |
|||
} |
|||
this.$preview(item, calback) |
|||
}, |
|||
|
|||
handleRemoveClick(item, index) { |
|||
this.$emit('remove', item, () => { |
|||
this.dataList.splice(index, 1); |
|||
this.$emit('change', this.dataList,'remove'); |
|||
}); |
|||
} |
|||
} |
|||
|
|||
} |
|||
</script> |
|||
|
|||
<style scoped lang="less"> |
|||
@name: xd-file-list; |
|||
.@{name} { |
|||
&__body { |
|||
padding-top: 20px; |
|||
color: #333; |
|||
display: flex; |
|||
justify-content: flex-start; |
|||
align-items: center; |
|||
flex-wrap: wrap; |
|||
} |
|||
|
|||
|
|||
&__item { |
|||
position: relative; |
|||
padding: 10px; |
|||
box-sizing: border-box; |
|||
height: 68px; |
|||
background: #f6f7fa; |
|||
border: 1px solid #cacad1; |
|||
border-radius: 5px; |
|||
width: 294px; |
|||
margin: 0 20px 20px 0; |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
align-content: flex-start; |
|||
text-align: left; |
|||
flex-wrap: nowrap; |
|||
|
|||
&-icon { |
|||
width: 50px; |
|||
height: 50px; |
|||
margin-right: 10px; |
|||
background: #fff; |
|||
|
|||
img { |
|||
width: 100%; |
|||
height: 100%; |
|||
} |
|||
|
|||
div { |
|||
width: 50px; |
|||
height: 50px; |
|||
text-align: center; |
|||
vertical-align: middle; |
|||
} |
|||
|
|||
i { |
|||
margin-top: 3px; |
|||
font-size: 40px !important; |
|||
width: 100%; |
|||
height: 100%; |
|||
display: inline-block; |
|||
} |
|||
} |
|||
|
|||
&-text { |
|||
flex: 1; |
|||
|
|||
&-title { |
|||
|
|||
} |
|||
|
|||
&-link { |
|||
height: 20px; |
|||
font-size: 14px; |
|||
font-family: PingFangSC, PingFangSC-Regular; |
|||
color: #4285f4; |
|||
line-height: 20px; |
|||
cursor: pointer; |
|||
} |
|||
|
|||
&-link:hover { |
|||
text-decoration: underline; |
|||
} |
|||
} |
|||
|
|||
& i.iconyduicuowushixin { |
|||
cursor: pointer; |
|||
display: none; |
|||
position: absolute; |
|||
top: 2px; |
|||
right: -7px; |
|||
width: 30px; |
|||
height: 30px; |
|||
font-size: 21px; |
|||
color: #999; |
|||
} |
|||
|
|||
&:hover i.iconyduicuowushixin { |
|||
display: block; |
|||
} |
|||
} |
|||
} |
|||
|
|||
</style> |
@ -0,0 +1,60 @@ |
|||
<template></template> |
|||
<script> |
|||
export default { |
|||
name: 'XdLoadPdfScript', |
|||
props: { |
|||
pdf: { |
|||
type: String, |
|||
default: 'https://cdn.bootcdn.net/ajax/libs/pdf.js/2.0.288/pdf.min.js', |
|||
}, |
|||
worker: { |
|||
type: String, |
|||
default: 'https://cdn.bootcdn.net/ajax/libs/pdf.js/2.0.288/pdf.worker.min.js', |
|||
} |
|||
}, |
|||
watch:{ |
|||
pdfStatus(val) { |
|||
if (val && this.workerStatus) { |
|||
this.$emit('load') |
|||
} |
|||
}, |
|||
workerStatus(val) { |
|||
if (val && this.pdfStatus) { |
|||
this.$emit('load') |
|||
} |
|||
} |
|||
}, |
|||
data(){ |
|||
return { |
|||
pdfStatus : false, |
|||
workerStatus: false, |
|||
} |
|||
}, |
|||
created() { |
|||
this.$loadGetApi(); |
|||
this.$loadGetscript(); |
|||
}, |
|||
methods:{ |
|||
$loadGetApi() { |
|||
const s = document.createElement('script'); |
|||
s.type = 'text/javascript'; |
|||
s.src = this.pdf; |
|||
document.body.appendChild(s); |
|||
s.onload = () => { |
|||
this.pdfStatus = true; |
|||
} |
|||
}, |
|||
|
|||
$loadGetscript() { |
|||
const s = document.createElement('script'); |
|||
s.type = 'text/javascript'; |
|||
s.src = this.worker; |
|||
document.body.appendChild(s); |
|||
s.onload = () => { |
|||
this.workerStatus = true; |
|||
} |
|||
}, |
|||
} |
|||
|
|||
} |
|||
</script> |
@ -0,0 +1,131 @@ |
|||
<template> |
|||
<div> |
|||
<div ref="parent"></div> |
|||
<xd-load-pdf-script :pdf="$xdOptions['pdf']" :worker="$xdOptions['worker']" @load="handleLoad"></xd-load-pdf-script> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import XdLoadPdfScript from "./XdLoadPdfScript"; |
|||
|
|||
export default { |
|||
name: 'XdPdf', |
|||
components: {XdLoadPdfScript}, |
|||
props: { |
|||
fileUrl: { |
|||
type: Blob, |
|||
default: '' |
|||
}, |
|||
currentPages: { |
|||
type:Number, |
|||
default: 1, |
|||
} |
|||
}, |
|||
|
|||
data() { |
|||
return { |
|||
pdfFile: null, //pdf对象 |
|||
context: null, //canvas对象 |
|||
} |
|||
}, |
|||
watch:{ |
|||
currentPages(val){ |
|||
this.openPage(val); |
|||
}, |
|||
}, |
|||
|
|||
created(){ |
|||
console.log('created', this.$xdOptions); |
|||
}, |
|||
|
|||
methods: { |
|||
/** |
|||
* @description pdf 和 workerjs加载完毕事件 |
|||
*/ |
|||
handleLoad(){ |
|||
console.log('handleLoad') |
|||
this.createCanvas(); |
|||
this.fileReader(this.fileUrl) |
|||
.then(pdfArrayBuffer => { |
|||
this.renderFile(pdfArrayBuffer); |
|||
this.$emit('onLoad', pdfArrayBuffer); |
|||
}) |
|||
.catch(); |
|||
}, |
|||
|
|||
/** |
|||
* @description 创建Canvas节点 |
|||
*/ |
|||
createCanvas(){ |
|||
let canvas = document.createElement('canvas'); |
|||
if (this.$refs.parent) { |
|||
this.$refs.parent.appendChild(canvas) |
|||
} |
|||
this.context = canvas.getContext('2d') |
|||
}, |
|||
|
|||
/** |
|||
* @description 文件流转化 Blob to ArrayBuffer |
|||
* @param responseBlob {Blob} |
|||
* @returns {Promise<unknown>} |
|||
*/ |
|||
fileReader(responseBlob){ |
|||
return new Promise((resolve, reject)=>{ |
|||
const reader = new FileReader(); |
|||
reader.onload = (e) =>{ |
|||
console.log('fileReader', e.target['result']); |
|||
let pdfArrayBuffer = new Uint8Array(e.target['result']); |
|||
resolve(pdfArrayBuffer); |
|||
}; |
|||
reader.readAsArrayBuffer(responseBlob); |
|||
}) |
|||
}, |
|||
|
|||
/*** |
|||
* @description 生产pdf对象 |
|||
* @param pdfArrayBuffer |
|||
*/ |
|||
renderFile(pdfArrayBuffer) { |
|||
console.log('renderFile',pdfArrayBuffer); |
|||
if(PDFJS !== undefined) { |
|||
// 加载字体文件,避免字体显示不完成,——不加这两行不显示日期 |
|||
PDFJS.cMapUrl = 'https://cdn.jsdelivr.net/npm/pdfjs-dist@2.0.288/cmaps/'; |
|||
PDFJS.cMapPacked = true; |
|||
PDFJS['getDocument'](pdfArrayBuffer).then(pdfFile => { |
|||
console.log('getDocument', pdfFile); |
|||
if (pdfFile) { |
|||
this.pdfFile = pdfFile; |
|||
let pageNum = this.pdfFile.numPages; |
|||
this.$emit('num-pages', pageNum); |
|||
this.openPage(this.currentPages); |
|||
} |
|||
}) |
|||
} |
|||
|
|||
}, |
|||
|
|||
openPage(pageNumber) { |
|||
let scale = 8; |
|||
this.pdfFile.getPage(pageNumber).then(page => { |
|||
let viewport = page.getViewport(scale); |
|||
let canvas = this.context.canvas; |
|||
canvas.width = viewport.width; |
|||
canvas.height = viewport.height; |
|||
canvas.style.width = '100%'; |
|||
canvas.style.height = '100%'; |
|||
let renderContext = { |
|||
canvasContext: this.context, |
|||
viewport: viewport |
|||
} |
|||
page.render(renderContext).then(() => { |
|||
// 渲染完成 |
|||
this.$emit('onRender') |
|||
}) |
|||
}) |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style> |
|||
</style> |
48
xd-file-preview/src/components/contact.js
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,350 @@ |
|||
'use strict'; |
|||
|
|||
const MD5 = require('md5.js'); |
|||
import {iconData, textType, typeHeader} from "./../contact"; |
|||
|
|||
class Helper { |
|||
hideScroll(type){ |
|||
let body = document.getElementsByTagName('body')[0]; |
|||
if (type === 1) { |
|||
body.style.overflowY = 'hidden'; |
|||
body.style.height = '100%'; |
|||
} else { |
|||
body.style.overflowY = ''; |
|||
body.style.height = ''; |
|||
} |
|||
}; |
|||
|
|||
/** |
|||
* @description 字符串截取 |
|||
* @param val |
|||
* @param len |
|||
*/ |
|||
cutStringLen(val, len = 10) { |
|||
let fix = '...'; |
|||
let newLength = 0; |
|||
let newStr = ""; |
|||
let chineseRegex = /[^\x00-\xff]/g; |
|||
let singleChar = ""; |
|||
let strLength = val.replace(chineseRegex, "**").length; |
|||
for (let i = 0; i < strLength; i++) { |
|||
singleChar = val.charAt(i).toString(); |
|||
if (singleChar.match(chineseRegex) != null) { |
|||
newLength += 2; |
|||
} else { |
|||
newLength++; |
|||
} |
|||
if (newLength > len) { |
|||
break; |
|||
} |
|||
newStr += singleChar; |
|||
} |
|||
if (strLength > len) { |
|||
newStr += fix; |
|||
} |
|||
return newStr; |
|||
} |
|||
|
|||
checkVarType(obj) { |
|||
let toString = Object.prototype.toString; |
|||
let map = { |
|||
'[object Boolean]': 'boolean', |
|||
'[object Number]': 'number', |
|||
'[object String]': 'string', |
|||
'[object Function]': 'function', |
|||
'[object Array]': 'array', |
|||
'[object Date]': 'date', |
|||
'[object RegExp]': 'regExp', |
|||
'[object Undefined]': 'undefined', |
|||
'[object Null]': 'null', |
|||
'[object Object]': 'object', |
|||
'[object Blob]' : 'blob' |
|||
}; |
|||
return map[toString.call(obj)]; |
|||
} |
|||
|
|||
getID() { |
|||
return this.random(1111111, 9999999); |
|||
} |
|||
|
|||
md5Fn(str, hex = 'hex'){ |
|||
return new MD5()['update'](str)['digest'](hex); |
|||
} |
|||
|
|||
random(min, max) { |
|||
let Range = max - min; |
|||
let Rand = Math.random(); |
|||
return (min + Math.round(Rand * Range)); |
|||
} |
|||
|
|||
parseURL(url) { |
|||
if (!url) { |
|||
url = window.location.href; |
|||
} |
|||
let a = document.createElement('a'); |
|||
a.href = url; |
|||
return { |
|||
source: url, |
|||
protocol: a.protocol.replace(':', ''), |
|||
host: a.hostname, |
|||
port: a.port, |
|||
query: a.search, |
|||
params: (function() { |
|||
let ret = {}, |
|||
seg = a.search.replace(/^\?/, '').split('&'), |
|||
len = seg.length, i = 0, s; |
|||
for (; i < len; i++) { |
|||
if (!seg[i]) { |
|||
continue; |
|||
} |
|||
s = seg[i].split('='); |
|||
if (s[1]) { |
|||
ret[s[0]] = s[1]; |
|||
} |
|||
} |
|||
return ret; |
|||
})(), |
|||
file: (a.pathname.match(/\/([^\/?#]+)$/i) || [, ''])[1], |
|||
hash: a.hash.replace('#', ''), |
|||
path: a.pathname.replace(/^([^\/])/, '/$1'), |
|||
relative: (a.href.match(/tps?:\/\/[^\/]+(.+)/) || [, ''])[1], |
|||
segments: a.pathname.replace(/^\//, '').split('/') |
|||
}; |
|||
} |
|||
|
|||
/*** |
|||
* @description 获取文件类型 |
|||
* @param blob |
|||
*/ |
|||
checkFileType(blob){ |
|||
let type = typeHeader['unkown']; |
|||
if(typeHeader[blob.type]) { |
|||
type = typeHeader[blob.type]; |
|||
} |
|||
return type; |
|||
} |
|||
|
|||
|
|||
checkType(arr, item) { |
|||
let temp = arr.filter(it => { |
|||
return it === item; |
|||
}); |
|||
return temp.length > 0; |
|||
} |
|||
|
|||
/** |
|||
* @description 获取文件base64流 |
|||
* @param blob |
|||
* @param file |
|||
* @returns {Promise<unknown>} |
|||
*/ |
|||
fileReaderBase64(blob, file){ |
|||
return new Promise((resolve, reject)=>{ |
|||
let reader = new FileReader(); |
|||
reader.onload = (e)=> { |
|||
if(file.type === 'JSON') { |
|||
resolve(JSON.parse(e.target['result'])); |
|||
} |
|||
else { |
|||
resolve(e.target['result']); |
|||
} |
|||
}; |
|||
reader.onerror = ()=>{ |
|||
reject('读取文件错误') |
|||
}; |
|||
|
|||
if (file.type === 'JSON' |
|||
|| this.checkType(textType, file.type) |
|||
) reader.readAsText(blob, 'utf-8'); |
|||
else reader.readAsDataURL(blob); |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* @description 获取文件相关信息 |
|||
* @param url |
|||
* @param name |
|||
* @returns {Promise<unknown>} |
|||
*/ |
|||
getFileBase64(url='',name = '') { |
|||
return new Promise((resolve, reject) => { |
|||
let getName = (type)=> { |
|||
let str = url; |
|||
if(str.indexOf('?')) str = url.split('?')[0]; |
|||
let arr = str.split('/'); |
|||
return arr[arr.length - 1]; |
|||
}; |
|||
|
|||
let x = new XMLHttpRequest(); |
|||
x.open("GET", url, true); |
|||
x.responseType = "blob"; |
|||
x.onload = (e) => { |
|||
console.log('XMLHttpRequest',e); |
|||
if (e.target['status'] === 200) { |
|||
//console.log('this.checkFileType(e.target[\'response\'])',url,this.checkFileType(e.target['response']));
|
|||
let temp = { |
|||
type: this.checkFileType(e.target['response']), |
|||
size: e.target['response']['size'], |
|||
name: name ? name: getName(this.checkFileType(e.target['response'])), |
|||
}; |
|||
|
|||
this.fileReaderBase64(e.target['response'], temp) |
|||
.then(res=>{ |
|||
temp['url'] = res; |
|||
temp['icon'] = this.getIcon(temp['type']); |
|||
temp['response'] = e.target['response']; |
|||
resolve(temp); |
|||
}) |
|||
.catch(res=>{ |
|||
reject(res) |
|||
}) |
|||
} else if (e.target['status'] === 404) { |
|||
console.error('error', e); |
|||
reject('您下载的文件不存在!'); |
|||
} else { |
|||
console.error('error', e); |
|||
reject('网络错误!'); |
|||
} |
|||
}; |
|||
x.onerror = (e) => { |
|||
console.log('onerror') |
|||
console.log('error', e); |
|||
reject('网络错误!'); |
|||
} |
|||
x.send(); |
|||
}) |
|||
|
|||
} |
|||
|
|||
/** |
|||
* @description 获取图片相应的图片 |
|||
* @param type |
|||
* @returns {string} |
|||
*/ |
|||
getIcon(type='') { |
|||
let temp = ''; |
|||
if(this.checkType(textType, type)) { |
|||
type = 'text'; |
|||
} |
|||
|
|||
if(iconData[type.toLocaleLowerCase()]) { |
|||
temp = iconData[type.toLocaleLowerCase()]; |
|||
} |
|||
return temp; |
|||
} |
|||
|
|||
|
|||
/** |
|||
* @description 判断俩个需要处理的数字谁的小数点后位数多, |
|||
* 以多的为准,值乘以10的小数位的幂数,相加以后,再除以10的小数位的幂数 |
|||
* @param currentNum |
|||
* @param targetNum |
|||
*/ |
|||
checkFloatMore(currentNum, targetNum){ |
|||
let sq1, sq2; |
|||
try {sq1 = currentNum.toString().split(".")[1].length;} |
|||
catch (e) {sq1 = 0;} |
|||
try {sq2 = targetNum.toString().split(".")[1].length;} |
|||
catch (e) {sq2 = 0;} |
|||
return Math.pow(10, Math.max(sq1, sq2)); |
|||
} |
|||
|
|||
/** |
|||
* @description 两个小数相加 |
|||
* @param currentNum |
|||
* @param targetNum |
|||
* @return number |
|||
*/ |
|||
addFloatNumber(currentNum, targetNum){ |
|||
let power = this.checkFloatMore(currentNum, targetNum); |
|||
return (currentNum * power + targetNum * power) / power; |
|||
} |
|||
|
|||
/** |
|||
* @description 两个小数减 |
|||
* @param currentNum |
|||
* @param targetNum |
|||
* @return number |
|||
*/ |
|||
cutFloatNumber(currentNum, targetNum) { |
|||
let power = this.checkFloatMore(currentNum, targetNum); |
|||
return (currentNum * power - targetNum * power) / power; |
|||
} |
|||
|
|||
/** |
|||
* @description 计算两个小数相乘 |
|||
* @param currentNum |
|||
* @param targetNum |
|||
* @returns {number} |
|||
*/ |
|||
multiplyFloatNumber(currentNum, targetNum){ |
|||
let m = 0, s1 = currentNum.toString(), s2 = targetNum.toString(); |
|||
try {m += s1.split(".")[1].length;} catch (e) {} |
|||
try {m += s2.split(".")[1].length;} catch (e) {} |
|||
return Number(s1.replace(".", "")) * Number(s2.replace(".", "")) / Math.pow(10, m); |
|||
} |
|||
|
|||
/** |
|||
* @description 计算两个小数相除 |
|||
* @param currentNum |
|||
* @param targetNum |
|||
* @returns {number} |
|||
*/ |
|||
divisionFloatNumber(currentNum, targetNum){ |
|||
let t1 = 0, t2 = 0, r1, r2; |
|||
try {t1 = currentNum.toString().split(".")[1].length} catch (e) {} |
|||
try {t2 = targetNum.toString().split(".")[1].length} catch (e) {} |
|||
r1 = Number(currentNum.toString().replace(".", "")) |
|||
r2 = Number(targetNum.toString().replace(".", "")) |
|||
return (r1 / r2) * Math.pow(10, t2 - t1); |
|||
} |
|||
|
|||
/** |
|||
* @description 创建node节点 |
|||
* @param options {object} |
|||
* @param options.fid 文件ID,唯一id(必填) |
|||
* @param options.name 文件名称(选填) |
|||
* @param options.url //文件地址(必填)
|
|||
* @param Vue Vue类 (必填) |
|||
* @param view vue文件(必填) |
|||
*/ |
|||
createElement(options, Vue, view){ |
|||
console.log('PDF预览功能', options); |
|||
let str = `${options.name}${options['fid']}`; |
|||
let elId = `img-${this.md5Fn(str)}`; |
|||
let ele = document.getElementById(elId); |
|||
|
|||
if (ele) { |
|||
ele.style.display = "block"; |
|||
this.hideScroll(1); |
|||
if(typeof options['callback'] === 'function') { |
|||
options['callback']('show') |
|||
} |
|||
return ele; |
|||
} |
|||
|
|||
const View = Vue.extend(view); |
|||
let $view = new View({ |
|||
el: document.createElement('div') |
|||
}); |
|||
options['ele'] = elId; |
|||
$view.options = options; |
|||
$view.close = (id) => { |
|||
let ele = document.getElementById(id); |
|||
ele.style.display = "none"; |
|||
this.hideScroll(-1); |
|||
if (typeof options['callback'] === 'function') { |
|||
options['callback']('close') |
|||
} |
|||
}; |
|||
|
|||
document.body.appendChild($view.$el); |
|||
this.hideScroll(1); |
|||
if (typeof options['callback'] === 'function') { |
|||
options['callback']('show') |
|||
} |
|||
} |
|||
|
|||
} |
|||
|
|||
export default new Helper(); |
@ -0,0 +1,18 @@ |
|||
'use strict'; |
|||
|
|||
import imgPreview from "./imageView"; |
|||
import helper from "./helper"; |
|||
|
|||
/** |
|||
* @description 图片预览功能 |
|||
* @param options {object} |
|||
* @param options.fid 文件ID,唯一id(必填) |
|||
* @param options.name 文件名称 |
|||
* @param options.type 文件类型 |
|||
* @param options.url //图片地址
|
|||
* @param $vue Vue |
|||
*/ |
|||
export default function (options, $vue) { |
|||
console.log('111,PDF预览功能'); |
|||
helper.createElement(options, $vue, imgPreview); |
|||
} |
@ -0,0 +1,554 @@ |
|||
<template> |
|||
<div class="img-preview" :id="options.ele" v-if="info && options && options.ele"> |
|||
<div class="img-preview-title" ref="imgPreviewHeader"> |
|||
<div class="img-preview-l" v-if="options.status"> |
|||
<img :src="options.icon" width="30" height="30"> |
|||
<span>{{info.name|getFileName(options['type'].toLocaleLowerCase())}}</span> |
|||
<button v-if="isDownLoad" class="btn" @click="download">下载</button> |
|||
</div> |
|||
<div class="img-preview-close" @click="closeHandle(options.ele)"><i class="fileIconfont iconwrong"></i></div> |
|||
</div> |
|||
<div class="img-preview-content"> |
|||
<div v-show="options.status" class="img-preview-content-box" @click="closeHandle(options.ele)" |
|||
:style="`top:${top}px;left: ${left}px`"> |
|||
<img |
|||
@mousedown="interHandle" |
|||
@mousemove="moveHandle" |
|||
@mouseup="leaveHandle" |
|||
@mouseleave="leaveHandle" |
|||
@mouseout="leaveHandle" |
|||
@click.stop="()=> {return false}" |
|||
ref="imgPreview" |
|||
:style="`cursor: ${pointerHandle()}; height: ${height}px; width:${width}px;transform:scale(${scale}) translate(${translatex}px,${translatey}px) rotate(${angle}deg)`" |
|||
@load="loadhandle()" |
|||
@error="errorHandle" |
|||
:src="options.url" alt="preview" |
|||
/> |
|||
</div> |
|||
<div class="img-preview-scale-percentage" v-if="showScale"><span>{{scalePercentage}}%</span></div> |
|||
<div class="img-preview-error" v-if="!options.status" @click="closeHandle(options.ele)"> |
|||
<div class="img-preview-error-content"> |
|||
<div class="img-preview-error-ico"><i class="iconfont iconwenjian"></i></div> |
|||
<div class="img-preview-error-tips">哎哟!我们无法加载该文件。</div> |
|||
<div class="img-preview-error-url" v-html="options.url"></div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="img-preview-toolbar" v-if="options.status && isShowToolbar"> |
|||
<span> |
|||
<i class="fileIconfont iconfangda" @click="zoomHandle(1)"></i> |
|||
<i class="fileIconfont iconsuoxiao" @click="zoomHandle(-1)"></i> |
|||
<i class="fileIconfont iconzuozhuan" @click="rotateHandle(-1)"></i> |
|||
<i class="fileIconfont iconyouzhuan" @click="rotateHandle(1)"></i> |
|||
<i class="fileIconfont iconhuanyuan" @click="zoomOriginalSize()"></i> |
|||
</span> |
|||
</div> |
|||
<div class="img-preview-bottom"></div> |
|||
<div class="change change-prev" v-if="isBtn" @click="handeCilck('prev')"> |
|||
<i class="fileIconfont iconpageup"></i> |
|||
</div> |
|||
<div class="change change-next" v-if="isBtn" @click="handeCilck('next')"> |
|||
<i class="fileIconfont iconpagedown"></i> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
<script> |
|||
import lodash from "lodash"; |
|||
import {iconData} from './../contact' |
|||
import download from 'downloadjs'; |
|||
|
|||
window.timeer = null; |
|||
window.zoomTimeer = null; |
|||
|
|||
window.boxyEleStop = () => { |
|||
return false; |
|||
}; |
|||
export default { |
|||
name: "img-preview", |
|||
props: { |
|||
options: Object, |
|||
}, |
|||
|
|||
watch: { |
|||
options(val) { |
|||
this.info = val; |
|||
if(val.download === false) this.isDownLoad = val.download; |
|||
console.log('options',val) |
|||
} |
|||
}, |
|||
filters: { |
|||
getFileName(name, type) { |
|||
console.log('getFileName',name, type) |
|||
if (name.indexOf(`.${type}`) === -1) { |
|||
return `${name}.${type}` |
|||
} |
|||
return name; |
|||
} |
|||
}, |
|||
computed:{ |
|||
isBtn() { |
|||
let isBtn = false; |
|||
if (this.info && this.info.callback && typeof this.info.callback === 'function') isBtn = true; |
|||
return isBtn |
|||
} |
|||
}, |
|||
data() { |
|||
return { |
|||
/**image**/ |
|||
showScale: false, |
|||
bodyEle: null, |
|||
eleStop: null, |
|||
isShowToolbar: false, |
|||
scalePercentage: 100, |
|||
scaleZoomTime: 500, |
|||
isError: false, |
|||
show: false, |
|||
top: -9999, |
|||
left: -9999, |
|||
width: 0, |
|||
height: 0, |
|||
angle: 0, |
|||
scale: 1, |
|||
moveStatus: false, |
|||
translatex: 0, |
|||
translatey: 0, |
|||
offsetX: 0, |
|||
offsetY: 0, |
|||
scaleLen: 0.2, |
|||
scaleMax: 4, /**最大放大4倍**/ |
|||
scaleMin: 0.2, /**最小缩小0.2倍**/ |
|||
originalWidth: 0, |
|||
originalHeight: 0, |
|||
windowWidth: 0, |
|||
windowHeight: 0, |
|||
loadingEle: '', |
|||
loadingUrl: iconData.loadicon, |
|||
/**image**/ |
|||
|
|||
info: null, |
|||
isDownLoad: true, |
|||
} |
|||
}, |
|||
|
|||
mounted() { |
|||
this.windowWidth = document.body.clientWidth; |
|||
this.windowHeight = window.innerHeight - 60; |
|||
let that = this; |
|||
|
|||
this.$nextTick(() => { |
|||
window.onresize = lodash.debounce(() => { |
|||
that.windowWidth = window.innerWidth; |
|||
//console.log(that.$refs.imgPreviewHeader, that.$refs.imgPreviewHeader.clientHeight); |
|||
that.windowHeight = window.innerHeight - that.$refs.imgPreviewHeader.clientHeight; |
|||
that.loadhandle(); |
|||
}, 400); |
|||
}); |
|||
|
|||
/**屏蔽图片拖拽功能**/ |
|||
window.bodyEle = document.getElementsByTagName('body')[0]; |
|||
window.bodyEle.ondragstart = () => { |
|||
return false; |
|||
} |
|||
window.bodyEle.onselect = () => { |
|||
return false; |
|||
} |
|||
|
|||
//window.bodyEle.addEventListener('dragstart', window.boxyEleStop,false); |
|||
//window.bodyEle.addEventListener('select', window.boxyEleStop, false); |
|||
}, |
|||
methods: { |
|||
handeCilck(status) { |
|||
if (this.info && this.info.callback && typeof this.info.callback === 'function') { |
|||
this.closeHandle(this.info.ele); |
|||
this.info.callback(status) |
|||
} |
|||
}, |
|||
download() { |
|||
console.log(this.info) |
|||
download(this.info['response'], this.info['name']) |
|||
}, |
|||
|
|||
loadhandle() { |
|||
let img = this.$refs.imgPreview; |
|||
|
|||
this.originalWidth = img.naturalWidth; |
|||
this.originalHeight = img.naturalHeight; |
|||
|
|||
|
|||
/** |
|||
* imgw <= ww and imgh <= wh |
|||
*/ |
|||
if (this.originalWidth <= this.windowWidth && this.originalHeight <= this.windowHeight) { |
|||
this.width = this.originalWidth; |
|||
this.height = this.originalHeight; |
|||
} |
|||
// else if(this.originalWidth > this.windowWidth && this.originalHeight < this.windowHeight){ |
|||
// this.width = this.windowWidth; |
|||
// this.height = this.width * this.originalHeight/ this.originalWidth; |
|||
// }else if(this.originalHeight > this.windowHeight && this.originalWidth < this.windowWidth){ |
|||
// this.height = this.windowHeight; |
|||
// this.width = this.height * this.originalWidth / this.originalHeight; |
|||
// } |
|||
|
|||
/** |
|||
* imgh > wh and imgw > ww |
|||
* 实际高度/窗口高度的倍数 与 实际宽度/窗口宽度的倍数 比较 谁的倍数越大 就使用谁为基准参数 |
|||
*/ |
|||
else { |
|||
|
|||
let wb = this.originalWidth / this.windowWidth; |
|||
let Hb = this.originalHeight / this.windowHeight; |
|||
console.log('aaa', wb, Hb); |
|||
|
|||
if (wb > Hb) { |
|||
this.width = this.windowWidth; |
|||
this.height = this.width * this.originalHeight / this.originalWidth; |
|||
} else { |
|||
this.height = this.windowHeight; |
|||
this.width = this.height * this.originalWidth / this.originalHeight; |
|||
} |
|||
} |
|||
|
|||
console.log(this.width, this.height, this.originalWidth, this.originalHeight); |
|||
|
|||
this.top = 0; |
|||
this.left = 0; |
|||
this.show = true; |
|||
this.isShowToolbar = true; |
|||
}, |
|||
zoomHandle(type) { |
|||
let scale = this.scale + this.scaleLen * type; |
|||
if (scale < this.scaleMin) scale = this.scaleMin; |
|||
if (scale > this.scaleMax) scale = this.scaleMax; |
|||
this.scale = scale; |
|||
this.showScale = true; |
|||
this.scalePercentage = parseInt(this.scale * 100); |
|||
|
|||
if (window.zoomTimeer) { |
|||
clearTimeout(window.zoomTimeer); |
|||
} |
|||
window.zoomTimeer = setTimeout(() => { |
|||
this.showScale = false; |
|||
}, this.scaleZoomTime); |
|||
}, |
|||
zoomOriginalSize() { |
|||
|
|||
/**原始尺寸不处理**/ |
|||
// if (this.scale === 1) { |
|||
// return |
|||
// } |
|||
|
|||
this.scale = 1; |
|||
this.angle = 0; |
|||
this.translatex = 0; |
|||
this.translatey = 0; |
|||
|
|||
this.showScale = true; |
|||
this.scalePercentage = parseInt(this.scale * 100); |
|||
|
|||
if (window.zoomTimeer) { |
|||
clearTimeout(window.zoomTimeer); |
|||
} |
|||
window.zoomTimeer = setTimeout(() => { |
|||
this.showScale = false; |
|||
}, this.scaleZoomTime); |
|||
|
|||
}, |
|||
rotateHandle(type) { |
|||
this.angle = this.angle + 90 * type; |
|||
if (this.angle % 180 === 0) { |
|||
this.loadhandle(1) |
|||
} else { |
|||
this.loadhandle(-1) |
|||
} |
|||
}, |
|||
pointerHandle() { |
|||
let img = this.$refs.imgPreview; |
|||
|
|||
/**旋转状态不支持拖拽**/ |
|||
if (this.angle !== 0) { |
|||
return 'default'; |
|||
} |
|||
|
|||
if (!img) return 'default'; |
|||
if (this.width * this.scale > this.windowWidth |
|||
|| this.height * this.scale > this.windowHeight) { |
|||
return 'pointer'; |
|||
} else { |
|||
return "default" |
|||
} |
|||
}, |
|||
moveHandle($vet) { |
|||
if (this.pointerHandle() === 'default' || !this.moveStatus) return; |
|||
this.translatex = $vet.offsetX - this.offsetX; |
|||
this.translatey = $vet.offsetY - this.offsetY; |
|||
|
|||
}, |
|||
interHandle($vet) { |
|||
if (this.pointerHandle() === 'default') return; |
|||
this.offsetX = $vet.offsetX - this.translatex; |
|||
this.offsetY = $vet.offsetY - this.translatey; |
|||
this.moveStatus = true; |
|||
}, |
|||
leaveHandle($vet) { |
|||
if (this.pointerHandle() === 'default') return; |
|||
this.moveStatus = false; |
|||
}, |
|||
errorHandle($vet) { |
|||
console.log('errorHandle=>', $vet); |
|||
this.isError = true; |
|||
this.show = true |
|||
}, |
|||
closeHandle(id) { |
|||
//window.bodyEle.removeEventListener('dragstart', window.boxyEleStop); |
|||
//window.bodyEle.removeEventListener('select', window.boxyEleStop); |
|||
this.close(id); |
|||
}, |
|||
}, |
|||
|
|||
|
|||
}; |
|||
</script> |
|||
<style type="text/css"> |
|||
@import "style.css"; |
|||
|
|||
.img-preview { |
|||
position: fixed; |
|||
top: 0; |
|||
left: 0; |
|||
bottom: 0; |
|||
right: 0; |
|||
width: 100%; |
|||
height: 100%; |
|||
min-width: 1000px; |
|||
min-height: 300px; |
|||
background: rgba(0, 0, 0, 0.5); |
|||
z-index: 2098; |
|||
} |
|||
|
|||
.img-preview-title { |
|||
width: 100%; |
|||
height: 48px; |
|||
background: #333; |
|||
color: #fff; |
|||
box-shadow: 0 0 20px rgba(0, 0, 0, 0.5); |
|||
} |
|||
|
|||
.img-preview-l img { |
|||
margin-right: 15px; |
|||
} |
|||
|
|||
.img-preview-l { |
|||
float: left; |
|||
height: 100%; |
|||
display: flex; |
|||
justify-content: flex-start; |
|||
align-items: center; |
|||
padding-left:10px; |
|||
} |
|||
|
|||
.img-preview-l .btn { |
|||
background: #4395ff; |
|||
margin-left: 20px; |
|||
font-size: 14px; |
|||
height: 30px; |
|||
max-height: 30px; |
|||
border-radius: 15px; |
|||
padding: 0 20px; |
|||
outline: none; |
|||
border: 1px solid #4395ff; |
|||
color: #fff; |
|||
box-shadow: 0 0 0 rgba(0, 0, 0, 0); |
|||
transition: all .5s; |
|||
} |
|||
|
|||
.img-preview-l .btn:hover { |
|||
box-shadow: 0 0 10px rgba(0, 0, 0, .3); |
|||
opacity: 0.9; |
|||
background: #539dfc; |
|||
cursor: pointer; |
|||
} |
|||
|
|||
|
|||
.img-preview-l .icontupian { |
|||
font-size: 30px; |
|||
margin-right: 10px; |
|||
} |
|||
|
|||
.img-preview-bottom { |
|||
position: absolute; |
|||
bottom: 0; |
|||
left: 0; |
|||
right: 0; |
|||
height: 0; |
|||
background: #333; |
|||
} |
|||
|
|||
.img-preview-close { |
|||
cursor: pointer; |
|||
float: right; |
|||
font-size: 30px; |
|||
width: 30px; |
|||
height: 30px; |
|||
margin: 9px 7px 0 0; |
|||
line-height: 30px; |
|||
} |
|||
|
|||
i.fileIconfont { |
|||
font-size: 30px; |
|||
font-weight: normal; |
|||
} |
|||
|
|||
i.fileIconfont.iconzuozhuan, i.fileIconfont.iconyouzhuan, i.fileIconfont.iconhuanyuan { |
|||
font-size: 28px; |
|||
font-weight: normal !important; |
|||
} |
|||
|
|||
.img-preview-toolbar { |
|||
position: absolute; |
|||
font-size: 0; |
|||
left: 50%; |
|||
bottom: 30px; |
|||
text-align: center; |
|||
transform: translateX(-50%); |
|||
z-index: 10000 |
|||
} |
|||
|
|||
.img-preview-toolbar span { |
|||
display: flex; |
|||
line-height: 24px; |
|||
border-radius: 8px; |
|||
padding: 8px 10px; |
|||
font-size: 0; |
|||
background: rgba(0, 0, 0, 0.5); |
|||
} |
|||
|
|||
.img-preview-toolbar span * { |
|||
margin: 0 6px; |
|||
color: #fff; |
|||
font-size: 30px; |
|||
cursor: pointer; |
|||
font-weight: 400; |
|||
} |
|||
|
|||
.img-preview-scale-percentage { |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
align-content: center; |
|||
flex-wrap: nowrap; |
|||
height: 100%; |
|||
width: 100%; |
|||
position: absolute; |
|||
top: 0; |
|||
left: 0; |
|||
} |
|||
|
|||
.img-preview-scale-percentage span { |
|||
width: 80px; |
|||
height: 30px; |
|||
line-height: 30px; |
|||
background: rgba(0, 0, 0, 0.6); |
|||
border-radius: 5px; |
|||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.5); |
|||
color: #fff; |
|||
text-align: center; |
|||
margin-right: 5px; |
|||
} |
|||
|
|||
.img-preview-content { |
|||
height: -moz-calc(100% - 60px); |
|||
height: -webkit-calc(100% - 60px); |
|||
height: calc(100% - 60px); |
|||
overflow: hidden; |
|||
position: relative; |
|||
|
|||
} |
|||
|
|||
.img-preview-content-box { |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
align-content: center; |
|||
flex-wrap: nowrap; |
|||
height: 100%; |
|||
width: 100%; |
|||
position: absolute; |
|||
top: -9999px; |
|||
left: -9999px; |
|||
} |
|||
|
|||
.img-preview-content-box img { |
|||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.5); |
|||
} |
|||
|
|||
.img-preview-mask { |
|||
position: absolute; |
|||
top: 0; |
|||
left: 0; |
|||
bottom: 0; |
|||
right: 0; |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
flex-direction: row; |
|||
flex-wrap: nowrap; |
|||
} |
|||
|
|||
.img-preview-mask span { |
|||
width: 80px; |
|||
height: 80px; |
|||
padding: 10px; |
|||
margin-right: 5px; |
|||
border-radius: 10px; |
|||
background: #171717; |
|||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.5); |
|||
} |
|||
|
|||
.img-preview-mask img { |
|||
width: 100%; |
|||
height: 100%; |
|||
} |
|||
|
|||
.img-preview-error { |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
align-content: center; |
|||
flex-wrap: nowrap; |
|||
height: 100%; |
|||
width: 100%; |
|||
} |
|||
|
|||
.img-preview-error-content { |
|||
width: 540px; |
|||
background: #000; |
|||
border-radius: 10px; |
|||
padding: 30px; |
|||
color: #fff; |
|||
text-align: center; |
|||
|
|||
} |
|||
|
|||
i.fileIconfont.iconwenjian { |
|||
font-size: 60px; |
|||
font-weight: normal; |
|||
} |
|||
|
|||
.img-preview-error-tips { |
|||
font-size: 18px; |
|||
line-height: 30px; |
|||
padding: 10px 0 30px |
|||
} |
|||
|
|||
.img-preview-error-url { |
|||
font-size: 13px; |
|||
line-height: 24px; |
|||
word-wrap: break-word; |
|||
} |
|||
|
|||
.ant-tooltip.ant-tooltip-placement-top { |
|||
z-index: 1000; |
|||
} |
|||
|
|||
</style> |
@ -0,0 +1,143 @@ |
|||
'use strict'; |
|||
|
|||
import image from "./image"; |
|||
import office from "./office"; |
|||
import pdf from "./pdf"; |
|||
import json from "./json"; |
|||
import text from "./text"; |
|||
import helper from "./helper"; |
|||
import ofd from "./ofd"; |
|||
import {iconData, imagesType , wordType, pdfType, jsonType, textType, ofdType} from './../contact'; |
|||
import Loading from "./loading"; |
|||
|
|||
/** |
|||
* @description 检查文件类型 |
|||
* @param arr {Array} |
|||
* @param item |
|||
*/ |
|||
function checkType(arr, item ) { |
|||
let temp = arr.filter(it =>{ |
|||
return it === item; |
|||
}); |
|||
return temp.length > 0; |
|||
} |
|||
|
|||
function check(options, $vue) { |
|||
console.log('options', options['type'], JSON.stringify(wordType)) |
|||
//错误图片
|
|||
if (!options.status) { |
|||
image(options, $vue); |
|||
return; |
|||
} |
|||
|
|||
//图片类型
|
|||
if (checkType(imagesType, options['type'])) { |
|||
console.log('image'); |
|||
image(options, $vue); |
|||
} |
|||
|
|||
//word文件类型
|
|||
if (checkType(wordType, options['type'])) { |
|||
console.log('office'); |
|||
office(options, $vue); |
|||
} |
|||
|
|||
//Pdf文件类型
|
|||
if (checkType(pdfType, options['type'])) { |
|||
console.log('pdf'); |
|||
pdf(options, $vue); |
|||
} |
|||
|
|||
//TEXT文件类型
|
|||
if (checkType(textType, options['type'])) { |
|||
console.log('text'); |
|||
text(options, $vue); |
|||
} |
|||
|
|||
|
|||
//JSON文件类型
|
|||
if (checkType(jsonType, options['type'])) { |
|||
console.log('json'); |
|||
json(options, $vue); |
|||
} |
|||
|
|||
//OFD文件类型
|
|||
if (checkType(ofdType, options['type'])) { |
|||
console.log('ofd'); |
|||
ofd(options, $vue); |
|||
} |
|||
} |
|||
|
|||
let __File_Save = {}; |
|||
|
|||
/** |
|||
* @description 文件预览功能 |
|||
* @param options {object} |
|||
* @param options.fid 文件ID,唯一id(必填) |
|||
* @param options.name 文件名称(选填) |
|||
* @param options.url //文件地址(必填)
|
|||
* @param $vue |
|||
*/ |
|||
export function preview(options={}, $vue) { |
|||
|
|||
//已经加载过的文件
|
|||
if(options['response'] && helper.checkVarType(options['response']) === 'blob') { |
|||
check(options, $vue); |
|||
return; |
|||
} |
|||
|
|||
let keyMd5 = helper.md5Fn(`${options.url}${options.fid}`); |
|||
if(__File_Save[keyMd5]) { |
|||
check(__File_Save[keyMd5], $vue); |
|||
return |
|||
} |
|||
|
|||
/** |
|||
* @description 创建loading实例 |
|||
* @type {ExtendedVue<Vue, unknown, unknown, unknown, Record<never, any>>} |
|||
*/ |
|||
const loadingVue = $vue.extend(Loading); |
|||
let $loading = new loadingVue({ |
|||
el: document.createElement('div'), |
|||
props: { |
|||
show: { |
|||
type: Boolean, |
|||
default: true |
|||
} |
|||
} |
|||
}); |
|||
document.body.appendChild($loading.$el); |
|||
|
|||
/** |
|||
* @description 销毁loading实例 |
|||
*/ |
|||
const $destroy = () => { |
|||
$loading.$destroy(); |
|||
$loading.$el.parentNode.removeChild($loading.$el); |
|||
}; |
|||
|
|||
let t = new Date().getTime(); |
|||
options['src'] = iconData.loadicon; |
|||
options['source'] = options['url']; |
|||
|
|||
helper.getFileBase64(options.url, options.name) |
|||
.then(res=>{ |
|||
let now = new Date().getTime(); |
|||
let deTime = 1000 - (now - t); |
|||
setTimeout(()=>{ |
|||
$destroy(); |
|||
options = Object.assign({}, options, res); |
|||
options['status'] = true; |
|||
__File_Save[keyMd5] = options; |
|||
check(options, $vue); |
|||
}, (deTime <=10? 10: deTime)); |
|||
}) |
|||
.catch(res=>{ |
|||
console.error('res',options, res); |
|||
options['status'] = false; |
|||
$destroy(); |
|||
__File_Save[keyMd5] = options; |
|||
console.log(options); |
|||
image(options, $vue); |
|||
}); |
|||
} |
@ -0,0 +1,17 @@ |
|||
'use strict'; |
|||
|
|||
import jsonView from "./jsonView"; |
|||
import helper from "./helper"; |
|||
|
|||
/** |
|||
* @description PDF预览功能 |
|||
* @param options {object} |
|||
* @param options.fid 文件ID,唯一id(必填) |
|||
* @param options.name 文件名称 |
|||
* @param options.type 文件类型 |
|||
* @param options.url // PDF地址
|
|||
* @param $vue Vue |
|||
*/ |
|||
export default function (options, $vue) { |
|||
helper.createElement(options, $vue, jsonView); |
|||
} |
@ -0,0 +1,309 @@ |
|||
<template> |
|||
<div class="pdf-preview" :id="options.ele" v-if="info"> |
|||
<div class="pdf-preview__title"> |
|||
<div class="pdf-preview__title-text"> |
|||
<img :src="options.icon" height="30" width="30"> |
|||
<input class="pdf-preview__input" v-model.number="page" type="number"> |
|||
<span>/ {{numPages}}</span> |
|||
<button class="btn" v-if="isDownLoad" @click="download">下载</button> |
|||
<span>{{info.name|getFileName(options['type'].toLocaleLowerCase())}}</span> |
|||
</div> |
|||
<div class="pdf-preview__title-close" @click="closeHandle(options.ele)"><i class="fileIconfont iconwrong"></i></div> |
|||
</div> |
|||
<div class="pdf-preview__content" :style="`width: ${getWdith}`"> |
|||
<json-viewer |
|||
:value="info.url" |
|||
:expand-depth='2' |
|||
> |
|||
</json-viewer> |
|||
</div> |
|||
<div class="img-preview__bottom"></div> |
|||
<div class="change change-prev" v-if="isBtn" @click="handeCilck('prev')"> |
|||
<i class="fileIconfont iconpageup"></i> |
|||
</div> |
|||
<div class="change change-next" v-if="isBtn" @click="handeCilck('next')"> |
|||
<i class="fileIconfont iconpagedown"></i> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
<script> |
|||
import helper from "./helper"; |
|||
import download from 'downloadjs'; |
|||
import JsonViewer from 'vue-json-viewer' |
|||
|
|||
export default { |
|||
name: "xdPdfPreview", |
|||
|
|||
props: { |
|||
options: { |
|||
type: Object|null, |
|||
default(){ |
|||
return null |
|||
} |
|||
}, |
|||
}, |
|||
components: { |
|||
JsonViewer |
|||
}, |
|||
data() { |
|||
return { |
|||
src: '', |
|||
loadedRatio: 0, |
|||
page: 1, |
|||
numPages: 0, |
|||
rotate: 0, |
|||
width: 0.5, |
|||
info: null, |
|||
isDownLoad: true, |
|||
|
|||
} |
|||
}, |
|||
filters:{ |
|||
getFileName(name, type){ |
|||
if(name.indexOf(`.${type}`) === -1) { |
|||
return `${name}.${type}` |
|||
} |
|||
return name; |
|||
} |
|||
}, |
|||
watch:{ |
|||
options(val){ |
|||
this.info = val; |
|||
if (val.download === false) this.isDownLoad = val.download; |
|||
if(this.info['url']) { |
|||
this.src= this.info['url'] |
|||
} |
|||
}, |
|||
}, |
|||
created(){ |
|||
this.info = this.options; |
|||
if (this.options && this.options.download === false) this.isDownLoad = this.options.download; |
|||
}, |
|||
computed:{ |
|||
getWdith() { |
|||
return (this.width * 100) + '%'; |
|||
}, |
|||
isBtn() { |
|||
let isBtn = false; |
|||
if (this.info && this.info.callback && typeof this.info.callback === 'function') isBtn = true; |
|||
return isBtn |
|||
} |
|||
}, |
|||
methods: { |
|||
handeCilck(status) { |
|||
if (this.info && this.info.callback && typeof this.info.callback === 'function') { |
|||
this.closeHandle(this.info.ele); |
|||
this.info.callback(status) |
|||
} |
|||
}, |
|||
/** |
|||
* @description 设置总页数 |
|||
*/ |
|||
setTotalNumPages(num){ |
|||
this.numPages = num; |
|||
}, |
|||
closeHandle(id) { |
|||
this.close(id); |
|||
}, |
|||
|
|||
download(){ |
|||
download(this.info['response'], this.info['name']) |
|||
}, |
|||
|
|||
/** |
|||
* @description 翻页处理 |
|||
* @param type |
|||
*/ |
|||
overPage(type){ |
|||
if (this.page + type === 0) { |
|||
this.page = 1; |
|||
} |
|||
else if(this.page + type >= this.numPages){ |
|||
this.page = this.numPages; |
|||
} |
|||
else{ |
|||
this.page = this.page + type; |
|||
} |
|||
}, |
|||
|
|||
zoomOriginalSize(){ |
|||
this.width = 0.5 |
|||
}, |
|||
|
|||
/** |
|||
* @description 放大页面30-100之间 |
|||
* @param type |
|||
*/ |
|||
zoomHandle(type){ |
|||
if(type === 1) { |
|||
if (helper.addFloatNumber(this.width, 0.1) < 0.3) { |
|||
this.width = 0.3; |
|||
} else if (helper.addFloatNumber(this.width, 0.1) >= 1) { |
|||
this.width = 0.98; |
|||
} else { |
|||
this.width = helper.addFloatNumber(this.width, 0.1); |
|||
} |
|||
}else{ |
|||
if (helper.cutFloatNumber(this.width, 0.1) < 0.3) { |
|||
this.width = 0.3; |
|||
} else if (helper.cutFloatNumber(this.width, 0.1) >= 1) { |
|||
this.width = 0.98; |
|||
} else { |
|||
this.width = helper.cutFloatNumber(this.width, 0.1); |
|||
} |
|||
} |
|||
}, |
|||
|
|||
password: function (updatePassword, reason) { |
|||
updatePassword(prompt('password is "test"')); |
|||
}, |
|||
error: function (err) { |
|||
console.log(err); |
|||
} |
|||
} |
|||
}; |
|||
</script> |
|||
<style type="text/css"> |
|||
@import "style.css"; |
|||
|
|||
.pdf-preview i.fileIconfont { |
|||
font-size: 30px; |
|||
font-weight: normal; |
|||
} |
|||
.pdf-preview { |
|||
position: fixed; |
|||
top: 0; |
|||
left: 0; |
|||
bottom: 0; |
|||
right: 0; |
|||
width: 100%; |
|||
height: 100%; |
|||
min-width: 1000px; |
|||
min-height: 300px; |
|||
background: rgba(0, 0, 0, .6); |
|||
z-index: 10000; |
|||
padding-top: 48px; |
|||
box-sizing: border-box; |
|||
} |
|||
.pdf-preview__title { |
|||
position: absolute; |
|||
background: #333; |
|||
top: 0; |
|||
right: 0; |
|||
left:0; |
|||
width: 100%; |
|||
height: 48px; |
|||
padding: 0 0 0 10px; |
|||
box-sizing: border-box; |
|||
color: #fff; |
|||
z-index: 10; |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
box-shadow: 0 0 20px rgba(0,0,0,0.5); |
|||
} |
|||
.pdf-preview__title-close { |
|||
cursor: pointer; |
|||
font-size: 18px; |
|||
height: 40px; |
|||
width: 40px; |
|||
line-height: 40px; |
|||
} |
|||
.pdf-preview__content { |
|||
height: -moz-calc(100% - 55px); |
|||
height: -webkit-calc(100% - 55px); |
|||
height: calc(100% - 55px); |
|||
height: 100%; |
|||
overflow-x: hidden; |
|||
overflow-y: auto; |
|||
position: relative; |
|||
z-index: 9; |
|||
margin: 0 auto; |
|||
} |
|||
|
|||
.pdf-preview__content .jv-container { |
|||
min-height: 100% !important; |
|||
} |
|||
|
|||
.img-preview__toolbar { |
|||
position: absolute; |
|||
font-size: 0; |
|||
left: 50%; |
|||
bottom: 30px; |
|||
text-align: center; |
|||
transform: translateX(-50%); |
|||
z-index: 10000 |
|||
} |
|||
.img-preview__toolbar span { |
|||
display: flex; |
|||
line-height: 24px; |
|||
border-radius: 8px; |
|||
padding: 8px 10px; |
|||
font-size: 0; |
|||
background: rgba(0, 0, 0, 0.5); |
|||
} |
|||
.img-preview__toolbar span * { |
|||
margin: 0 6px; |
|||
color: #fff; |
|||
font-size: 24px; |
|||
cursor: pointer; |
|||
font-weight: 400; |
|||
} |
|||
.pdf-preview__title-text { |
|||
display: flex; |
|||
justify-content: flex-start; |
|||
align-items: center; |
|||
} |
|||
|
|||
.pdf-preview__title-text img { |
|||
margin-right: 10px; |
|||
} |
|||
|
|||
.pdf-preview__title-text span { |
|||
padding: 0 20px 0 10px; |
|||
} |
|||
.pdf-preview__title-text .btn { |
|||
background: #4395ff; |
|||
font-size: 14px; |
|||
height: 30px; |
|||
max-height: 30px; |
|||
border-radius: 15px; |
|||
padding: 0 20px; |
|||
outline: none; |
|||
border: 1px solid #4395ff; |
|||
color: #fff; |
|||
box-shadow: 0 0 0 rgba(0,0,0,0); |
|||
transition: all .5s; |
|||
} |
|||
|
|||
.pdf-preview__title-text .btn:hover { |
|||
box-shadow: 0 0 10px rgba(0, 0, 0, .3); |
|||
opacity: 0.9; |
|||
background: #539dfc; |
|||
cursor: pointer; |
|||
} |
|||
|
|||
.pdf-preview__title-text .pdf-preview__input { |
|||
font-size: 14px; |
|||
height: 30px; |
|||
max-height: 30px; |
|||
border-radius: 15px; |
|||
background-color: #fff; |
|||
padding: 0 20px; |
|||
width: 50px; |
|||
text-align: center; |
|||
outline: none; |
|||
} |
|||
.img-preview__bottom { |
|||
position: absolute; |
|||
bottom: 0; |
|||
left: 0; |
|||
right: 0; |
|||
height: 5px; |
|||
background: #333; |
|||
z-index: 10; |
|||
box-shadow: 0 0 20px rgba(0, 0, 0, 0.5); |
|||
} |
|||
|
|||
|
|||
</style> |
@ -0,0 +1,55 @@ |
|||
<template> |
|||
<div class="xd-loading" v-if="show"> |
|||
<div class="xd-loading-box"> |
|||
<img :src="iconData.loadicon" /> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import {iconData} from './../contact' |
|||
export default { |
|||
name: "loading", |
|||
props: ['show'], |
|||
data(){ |
|||
return { |
|||
iconData |
|||
} |
|||
}, |
|||
created() { |
|||
console.log('loading',this.show); |
|||
}, |
|||
|
|||
watch:{ |
|||
show(){ |
|||
console.log('loading', this.show); |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style> |
|||
.xd-loading { |
|||
position: fixed; |
|||
top: 0; |
|||
left: 0; |
|||
right: 0; |
|||
bottom: 0; |
|||
background: rgba(0,0,0,.5); |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
z-index: 10000; |
|||
} |
|||
.xd-loading-box { |
|||
height: 120px; |
|||
width: 120px; |
|||
border-radius: 15px; |
|||
overflow: hidden; |
|||
} |
|||
|
|||
.xd-loading-box img { |
|||
height: 100%; |
|||
width: 100%; |
|||
} |
|||
</style> |
@ -0,0 +1,17 @@ |
|||
'use strict'; |
|||
|
|||
import jsonView from "./jsonView"; |
|||
import helper from "./helper"; |
|||
|
|||
/** |
|||
* @description PDF预览功能 |
|||
* @param options {object} |
|||
* @param options.fid 文件ID,唯一id(必填) |
|||
* @param options.name 文件名称 |
|||
* @param options.type 文件类型 |
|||
* @param options.url // PDF地址
|
|||
* @param $vue Vue |
|||
*/ |
|||
export default function (options, $vue) { |
|||
helper.createElement(options, $vue, jsonView); |
|||
} |
@ -0,0 +1,18 @@ |
|||
'use strict'; |
|||
|
|||
import officePreview from "./officeView"; |
|||
import helper from "./helper"; |
|||
|
|||
|
|||
/** |
|||
* @description Office预览功能 |
|||
* @param options {object} |
|||
* @param options.fid 文件ID,唯一id(必填) |
|||
* @param options.name 文件名称 |
|||
* @param options.type 文件类型 |
|||
* @param options.url // Office地址
|
|||
* @param $vue Vue |
|||
*/ |
|||
export default function (options, $vue) { |
|||
helper.createElement(options, $vue, officePreview); |
|||
} |
@ -0,0 +1,198 @@ |
|||
<template> |
|||
<div class="office-preview" :id="options.ele" v-if="info && options && options.ele"> |
|||
<div class="office-preview-title"> |
|||
<div class="office-preview-text"> |
|||
<img :src="options.icon" height="30" width="30"> |
|||
<span>{{info.name|getFileName(options['type'].toLocaleLowerCase())}}</span> |
|||
<button v-if="isDownLoad" class="btn" @click="download">下载</button> |
|||
</div> |
|||
<div class="office-preview-close" @click="handleCloseClick(options.ele)"><i class="fileIconfont iconwrong"></i></div> |
|||
</div> |
|||
<div class="office-preview-content"> |
|||
<div class="office-preview-content-box"> |
|||
<iframe v-if="src" :src="src" height="100%" width="100%" frameborder="0"></iframe> |
|||
</div> |
|||
</div> |
|||
<div class="change office change-prev" v-if="isBtn" @click="handeCilck('prev')"> |
|||
<i class="fileIconfont iconpageup"></i> |
|||
</div> |
|||
<div class="change office change-next" v-if="isBtn" @click="handeCilck('next')"> |
|||
<i class="fileIconfont iconpagedown"></i> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
<script> |
|||
window.pdfUrl = ""; |
|||
window.pdfLang = "zh-CN"; |
|||
import download from 'downloadjs'; |
|||
|
|||
export default { |
|||
name: "XdOfficePreview", |
|||
props: { |
|||
options:{ |
|||
type: Object|null, |
|||
default(){ |
|||
return null |
|||
}, |
|||
} |
|||
}, |
|||
created(){ |
|||
if(this.options) { |
|||
this.getUrl(this.options['source']) |
|||
if (this.options.download === false) this.isDownLoad = this.options.download; |
|||
} |
|||
|
|||
}, |
|||
filters: { |
|||
getFileName(name, type) { |
|||
if (name.indexOf(`.${type}`) === -1) { |
|||
return `${name}.${type}` |
|||
} |
|||
return name; |
|||
} |
|||
}, |
|||
watch: { |
|||
options(val) { |
|||
if (val) { |
|||
console.log('options',val) |
|||
this.getUrl(val['source']); |
|||
this.info = val; |
|||
if (val.download === false) this.isDownLoad = val.download; |
|||
} |
|||
} |
|||
}, |
|||
computed:{ |
|||
isBtn() { |
|||
let isBtn = false; |
|||
if (this.info && this.info.callback && typeof this.info.callback === 'function') isBtn = true; |
|||
return isBtn |
|||
} |
|||
}, |
|||
data() { |
|||
return { |
|||
otherPreviewUrl: 'https://view.officeapps.live.com/op/view.aspx?src=', |
|||
src: '', |
|||
info: null, |
|||
isDownLoad: true, |
|||
} |
|||
}, |
|||
methods: { |
|||
handeCilck(status) { |
|||
if (this.info && this.info.callback && typeof this.info.callback === 'function') { |
|||
this.handleCloseClick(this.info.ele); |
|||
this.info.callback(status) |
|||
} |
|||
}, |
|||
download() { |
|||
console.log(this.info) |
|||
download(this.info['response'], this.info['name']) |
|||
}, |
|||
|
|||
getUrl(val) { |
|||
this.src = `${this.otherPreviewUrl}${val}&lang=${window.pdfLang}&llcc=${window.pdfLang}`; |
|||
}, |
|||
handleCloseClick(el){ |
|||
this.close(el); |
|||
} |
|||
} |
|||
}; |
|||
</script> |
|||
<style> |
|||
@import "style.css"; |
|||
|
|||
.change.office > i.fileIconfont { |
|||
color: #999; |
|||
opacity: 0.7; |
|||
} |
|||
.office-preview { |
|||
position: fixed; |
|||
top: 0; |
|||
left: 0; |
|||
bottom: 0; |
|||
right: 0; |
|||
width: 100%; |
|||
height: 100%; |
|||
background: rgba(0, 0, 0, 0.5); |
|||
z-index: 10000; |
|||
} |
|||
|
|||
.office-preview-title { |
|||
position: absolute; |
|||
top:0; |
|||
left:0; |
|||
right:0; |
|||
height: 48px; |
|||
background: #333; |
|||
color: #fff; |
|||
z-index: 10; |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
padding: 0 5px; |
|||
box-sizing: border-box; |
|||
box-shadow: 0 0 20px rgba(0, 0, 0, 0.5); |
|||
} |
|||
|
|||
.office-preview-text { |
|||
display: flex; |
|||
justify-content: flex-start; |
|||
align-items: center; |
|||
} |
|||
|
|||
.office-preview-text img { |
|||
margin-right: 15px; |
|||
} |
|||
|
|||
.office-preview-text .btn { |
|||
background: #4395ff; |
|||
margin-left: 20px; |
|||
font-size: 14px; |
|||
height: 30px; |
|||
max-height: 30px; |
|||
border-radius: 15px; |
|||
padding: 0 20px; |
|||
outline: none; |
|||
border: 1px solid #4395ff; |
|||
color: #fff; |
|||
box-shadow: 0 0 0 rgba(0, 0, 0, 0); |
|||
transition: all .5s; |
|||
} |
|||
|
|||
.office-preview-text .btn:hover { |
|||
box-shadow: 0 0 10px rgba(0, 0, 0, .3); |
|||
opacity: 0.9; |
|||
background: #539dfc; |
|||
cursor: pointer; |
|||
} |
|||
|
|||
.office-preview-close { |
|||
cursor: pointer; |
|||
font-size: 30px; |
|||
height: 30px; |
|||
width: 30px; |
|||
line-height: 30px; |
|||
} |
|||
|
|||
|
|||
.office-preview-content { |
|||
height: -moz-calc(100% - 0); |
|||
height: -webkit-calc(100% - 0); |
|||
height: calc(100% - 0); |
|||
height: 100%; |
|||
overflow: hidden; |
|||
position: relative; |
|||
z-index: 9; |
|||
} |
|||
|
|||
.office-preview-content iframe { |
|||
background: rgba(0,0,0,.5); |
|||
height: 100%; |
|||
} |
|||
|
|||
.office-preview-content-box { |
|||
height: 100%; |
|||
} |
|||
|
|||
|
|||
|
|||
</style> |
@ -0,0 +1,17 @@ |
|||
'use strict'; |
|||
|
|||
import pdfPreview from "./pdfView"; |
|||
import helper from "./helper"; |
|||
|
|||
/** |
|||
* @description PDF预览功能 |
|||
* @param options {object} |
|||
* @param options.fid 文件ID,唯一id(必填) |
|||
* @param options.name 文件名称 |
|||
* @param options.type 文件类型 |
|||
* @param options.url // PDF地址
|
|||
* @param $vue Vue |
|||
*/ |
|||
export default function (options, $vue) { |
|||
helper.createElement(options, $vue, pdfPreview); |
|||
} |
@ -0,0 +1,305 @@ |
|||
<template> |
|||
<div class="pdf-preview" :id="options.ele" v-if="info"> |
|||
<div class="pdf-preview__title"> |
|||
<div class="pdf-preview__title-text"> |
|||
<img :src="options.icon" height="30" width="30"> |
|||
<input class="pdf-preview__input" v-model.number="page" type="number"> |
|||
<span>/ {{numPages}}</span> |
|||
<button class="btn" v-if="isDownLoad" @click="download">下载</button> |
|||
<span>{{info.name|getFileName(options['type'].toLocaleLowerCase())}}</span> |
|||
</div> |
|||
<div class="pdf-preview__title-close" @click="closeHandle(options.ele)"><i class="fileIconfont iconwrong"></i></div> |
|||
</div> |
|||
<div class="pdf-preview__content" :style="`width: ${getWdith}`"> |
|||
<xd-pdf |
|||
:file-url="info['response']" |
|||
@num-pages="setTotalNumPages" |
|||
:current-pages="page" |
|||
></xd-pdf> |
|||
</div> |
|||
<div class="img-preview__toolbar"> |
|||
<span> |
|||
<i class="fileIconfont iconfangda" @click="zoomHandle(1)"></i> |
|||
<i class="fileIconfont iconsuoxiao" @click="zoomHandle(-1)"></i> |
|||
<i class="fileIconfont iconpageup" @click="overPage(-1)"></i> |
|||
<i class="fileIconfont iconpagedown" @click="overPage(1)"></i> |
|||
<i class="fileIconfont iconhuanyuan" @click="zoomOriginalSize()"></i> |
|||
</span> |
|||
</div> |
|||
<div class="img-preview__bottom"></div> |
|||
<div class="change change-prev" v-if="isBtn" @click="handeCilck('prev')"><i class="fileIconfont iconpageup"></i></div> |
|||
<div class="change change-next" v-if="isBtn" @click="handeCilck('next')"><i class="fileIconfont iconpagedown"></i></div> |
|||
</div> |
|||
</template> |
|||
<script> |
|||
import helper from "./helper"; |
|||
import download from 'downloadjs'; |
|||
import XdPdf from "../XdPdf"; |
|||
|
|||
export default { |
|||
name: "xdPdfPreview", |
|||
props: { |
|||
options: { |
|||
type: Object|null, |
|||
default(){ |
|||
return null |
|||
} |
|||
}, |
|||
}, |
|||
components: {XdPdf}, |
|||
data() { |
|||
return { |
|||
src: '', |
|||
loadedRatio: 0, |
|||
page: 1, |
|||
numPages: 0, |
|||
rotate: 0, |
|||
width: 0.5, |
|||
info: null, |
|||
isDownLoad: true |
|||
} |
|||
}, |
|||
filters:{ |
|||
getFileName(name, type){ |
|||
if(name.indexOf(`.${type}`) === -1) { |
|||
return `${name}.${type}` |
|||
} |
|||
return name; |
|||
} |
|||
}, |
|||
watch:{ |
|||
options(val){ |
|||
this.info = val; |
|||
if (val.download === false) this.isDownLoad = val.download; |
|||
if(this.info['url']) { |
|||
this.src= this.info['url'] |
|||
} |
|||
}, |
|||
}, |
|||
created(){ |
|||
this.info = this.options; |
|||
if (this.options && this.options.download === false) this.isDownLoad = this.options.download; |
|||
}, |
|||
computed:{ |
|||
getWdith() { |
|||
return (this.width * 100) + '%'; |
|||
}, |
|||
isBtn() { |
|||
let isBtn = false; |
|||
if (this.info && this.info.callback && typeof this.info.callback === 'function') isBtn = true; |
|||
return isBtn |
|||
} |
|||
}, |
|||
methods: { |
|||
handeCilck(status) { |
|||
if (this.info && this.info.callback && typeof this.info.callback === 'function') { |
|||
this.closeHandle(this.info.ele); |
|||
this.info.callback(status) |
|||
} |
|||
}, |
|||
/** |
|||
* @description 设置总页数 |
|||
*/ |
|||
setTotalNumPages(num){ |
|||
this.numPages = num; |
|||
}, |
|||
closeHandle(id) { |
|||
this.close(id); |
|||
}, |
|||
|
|||
download(){ |
|||
download(this.info['response'], this.info['name']) |
|||
}, |
|||
|
|||
/** |
|||
* @description 翻页处理 |
|||
* @param type |
|||
*/ |
|||
overPage(type){ |
|||
if (this.page + type === 0) { |
|||
this.page = 1; |
|||
} |
|||
else if(this.page + type >= this.numPages){ |
|||
this.page = this.numPages; |
|||
} |
|||
else{ |
|||
this.page = this.page + type; |
|||
} |
|||
}, |
|||
|
|||
zoomOriginalSize(){ |
|||
this.width = 0.5 |
|||
}, |
|||
|
|||
/** |
|||
* @description 放大页面30-100之间 |
|||
* @param type |
|||
*/ |
|||
zoomHandle(type){ |
|||
if(type === 1) { |
|||
if (helper.addFloatNumber(this.width, 0.1) < 0.3) { |
|||
this.width = 0.3; |
|||
} else if (helper.addFloatNumber(this.width, 0.1) >= 1) { |
|||
this.width = 0.98; |
|||
} else { |
|||
this.width = helper.addFloatNumber(this.width, 0.1); |
|||
} |
|||
}else{ |
|||
if (helper.cutFloatNumber(this.width, 0.1) < 0.3) { |
|||
this.width = 0.3; |
|||
} else if (helper.cutFloatNumber(this.width, 0.1) >= 1) { |
|||
this.width = 0.98; |
|||
} else { |
|||
this.width = helper.cutFloatNumber(this.width, 0.1); |
|||
} |
|||
} |
|||
}, |
|||
|
|||
password: function (updatePassword, reason) { |
|||
updatePassword(prompt('password is "test"')); |
|||
}, |
|||
error: function (err) { |
|||
console.log(err); |
|||
} |
|||
} |
|||
}; |
|||
</script> |
|||
<style type="text/css"> |
|||
@import "style.css"; |
|||
|
|||
.pdf-preview i.fileIconfont { |
|||
font-size: 30px; |
|||
font-weight: normal; |
|||
} |
|||
.pdf-preview { |
|||
position: fixed; |
|||
top: 0; |
|||
left: 0; |
|||
bottom: 0; |
|||
right: 0; |
|||
width: 100%; |
|||
height: 100%; |
|||
min-width: 1000px; |
|||
min-height: 300px; |
|||
background: rgba(0, 0, 0, .6); |
|||
z-index: 10000; |
|||
padding-top: 48px; |
|||
box-sizing: border-box; |
|||
} |
|||
.pdf-preview__title { |
|||
position: absolute; |
|||
background: #333; |
|||
top: 0; |
|||
right: 0; |
|||
left:0; |
|||
width: 100%; |
|||
height: 48px; |
|||
padding: 0 0 0 10px; |
|||
box-sizing: border-box; |
|||
color: #fff; |
|||
z-index: 10; |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
box-shadow: 0 0 20px rgba(0,0,0,0.5); |
|||
} |
|||
.pdf-preview__title-close { |
|||
cursor: pointer; |
|||
font-size: 18px; |
|||
height: 40px; |
|||
width: 40px; |
|||
line-height: 40px; |
|||
} |
|||
.pdf-preview__content { |
|||
height: -moz-calc(100% - 55px); |
|||
height: -webkit-calc(100% - 55px); |
|||
height: calc(100% - 55px); |
|||
height: 100%; |
|||
overflow-x: hidden; |
|||
overflow-y: auto; |
|||
position: relative; |
|||
z-index: 9; |
|||
margin: 0 auto; |
|||
} |
|||
.img-preview__toolbar { |
|||
position: absolute; |
|||
font-size: 0; |
|||
left: 50%; |
|||
bottom: 30px; |
|||
text-align: center; |
|||
transform: translateX(-50%); |
|||
z-index: 10000 |
|||
} |
|||
.img-preview__toolbar span { |
|||
display: flex; |
|||
line-height: 24px; |
|||
border-radius: 8px; |
|||
padding: 8px 10px; |
|||
font-size: 0; |
|||
background: rgba(0, 0, 0, 0.5); |
|||
} |
|||
.img-preview__toolbar span * { |
|||
margin: 0 6px; |
|||
color: #fff; |
|||
font-size: 24px; |
|||
cursor: pointer; |
|||
font-weight: 400; |
|||
} |
|||
.pdf-preview__title-text { |
|||
display: flex; |
|||
justify-content: flex-start; |
|||
align-items: center; |
|||
} |
|||
|
|||
.pdf-preview__title-text img { |
|||
margin-right: 10px; |
|||
} |
|||
|
|||
.pdf-preview__title-text span { |
|||
padding: 0 20px 0 10px; |
|||
} |
|||
.pdf-preview__title-text .btn { |
|||
background: #4395ff; |
|||
font-size: 14px; |
|||
height: 30px; |
|||
max-height: 30px; |
|||
border-radius: 15px; |
|||
padding: 0 20px; |
|||
outline: none; |
|||
border: 1px solid #4395ff; |
|||
color: #fff; |
|||
box-shadow: 0 0 0 rgba(0,0,0,0); |
|||
transition: all .5s; |
|||
} |
|||
|
|||
.pdf-preview__title-text .btn:hover { |
|||
box-shadow: 0 0 10px rgba(0, 0, 0, .3); |
|||
opacity: 0.9; |
|||
background: #539dfc; |
|||
cursor: pointer; |
|||
} |
|||
|
|||
.pdf-preview__title-text .pdf-preview__input { |
|||
font-size: 14px; |
|||
height: 30px; |
|||
max-height: 30px; |
|||
border-radius: 15px; |
|||
background-color: #fff; |
|||
padding: 0 20px; |
|||
width: 50px; |
|||
text-align: center; |
|||
outline: none; |
|||
} |
|||
.img-preview__bottom { |
|||
position: absolute; |
|||
bottom: 0; |
|||
left: 0; |
|||
right: 0; |
|||
height: 5px; |
|||
background: #333; |
|||
z-index: 10; |
|||
box-shadow: 0 0 20px rgba(0, 0, 0, 0.5); |
|||
} |
|||
|
|||
|
|||
</style> |
@ -0,0 +1,88 @@ |
|||
@font-face { |
|||
font-family: "fileIconfont"; |
|||
src: url('//at.alicdn.com/t/font_2306061_i5jhgzel2u.eot?t=1610246045536'); /* IE9 */ |
|||
src: url('//at.alicdn.com/t/font_2306061_i5jhgzel2u.eot?t=1610246045536#iefix') format('embedded-opentype'), /* IE6-IE8 */ url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAhIAAsAAAAAENgAAAf7AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCEQgqSWI8lATYCJAM0CxwABCAFhG0HgSYbPw5RlE9SmuwLbBv2ZIMWZhwbxgArIACOAgkkAADgA5khERlKSfA19tt3d98E0ySaGLpPJ9FoDEkrlUYiFDwVUiF7qPa/c5kdkBqwyvPHCtSIFPpc8pOmr81PAdXQOSCjJ+Qm3IanU/9d3qveJe1lQRWPSAb5UDHdN3O3OdkcFR6CCQhmpCPL/LwGCP7ar1X10EzbhcKQiUw/Svt7/+z9XWRxsUaIns8Na9CkNJluuQLNLY/ho6/JIgvbrBOonuG2EUx+OdcEmmZ1LewdXVyTlsLiAkNOtGKklctXWsJDPbtaY7IMx3xR6uk6HcdN+PXxbT1iSSqZdaf940NBdt7Wfmf+n5eV7wjqSvGQR8YaojyynmvLb8EY1kLcrBuNXCAGLRr2pbcR26YUlHp5//7/QjnTlgmYyyoNg3bsqnXbzhA1dQ1J1tLUVl08VMx/XpWB21jxmCt4W3Op2jfZAlUH2QbVAJmASiBTUBkEQLVAJKgmiAKrmiCoKkgKKkBekELh/Zu9OOV0fBOTiFUkvZJ/WFlHIc52a11RdQWpvCLEf0pURLw42pGP9FCKxJqO4tj4aKkVTmExp0RJalIir9au3T+BAB0MMuEwFwqx2Q7eY1WytN3qExI51in4bQqGc9m8vJxm8kN32fA9LniH4QNa+bfINU7iWI6h2wKyaDsKSQL/gKGgZJ1YbLUDgD0PpF/EO0ipzUVAwZnD4AIJyPcmRdgqpzGN4ox0xF8UQTKORDItHPlzz+7LXA28LbF19/Y9nPIWt36t2nR32JiWgJYOQZe0HOetcnmTzm/5hyvIOAK0PcQ6w4WuLWrkWG76276is5TALJ2RZsrB/1DO9SrpN4Tgs3rkANs9vJckbX4R2KgIn5LATvAX/Lz5er02fyJBuvyCD2OrBxKbF+FVANIBHjzR92tM9bmu0g1n1NEVp03UxrP/UEuTo93NpTHlhXZ+kqUlLmF0JSKH7U1Tmp1WO6/I3tCSwO2/A3SEsr1Cd/9iz4UDwhZH28JjGYfNL/y91WjD0bYz5P8gHiVIqjbrI66B59YXlG7ZlkqQnPifJZYTRNGZqCzB1rnm/1rUvQCAtRDMd2yJq2pjBmlbtXLhGLAygigexgFlsd0DgNm5vkJRjK3LVzQnq5Hk3qxzvadSwcx8Oueq9m2U06GbYxzNuap86+WnA/hastPsncm5Nngr5KcTXaCBVf5NCiZ8a1sobT26gdX+DYozQfIkywgEdLDfDvTxp1S6wwgzUxs2Dp+VbEhxz5w1a6Y72ZhcOmvGn1EKSmk8AnyxnI/S6aJGesE9zqMLUTotukpGbVkwf8vo6CmL18BIBKrn2sijtWgNwg64Fq6JRPRDly3zevr3f/TwwQPujFyI0vYqXLwWPooIIaReM2LA0P797z94+HAe5/EAuzzUOtTK19oRx+zaxcTtxj7c7xvsjwOtS7EiB7wrV4H9L/V//PHnLofT/zXCzztj9Obeh2ObPkZpecA+ZDvmK9lHp8y9DXmhPMP2PKVfTlGTF45sKGn0lOq8ZOHkZ9KFC+U2uf+zBXtHDP9rCn9qEMNCSlgjsaGwqaP9Qqme7L90BFkX+HRYkK6JGjY4hRsXPZH7LzC8iXqifJnuuf4YVA3sVdMZio1Od9GxE+7S08QJ42lQbKz4u07d1aZHwc99eYrRD04wm5/Seobilce/LhwuWdGsZvZAEy6tMdWU4tDe7ov+NM2PM8XNHz06Doy8XyJ/LC/JLjSbu8wzMi+0uTqIUlNREAVSVcGoQJQqFQVQUKWSTNy6BwEC7oZ7CLAbNgOA9qDdgAC9nvarrLw2aCnIQYdJ8lClyAjSQzDYMH6BcUdNjVczSNPt2RPemze9Coc3bpZ5b9xIv+ObNzqeHP7UqDVRwymT1ihpvGChBmqNCRaLRGb7IVMTZBHU6u4ta98Qb1Qb490SiVc1SF0KdudRDR0T+xuU0CknvssHry7JeHjELevUUVbFCpa/V103aiPpjpOfRvmAAR3MZwHd92we2TOSv0LRUMVfanxJqG5QVBZEOg/X7FC+2O8C0ulQ0fVnsOXr7eOGjbgadXxcw/Ky/sxq+PAhlHS1GW5HrejGYXBrk4p0fbUjrEZ0s6/lLQDAlyODfiE/n4C8Mz4hyH75+z9YJPrIFwsCda2zfMyX4Bdcgv+3r3QWThB1m4xEOvkC5HVKVeDvPZKzuQm9XsW2/nk2XdbNrAwRjbPQWU2iQgTAt1Bf5JCS6s/l6kdsFUjQ11wuos1bx/Es/8ufgnIJcGu7WATDQNPega5YPeiPkZFJsD7Uc8JHbFIzA7nOew4KvNdiK1o2oArvzdimVcfmW4aEqqI0sOIZsaHvPTbpeoEM7x8o8P6NrRj1L60SHDC26SBWbGxZiK86+yGwGASdF1RzNDJFcScaegkq8VjIxKamWwgjjYaO+sO/rmMwEKrQE6VqHMeSyhB9enTTAZ6H1IboAo/7Dp12NhjIl94+R5907AoBJvYTC9RcwatxyJBnxzqlz78ElISHCVvm/Oa9BUIRfXlqpG9IcD/GhjTnVEZHUspYzEol6k4OIR91xEqBZ7cjytYrcwEu1ucItFozA7aWpOL+8Fn+OcdO37zWO3UiRY4SlahGLerRiGa0oh2d6OpdikTzBLMkcnSuTcsyBQIz04hkJraZgXE1M434oKCk5SRA4bpYz0I0qhklmGuGDcmMEqzJ+oxaf2FSkupbZYJRHiE=') format('woff2'), |
|||
url('//at.alicdn.com/t/font_2306061_i5jhgzel2u.woff?t=1610246045536') format('woff'), |
|||
url('//at.alicdn.com/t/font_2306061_i5jhgzel2u.ttf?t=1610246045536') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */ url('//at.alicdn.com/t/font_2306061_i5jhgzel2u.svg?t=1610246045536#iconfont') format('svg'); /* iOS 4.1- */ |
|||
} |
|||
|
|||
.fileIconfont { |
|||
font-family: "fileIconfont" !important; |
|||
font-size: 16px; |
|||
font-style: normal; |
|||
-webkit-font-smoothing: antialiased; |
|||
-moz-osx-font-smoothing: grayscale; |
|||
} |
|||
|
|||
.iconyduicuowushixin:before { |
|||
content: "\e676"; |
|||
} |
|||
|
|||
.iconpagedown:before { |
|||
content: "\e638"; |
|||
} |
|||
|
|||
.iconpageup:before { |
|||
content: "\e639"; |
|||
} |
|||
|
|||
.iconwenjian:before { |
|||
content: "\e6ac"; |
|||
} |
|||
|
|||
.icontupian:before { |
|||
content: "\e7b3"; |
|||
} |
|||
|
|||
.iconhuanyuan:before { |
|||
content: "\e66f"; |
|||
} |
|||
|
|||
.iconwrong:before { |
|||
content: "\e615"; |
|||
} |
|||
|
|||
.iconsuoxiao:before { |
|||
content: "\e619"; |
|||
} |
|||
|
|||
.iconfangda:before { |
|||
content: "\e61a"; |
|||
} |
|||
|
|||
.iconfangda1:before { |
|||
content: "\e666"; |
|||
} |
|||
|
|||
.iconyouzhuan:before { |
|||
content: "\e665"; |
|||
} |
|||
|
|||
.iconzuozhuan:before { |
|||
content: "\e667"; |
|||
} |
|||
|
|||
.change { |
|||
width: 30px; |
|||
height: 30px; |
|||
position: absolute; |
|||
top: 50%; |
|||
margin-top: -15px; |
|||
z-index: 100000; |
|||
} |
|||
|
|||
.change > i.fileIconfont { |
|||
color: #fff; |
|||
font-size: 40px!important; |
|||
opacity: .8; |
|||
cursor: pointer; |
|||
} |
|||
|
|||
.change.change-prev { |
|||
left: 20px; |
|||
} |
|||
|
|||
.change.change-next { |
|||
right: 20px; |
|||
} |
|||
|
@ -0,0 +1,17 @@ |
|||
'use strict'; |
|||
|
|||
import textView from "./textView"; |
|||
import helper from "./helper"; |
|||
|
|||
/** |
|||
* @description PDF预览功能 |
|||
* @param options {object} |
|||
* @param options.fid 文件ID,唯一id(必填) |
|||
* @param options.name 文件名称 |
|||
* @param options.type 文件类型 |
|||
* @param options.url // PDF地址
|
|||
* @param $vue Vue |
|||
*/ |
|||
export default function (options, $vue) { |
|||
helper.createElement(options, $vue, textView); |
|||
} |
@ -0,0 +1,397 @@ |
|||
<template> |
|||
<div class="pdf-preview" :id="options.ele" v-if="info"> |
|||
<div class="pdf-preview__title"> |
|||
<div class="pdf-preview__title-text"> |
|||
<img :src="options.icon" height="30" width="30"> |
|||
<input class="pdf-preview__input" v-model.number="page" type="number"> |
|||
<span>/ {{numPages}}</span> |
|||
<button class="btn" v-if="isDownLoad" @click="download">下载</button> |
|||
<span>{{info.name|getFileName(options['type'].toLocaleLowerCase())}}</span> |
|||
</div> |
|||
<div class="pdf-preview__title-close" @click="closeHandle(options.ele)"><i class="fileIconfont iconwrong"></i></div> |
|||
</div> |
|||
<div class="pdf-preview__content" :style="`width: ${getWdith}`"> |
|||
<pre v-highlightjs="info.url"><code :class="getCss(info.type)"></code></pre> |
|||
</div> |
|||
<div class="img-preview__bottom"></div> |
|||
<div class="change change-prev" v-if="isBtn" @click="handeCilck('prev')"><i class="fileIconfont iconpageup"></i></div> |
|||
<div class="change change-next" v-if="isBtn" @click="handeCilck('next')"><i class="fileIconfont iconpagedown"></i></div> |
|||
</div> |
|||
</template> |
|||
<script> |
|||
import helper from "./helper"; |
|||
import download from 'downloadjs'; |
|||
|
|||
export default { |
|||
name: "xdPdfPreview", |
|||
components:{ |
|||
}, |
|||
props: { |
|||
options: { |
|||
type: Object|null, |
|||
default(){ |
|||
return null |
|||
} |
|||
}, |
|||
}, |
|||
data() { |
|||
return { |
|||
src: '', |
|||
loadedRatio: 0, |
|||
page: 1, |
|||
numPages: 0, |
|||
rotate: 0, |
|||
width: 0.5, |
|||
info: null, |
|||
isDownLoad: true, |
|||
} |
|||
}, |
|||
filters:{ |
|||
getFileName(name, type){ |
|||
if(name.indexOf(`.${type}`) === -1) { |
|||
return `${name}.${type}` |
|||
} |
|||
return name; |
|||
} |
|||
}, |
|||
watch:{ |
|||
options(val){ |
|||
this.info = val; |
|||
if (val.download === false) this.isDownLoad = val.download; |
|||
if(this.info['url']) { |
|||
this.src= this.info['url'] |
|||
} |
|||
}, |
|||
}, |
|||
created(){ |
|||
this.info = this.options; |
|||
if (this.options && this.options.download === false) this.isDownLoad = this.options.download; |
|||
}, |
|||
computed:{ |
|||
getWdith() { |
|||
return (this.width * 100) + '%'; |
|||
}, |
|||
|
|||
isBtn(){ |
|||
let isBtn = false; |
|||
if(this.info && this.info.callback && typeof this.info.callback === 'function') isBtn = true; |
|||
return isBtn |
|||
} |
|||
}, |
|||
methods: { |
|||
handeCilck(status){ |
|||
if (this.info && this.info.callback && typeof this.info.callback === 'function'){ |
|||
this.closeHandle(this.info.ele); |
|||
this.info.callback(status) |
|||
} |
|||
}, |
|||
|
|||
getCss(type){ |
|||
return type.toLocaleLowerCase() |
|||
}, |
|||
/** |
|||
* @description 设置总页数 |
|||
*/ |
|||
setTotalNumPages(num){ |
|||
this.numPages = num; |
|||
}, |
|||
closeHandle(id) { |
|||
this.close(id); |
|||
}, |
|||
|
|||
download(){ |
|||
download(this.info['response'], this.info['name']) |
|||
}, |
|||
|
|||
/** |
|||
* @description 翻页处理 |
|||
* @param type |
|||
*/ |
|||
overPage(type){ |
|||
if (this.page + type === 0) { |
|||
this.page = 1; |
|||
} |
|||
else if(this.page + type >= this.numPages){ |
|||
this.page = this.numPages; |
|||
} |
|||
else{ |
|||
this.page = this.page + type; |
|||
} |
|||
}, |
|||
|
|||
zoomOriginalSize(){ |
|||
this.width = 0.5 |
|||
}, |
|||
|
|||
/** |
|||
* @description 放大页面30-100之间 |
|||
* @param type |
|||
*/ |
|||
zoomHandle(type){ |
|||
if(type === 1) { |
|||
if (helper.addFloatNumber(this.width, 0.1) < 0.3) { |
|||
this.width = 0.3; |
|||
} else if (helper.addFloatNumber(this.width, 0.1) >= 1) { |
|||
this.width = 0.98; |
|||
} else { |
|||
this.width = helper.addFloatNumber(this.width, 0.1); |
|||
} |
|||
}else{ |
|||
if (helper.cutFloatNumber(this.width, 0.1) < 0.3) { |
|||
this.width = 0.3; |
|||
} else if (helper.cutFloatNumber(this.width, 0.1) >= 1) { |
|||
this.width = 0.98; |
|||
} else { |
|||
this.width = helper.cutFloatNumber(this.width, 0.1); |
|||
} |
|||
} |
|||
}, |
|||
|
|||
password: function (updatePassword, reason) { |
|||
updatePassword(prompt('password is "test"')); |
|||
}, |
|||
|
|||
error: function (err) { |
|||
console.log(err); |
|||
} |
|||
} |
|||
}; |
|||
</script> |
|||
<style type="text/css"> |
|||
@import "style.css"; |
|||
|
|||
.pdf-preview i.fileIconfont { |
|||
font-size: 30px; |
|||
font-weight: normal; |
|||
} |
|||
.pdf-preview { |
|||
position: fixed; |
|||
top: 0; |
|||
left: 0; |
|||
bottom: 0; |
|||
right: 0; |
|||
width: 100%; |
|||
height: 100%; |
|||
min-width: 1000px; |
|||
min-height: 300px; |
|||
background: rgba(0, 0, 0, .6); |
|||
z-index: 10000; |
|||
padding-top: 48px; |
|||
box-sizing: border-box; |
|||
} |
|||
.pdf-preview__title { |
|||
position: absolute; |
|||
background: #333; |
|||
top: 0; |
|||
right: 0; |
|||
left:0; |
|||
width: 100%; |
|||
height: 48px; |
|||
padding: 0 0 0 10px; |
|||
box-sizing: border-box; |
|||
color: #fff; |
|||
z-index: 10; |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
box-shadow: 0 0 20px rgba(0,0,0,0.5); |
|||
} |
|||
.pdf-preview__title-close { |
|||
cursor: pointer; |
|||
font-size: 18px; |
|||
height: 40px; |
|||
width: 40px; |
|||
line-height: 40px; |
|||
} |
|||
.pdf-preview__content { |
|||
height: -moz-calc(100% - 55px); |
|||
height: -webkit-calc(100% - 55px); |
|||
height: calc(100% - 55px); |
|||
height: 100%; |
|||
overflow-x: hidden; |
|||
overflow-y: auto; |
|||
position: relative; |
|||
z-index: 9; |
|||
margin: 0 auto; |
|||
background: #fff; |
|||
padding: 10px; |
|||
box-sizing: border-box; |
|||
} |
|||
|
|||
.pdf-preview__content pre { |
|||
font-size: 14px; |
|||
margin: 0; |
|||
height: 100%; |
|||
} |
|||
|
|||
.pdf-preview__content code { |
|||
min-height: 100% !important; |
|||
word-break: break-all; |
|||
word-wrap: break-word; |
|||
white-space: pre-wrap; |
|||
box-sizing: border-box; |
|||
border-radius: 6px; |
|||
font-size: 14px!important; |
|||
padding: 20px; |
|||
} |
|||
|
|||
|
|||
.img-preview__toolbar { |
|||
position: absolute; |
|||
font-size: 0; |
|||
left: 50%; |
|||
bottom: 30px; |
|||
text-align: center; |
|||
transform: translateX(-50%); |
|||
z-index: 10000 |
|||
} |
|||
.img-preview__toolbar span { |
|||
display: flex; |
|||
line-height: 24px; |
|||
border-radius: 8px; |
|||
padding: 8px 10px; |
|||
font-size: 0; |
|||
background: rgba(0, 0, 0, 0.5); |
|||
} |
|||
.img-preview__toolbar span * { |
|||
margin: 0 6px; |
|||
color: #fff; |
|||
font-size: 24px; |
|||
cursor: pointer; |
|||
font-weight: 400; |
|||
} |
|||
.pdf-preview__title-text { |
|||
display: flex; |
|||
justify-content: flex-start; |
|||
align-items: center; |
|||
} |
|||
|
|||
.pdf-preview__title-text img { |
|||
margin-right: 10px; |
|||
} |
|||
|
|||
.pdf-preview__title-text span { |
|||
padding: 0 20px 0 10px; |
|||
} |
|||
.pdf-preview__title-text .btn { |
|||
background: #4395ff; |
|||
font-size: 14px; |
|||
height: 30px; |
|||
max-height: 30px; |
|||
border-radius: 15px; |
|||
padding: 0 20px; |
|||
outline: none; |
|||
border: 1px solid #4395ff; |
|||
color: #fff; |
|||
box-shadow: 0 0 0 rgba(0,0,0,0); |
|||
transition: all .5s; |
|||
} |
|||
|
|||
.pdf-preview__title-text .btn:hover { |
|||
box-shadow: 0 0 10px rgba(0, 0, 0, .3); |
|||
opacity: 0.9; |
|||
background: #539dfc; |
|||
cursor: pointer; |
|||
} |
|||
|
|||
.pdf-preview__title-text .pdf-preview__input { |
|||
font-size: 14px; |
|||
height: 30px; |
|||
max-height: 30px; |
|||
border-radius: 15px; |
|||
background-color: #fff; |
|||
padding: 0 20px; |
|||
width: 50px; |
|||
text-align: center; |
|||
outline: none; |
|||
} |
|||
.img-preview__bottom { |
|||
position: absolute; |
|||
bottom: 0; |
|||
left: 0; |
|||
right: 0; |
|||
height: 5px; |
|||
background: #333; |
|||
z-index: 10; |
|||
box-shadow: 0 0 20px rgba(0, 0, 0, 0.5); |
|||
} |
|||
|
|||
.hljs { |
|||
display: block; |
|||
overflow-x: auto; |
|||
padding: 0.5em; |
|||
color: #abb2bf; |
|||
background: #282c34; |
|||
} |
|||
|
|||
.hljs-comment, |
|||
.hljs-quote { |
|||
color: #5c6370; |
|||
font-style: italic; |
|||
} |
|||
|
|||
.hljs-doctag, |
|||
.hljs-keyword, |
|||
.hljs-formula { |
|||
color: #c678dd; |
|||
} |
|||
|
|||
.hljs-section, |
|||
.hljs-name, |
|||
.hljs-selector-tag, |
|||
.hljs-deletion, |
|||
.hljs-subst { |
|||
color: #e06c75; |
|||
} |
|||
|
|||
.hljs-literal { |
|||
color: #56b6c2; |
|||
} |
|||
|
|||
.hljs-string, |
|||
.hljs-regexp, |
|||
.hljs-addition, |
|||
.hljs-attribute, |
|||
.hljs-meta-string { |
|||
color: #98c379; |
|||
} |
|||
|
|||
.hljs-built_in, |
|||
.hljs-class .hljs-title { |
|||
color: #e6c07b; |
|||
} |
|||
|
|||
.hljs-attr, |
|||
.hljs-variable, |
|||
.hljs-template-variable, |
|||
.hljs-type, |
|||
.hljs-selector-class, |
|||
.hljs-selector-attr, |
|||
.hljs-selector-pseudo, |
|||
.hljs-number { |
|||
color: #d19a66; |
|||
} |
|||
|
|||
.hljs-symbol, |
|||
.hljs-bullet, |
|||
.hljs-link, |
|||
.hljs-meta, |
|||
.hljs-selector-id, |
|||
.hljs-title { |
|||
color: #61aeee; |
|||
} |
|||
|
|||
.hljs-emphasis { |
|||
font-style: italic; |
|||
} |
|||
|
|||
.hljs-strong { |
|||
font-weight: bold; |
|||
} |
|||
|
|||
.hljs-link { |
|||
text-decoration: underline; |
|||
} |
|||
|
|||
|
|||
</style> |
@ -0,0 +1,5 @@ |
|||
import watermark from './waterMark' |
|||
|
|||
export default function installDirective(app) { |
|||
app.directive(watermark.name, watermark.directives); |
|||
} |
@ -0,0 +1,56 @@ |
|||
// 全局保存 canvas 和 div ,避免重复创建(单例模式)
|
|||
const globalCanvas = null; |
|||
const globalWaterMark = null; |
|||
|
|||
// 获取 toDataURL 的结果
|
|||
const getDataUrl = ({ |
|||
font = "16px normal", |
|||
fillStyle = "rgba(180, 180, 180, 0.3)", |
|||
textAlign, |
|||
textBaseline, |
|||
text = "test1233", |
|||
}) => { |
|||
const rotate = -20; |
|||
const canvas = globalCanvas || document.createElement("canvas"); |
|||
const ctx = canvas.getContext("2d"); // 获取画布上下文
|
|||
|
|||
ctx.rotate((rotate * Math.PI) / 180); |
|||
ctx.font = font; |
|||
ctx.fillStyle = fillStyle; |
|||
ctx.textAlign = textAlign || "left"; |
|||
ctx.textBaseline = textBaseline || "middle"; |
|||
ctx.fillText(text, canvas.width / 3, canvas.height / 2); |
|||
|
|||
return canvas.toDataURL("image/png"); |
|||
}; |
|||
|
|||
// 设置水印
|
|||
const setWaterMark = (el, binding) => { |
|||
const { parentElement } = el; |
|||
|
|||
// 获取对应的 canvas 画布相关的 base64 url
|
|||
console.log(111111); |
|||
const url = getDataUrl(binding); |
|||
|
|||
// 创建 waterMark 父元素
|
|||
const waterMark = globalWaterMark || document.createElement("div"); |
|||
waterMark.className = `water-mark`; // 方便自定义展示结果
|
|||
waterMark.setAttribute("style", `background-image: url(${url});`); |
|||
|
|||
// 将对应图片的父容器作为定位元素
|
|||
parentElement.setAttribute("style", "position: relative;"); |
|||
|
|||
// 将图片元素移动到 waterMark 中
|
|||
parentElement.appendChild(waterMark); |
|||
}; |
|||
|
|||
const directives = { |
|||
bind(el, binding) { |
|||
el.onload = setWaterMark.bind(null, el, binding.value); |
|||
}, |
|||
}; |
|||
|
|||
export default { |
|||
name: "watermark", |
|||
directives, |
|||
}; |
@ -0,0 +1,31 @@ |
|||
'use strict'; |
|||
|
|||
import {preview} from "./components/preview"; |
|||
import helper from "./components/preview/helper"; |
|||
import XdFileListPreview from "@/components/XdFileListPreview"; |
|||
import VueHighlightJS from 'vue-highlightjs' |
|||
|
|||
// 定义 install 方法
|
|||
const install = function (Vue, options) { |
|||
if (install.installed) return; |
|||
install.installed = true; |
|||
Vue.use(VueHighlightJS); |
|||
Vue.prototype.$xdOptions = options; |
|||
Vue.prototype.$preview = (options, callback=null)=>{ |
|||
options['callback'] = callback; |
|||
preview(options, Vue); |
|||
}; |
|||
Vue.prototype.$fileHelper = helper; |
|||
console.log('Vue.use()=> options', options); |
|||
|
|||
Vue.component(XdFileListPreview.name, XdFileListPreview) |
|||
}; |
|||
|
|||
if (typeof window !== 'undefined' && window['Vue']) { |
|||
install(window['Vue']) |
|||
} |
|||
|
|||
export default { |
|||
install, |
|||
XdFileListPreview |
|||
} |
@ -0,0 +1,18 @@ |
|||
'use strict'; |
|||
|
|||
import Vue from 'vue' |
|||
import App from './App.vue' |
|||
|
|||
import install from "@/install"; |
|||
import directives from './directives' |
|||
Vue.use(install,{ |
|||
pdf: 'https://cdn.jsdelivr.net/npm/pdfjs-dist@2.0.288/build/pdf.min.js', |
|||
worker:'https://cdn.jsdelivr.net/npm/pdfjs-dist@2.0.288/build/pdf.worker.min.js', |
|||
}); |
|||
Vue.use(directives) |
|||
|
|||
Vue.config.productionTip = false; |
|||
|
|||
new Vue({ |
|||
render: h => h(App), |
|||
}).$mount('#app'); |
@ -0,0 +1,89 @@ |
|||
'use strict'; |
|||
|
|||
const path = require('path'); |
|||
const defaultSettings = require('./settings.js'); |
|||
const devServer = require('./devServer'); //devServer相关配置
|
|||
const UglifyJsPlugin = require('uglifyjs-webpack-plugin'); |
|||
|
|||
/**自动加载关系**/ |
|||
const CreatedComponentsPlugin = require('./build/plugins/CreatedComponentsPlugin'); |
|||
|
|||
|
|||
function resolve(dir) { |
|||
return path.join(__dirname, dir) |
|||
} |
|||
|
|||
/*** |
|||
* @description 根据环境入口使用的插件 |
|||
* @type {CreatedComponentsPlugin[]} |
|||
*/ |
|||
let plugins = []; |
|||
//console.log(process.env.npm_lifecycle_script.indexOf('gxdVue'), process.env);
|
|||
if(process.env.npm_lifecycle_script.indexOf('gxdVue') !== -1) { |
|||
plugins.push(new UglifyJsPlugin({ |
|||
uglifyOptions: { |
|||
compress: { |
|||
warnings: false, |
|||
drop_debugger: true, //去掉debugger
|
|||
drop_console: true, // 去掉console
|
|||
pure_funcs: ['console.log']// 移除console
|
|||
} |
|||
}, |
|||
sourceMap: false, |
|||
parallel: true |
|||
})); |
|||
} |
|||
|
|||
|
|||
const name = defaultSettings.title || 'XD Vue Package'; // page title
|
|||
|
|||
|
|||
// All configuration item explanations can be find in https://cli.vuejs.org/config/
|
|||
module.exports = { |
|||
/** |
|||
* You will need to set publicPath if you plan to deploy your site under a sub path, |
|||
* for example GitHub Pages. If you plan to deploy your site to https://foo.github.io/bar/,
|
|||
* then publicPath should be set to "/bar/". |
|||
* In most cases please use '/' !!! |
|||
* Detail: https://cli.vuejs.org/config/#publicpath
|
|||
*/ |
|||
publicPath: '/', |
|||
outputDir: 'dist', |
|||
assetsDir: 'static', |
|||
/**是否关闭eslint语法检测**/ |
|||
lintOnSave: defaultSettings.isCloseEslint, |
|||
productionSourceMap: false, |
|||
|
|||
devServer, |
|||
css: { |
|||
extract: false //设置不产生css样式模式
|
|||
}, |
|||
|
|||
configureWebpack: { |
|||
// provide the app's title in webpack's name field, so that
|
|||
// it can be accessed in index.html to inject the correct title.
|
|||
name: name, |
|||
//关闭性能提示
|
|||
performance: { |
|||
hints: false, |
|||
//入口起点的最大体积
|
|||
maxEntrypointSize: 50000000, |
|||
//生成文件的最大体积
|
|||
maxAssetSize: 30000000, |
|||
//只给出 js 文件的性能提示
|
|||
assetFilter: function (assetFilename) { |
|||
return assetFilename.endsWith('.js'); |
|||
} |
|||
}, |
|||
resolve: { |
|||
alias: { |
|||
'@': resolve('src'), |
|||
} |
|||
}, |
|||
plugins |
|||
}, |
|||
|
|||
chainWebpack: (config) => { |
|||
|
|||
} |
|||
}; |
Write
Preview
Loading…
Cancel
Save
Reference in new issue