5.0版本 发布 新增 cadviewer转换方法
47
README.cn.md
@@ -9,18 +9,18 @@
|
|||||||
7. 支持 pdf ,ofd, rtf 等文档
|
7. 支持 pdf ,ofd, rtf 等文档
|
||||||
8. 支持 xmind 软件模型文件
|
8. 支持 xmind 软件模型文件
|
||||||
9. 支持 bpmn 工作流文件
|
9. 支持 bpmn 工作流文件
|
||||||
10. 支持 eml 邮件文件
|
10. 支持 eml, msg 邮件文件
|
||||||
11. 支持 epub 图书文档
|
11. 支持 epub 图书文档
|
||||||
12. 支持 obj, 3ds, stl, ply, gltf, glb, off, 3dm, fbx, dae, wrl, 3mf, ifc, brep, step, iges, fcstd, bim 等 3D 模型文件
|
12. 支持 obj, 3ds, stl, ply, gltf, glb, off, 3dm, fbx, dae, wrl, 3mf, ifc, brep, step, iges, fcstd, bim 等 3D 模型文件
|
||||||
13. 支持 dwg, dxf, dwf, iges , igs, dwt, dng, ifc, dwfx, stl, cf2, plt 等 CAD 模型文件
|
13. 支持 dwg, dxf, dwf, iges , igs, dwt, dng, ifc, dwfx, stl, cf2, plt 等 CAD 模型文件
|
||||||
14. 支持 txt, xml(渲染), xbrl(渲染), md(渲染), java, php, py, js, css 等所有纯文本
|
14. 支持 txt, xml(渲染), xbrl(渲染), md(渲染), java, php, py, js, css 等所有纯文本
|
||||||
15. 支持 zip, rar, jar, tar, gzip, 7z 等压缩包
|
15. 支持 zip, rar, jar, tar, gzip, 7z 等压缩包
|
||||||
16. 支持 jpg, jpeg, png, gif, bmp, ico, jfif, webp 等图片预览(翻转,缩放,镜像)
|
16. 支持 jpg, jpeg, png, gif, bmp, ico, jfif, webp ,heic等图片预览(翻转,缩放,镜像)
|
||||||
17. 支持 tif, tiff 图信息模型文件
|
17. 支持 tif, tiff 图信息模型文件
|
||||||
18. 支持 tga 图像格式文件
|
18. 支持 tga 图像格式文件
|
||||||
19. 支持 svg 矢量图像格式文件
|
19. 支持 svg 矢量图像格式文件
|
||||||
20. 支持 mp3,wav,mp4,flv 等音视频格式文件
|
20. 支持 mp3,wav,mp4,flv 等音视频格式文件
|
||||||
21. 支持 avi,mov,rm,webm,ts,rm,mkv,mpeg,ogg,mpg,rmvb,wmv,3gp,ts,swf 等视频格式转码预览
|
21. 支持 avi,mov,rm,webm,ts,rm,mkv,mpeg,ogg,mpg,rmvb,wmv,3gp,ts 等视频格式转码预览
|
||||||
22. 支持 dcm 等医疗数位影像预览
|
22. 支持 dcm 等医疗数位影像预览
|
||||||
23. 支持 drawio 绘图预览
|
23. 支持 drawio 绘图预览
|
||||||
|
|
||||||
@@ -149,6 +149,47 @@ pdf预览模式预览效果如下
|
|||||||
|
|
||||||
### 历史更新记录
|
### 历史更新记录
|
||||||
|
|
||||||
|
#### > 2026年01月20日,v5.0 版本发布 :
|
||||||
|
#### 优化内容
|
||||||
|
1. xlsx 前端解析优化 - 提升Excel文件前端渲染性能
|
||||||
|
2. 图片解析优化 - 改进图片处理机制
|
||||||
|
3. tif 解析优化 - 增强TIF格式支持
|
||||||
|
4. svg 解析优化 - 优化SVG矢量图渲染
|
||||||
|
5. json 解析优化 - 改进JSON文件处理
|
||||||
|
6. ftp多客户端接入优化 - 提升FTP服务兼容性
|
||||||
|
7. 首页目录访问优化 - 采用post服务端分页机制
|
||||||
|
8. marked 解析优化 - 改进Markdown渲染
|
||||||
|
|
||||||
|
#### 新增功能
|
||||||
|
1. msg邮件解析 - 新增msg格式邮件文件预览支持
|
||||||
|
2. heic图片解析 - 新增HEIC格式图片预览支持
|
||||||
|
3. 跨域方法 - 新增跨域处理机制
|
||||||
|
4. 高亮方法 - 新增文本高亮功能
|
||||||
|
5. 页码方法 - 新增文档页码控制
|
||||||
|
6. AES加密方法 - 新增AES加密支持
|
||||||
|
7. Basic鉴权方法 - 新增Basic认证机制
|
||||||
|
8. 秘钥方法 - 新增密钥管理功能
|
||||||
|
9. 防重复转换 - 新增重复文件转换防护
|
||||||
|
10. 异步等待 - 新增异步处理机制
|
||||||
|
11. 上传限制 - 新增不支持文件上传限制
|
||||||
|
12. cadviewer转换方法 - 新增CAD查看器转换功能
|
||||||
|
|
||||||
|
#### 修复问题
|
||||||
|
1. 压缩包路径问题 - 修复压缩包内部路径处理
|
||||||
|
2. 安全问题 - 修复安全漏洞
|
||||||
|
3. 图片水印不全问题 - 修复水印显示不完整
|
||||||
|
4. SSL自签证书接入问题 - 修复自签名证书兼容性
|
||||||
|
|
||||||
|
#### 更新内容
|
||||||
|
1. JDK版本要求 - 强制要求JDK 21及以上版本
|
||||||
|
2. pdf前端解析更新 - 升级PDF前端渲染组件
|
||||||
|
3. odf前端解析更新 - 升级ODF文档前端渲染
|
||||||
|
4. 3D模型前端解析更新 - 升级3D模型查看器
|
||||||
|
5. pdf后端异步转换优化 - 实现多线程异步转换
|
||||||
|
6. tif后端异步转换优化 - 实现多线程异步转换
|
||||||
|
7. 视频后端异步转换优化 - 实现多线程异步转换
|
||||||
|
8. CAD后端异步转换优化 - 实现多线程异步转换
|
||||||
|
|
||||||
#### > 2025年01月16日,v4.4.0 版本发布 :
|
#### > 2025年01月16日,v4.4.0 版本发布 :
|
||||||
|
|
||||||
### 新增功能
|
### 新增功能
|
||||||
|
|||||||
172
README.md
@@ -13,13 +13,13 @@ Document online preview project solution, built using the popular Spring Boot fr
|
|||||||
7. Supports document formats like `pdf`, `ofd`, and `rtf`.
|
7. Supports document formats like `pdf`, `ofd`, and `rtf`.
|
||||||
8. Supports software model files like `xmind`.
|
8. Supports software model files like `xmind`.
|
||||||
9. Support for `bpmn` workflow files.
|
9. Support for `bpmn` workflow files.
|
||||||
10. Support for `eml` mail files
|
10. Support for `eml` , `msg` mail files
|
||||||
11. Support for `epub` book documents
|
11. Support for `epub` book documents
|
||||||
12. Supports 3D model files like `obj`, `3ds`, `stl`, `ply`, `gltf`, `glb`, `off`, `3dm`, `fbx`, `dae`, `wrl`, `3mf`, `ifc`, `brep`, `step`, `iges`, `fcstd`, `bim`, etc.
|
12. Supports 3D model files like `obj`, `3ds`, `stl`, `ply`, `gltf`, `glb`, `off`, `3dm`, `fbx`, `dae`, `wrl`, `3mf`, `ifc`, `brep`, `step`, `iges`, `fcstd`, `bim`, etc.
|
||||||
13. Supports CAD model files such as `dwg`, `dxf`, `dwf` `iges` ,` igs`, `dwt` , `dng` , `ifc` , `dwfx` , `stl` , `cf2` , `plt`, etc.
|
13. Supports CAD model files such as `dwg`, `dxf`, `dwf` `iges` ,` igs`, `dwt` , `dng` , `ifc` , `dwfx` , `stl` , `cf2` , `plt`, etc.
|
||||||
14. Supports all plain text files such as `txt`, `xml` (rendering), `md` (rendering), `java`, `php`, `py`, `js`, `css`, etc.
|
14. Supports all plain text files such as `txt`, `xml` (rendering), `md` (rendering), `java`, `php`, `py`, `js`, `css`, etc.
|
||||||
15. Supports compressed packages such as `zip`, `rar`, `jar`, `tar`, `gzip`, `7z`, etc.
|
15. Supports compressed packages such as `zip`, `rar`, `jar`, `tar`, `gzip`, `7z`, etc.
|
||||||
16. Supports image previewing (flip, zoom, mirror) of `jpg`, `jpeg`, `png`, `gif`, `bmp`, `ico`, `jfif`, `webp`, etc.
|
16. Supports image previewing (flip, zoom, mirror) of `jpg`, `jpeg`, `png`, `gif`, `bmp`, `ico`, `jfif`, `webp`, `heic`, etc.
|
||||||
17. Supports image information model files such as `tif` and `tiff`.
|
17. Supports image information model files such as `tif` and `tiff`.
|
||||||
18. Supports image format files such as `tga`.
|
18. Supports image format files such as `tga`.
|
||||||
19. Supports vector image format files such as `svg`.
|
19. Supports vector image format files such as `svg`.
|
||||||
@@ -63,6 +63,174 @@ URL:[https://file.kkview.cn](https://file.kkview.cn)
|
|||||||
|
|
||||||
2. second step:Run the main method of `/server/src/main/java/cn/keking/ServerMain.java`. After starting,visit `http://localhost:8012/`.
|
2. second step:Run the main method of `/server/src/main/java/cn/keking/ServerMain.java`. After starting,visit `http://localhost:8012/`.
|
||||||
|
|
||||||
|
## Change History
|
||||||
|
|
||||||
|
### Version 5.0 (January 20, 2026)
|
||||||
|
|
||||||
|
#### Optimizations
|
||||||
|
1. Enhanced xlsx front-end parsing - Improved Excel file front-end rendering performance
|
||||||
|
2. Optimized image parsing - Enhanced image processing mechanism
|
||||||
|
3. Improved tif parsing - Enhanced TIF format support
|
||||||
|
4. Enhanced svg parsing - Optimized SVG vector image rendering
|
||||||
|
5. Improved json parsing - Enhanced JSON file processing
|
||||||
|
6. Optimized ftp multi-client access - Improved FTP service compatibility
|
||||||
|
7. Enhanced home page directory access - Implemented post server-side pagination mechanism
|
||||||
|
8. Improved marked parsing - Enhanced Markdown rendering
|
||||||
|
|
||||||
|
#### New Features
|
||||||
|
1. msg email parsing - Added support for msg format email file preview
|
||||||
|
2. heic image parsing - Added support for HEIC format image preview
|
||||||
|
3. Cross-domain methods - Added cross-domain processing mechanism
|
||||||
|
4. Highlighting methods - Added text highlighting functionality
|
||||||
|
5. Pagination methods - Added document page control
|
||||||
|
6. AES encryption methods - Added AES encryption support
|
||||||
|
7. Basic authentication methods - Added Basic authentication mechanism
|
||||||
|
8. Key management methods - Added key management functionality
|
||||||
|
9. Anti-duplicate conversion - Added duplicate file conversion protection
|
||||||
|
10. Async waiting - Added asynchronous processing mechanism
|
||||||
|
11. Upload restrictions - Added restrictions for unsupported file uploads
|
||||||
|
12. cadviewer conversion methods - Added CAD viewer conversion functionality
|
||||||
|
|
||||||
|
#### Fixed Issues
|
||||||
|
1. Compressed file path issues - Fixed internal path handling in compressed files
|
||||||
|
2. Security issues - Fixed security vulnerabilities
|
||||||
|
3. Incomplete image watermark issues - Fixed incomplete watermark display
|
||||||
|
4. SSL self-signed certificate access issues - Fixed compatibility with self-signed certificates
|
||||||
|
|
||||||
|
#### Updates
|
||||||
|
1. JDK version requirement - Mandatory requirement for JDK 21 or higher
|
||||||
|
2. pdf front-end parsing update - Upgraded PDF front-end rendering component
|
||||||
|
3. odf front-end parsing update - Upgraded ODF document front-end rendering
|
||||||
|
4. 3D model front-end parsing update - Upgraded 3D model viewer
|
||||||
|
5. pdf backend async conversion optimization - Implemented multi-threaded asynchronous conversion
|
||||||
|
6. tif backend async conversion optimization - Implemented multi-threaded asynchronous conversion
|
||||||
|
7. Video backend async conversion optimization - Implemented multi-threaded asynchronous conversion
|
||||||
|
8. CAD backend async conversion optimization - Implemented multi-threaded asynchronous conversion
|
||||||
|
|
||||||
|
### Version 4.4.0 (January 16, 2025)
|
||||||
|
|
||||||
|
#### New Features
|
||||||
|
1. xlsx printing support
|
||||||
|
2. Added GZIP compression enablement in configuration
|
||||||
|
3. CAD format now supports conversion to SVG and TIF formats, added timeout termination and thread management
|
||||||
|
4. Added captcha verification for file deletion
|
||||||
|
5. Added xbrl format preview support
|
||||||
|
6. PDF preview added control over signatures, drawings, illustration control, search positioning pagination, and display content definition
|
||||||
|
7. Added CSV format front-end parsing support
|
||||||
|
8. Added Docker image support for ARM64
|
||||||
|
9. Added Office preview conversion timeout property setting
|
||||||
|
10. Added preview file host blacklist mechanism
|
||||||
|
|
||||||
|
#### Optimizations
|
||||||
|
1. Optimized OFD mobile preview page adaptability
|
||||||
|
2. Updated xlsx front-end parsing component to accelerate parsing speed
|
||||||
|
3. Upgraded CAD component
|
||||||
|
4. Office function adjustments, supporting comments, conversion page limit, watermark generation, etc.
|
||||||
|
5. Upgraded markdown component
|
||||||
|
6. Upgraded dcm parsing component
|
||||||
|
7. Upgraded PDF.JS parsing component
|
||||||
|
8. Changed video player plugin to ckplayer
|
||||||
|
9. Smarter tif parsing, supporting modified image formats
|
||||||
|
10. Improved character encoding detection accuracy for large and small text files, handling concurrency vulnerabilities
|
||||||
|
11. Refactored file download code, added general file server authentication access design
|
||||||
|
12. Updated bootstrap component and streamlined unnecessary files
|
||||||
|
13. Updated epub version, optimized epub display effect
|
||||||
|
14. Fixed issue where scheduled cache cleanup only deleted disk cache files for multimedia file types
|
||||||
|
15. Auto-detection of installed Office components, added default paths for LibreOffice 7.5 & 7.6 versions
|
||||||
|
16. Changed drawio default to preview mode
|
||||||
|
17. Added PDF thread management, timeout management, memory cache management, updated PDF parsing component version
|
||||||
|
18. Optimized Dockerfile for true cross-platform image building
|
||||||
|
|
||||||
|
#### Fixes
|
||||||
|
1. Fixed forceUpdatedCache property setting issue where local cache files weren't updated
|
||||||
|
2. Fixed PDF decryption error after successful encrypted file conversion
|
||||||
|
3. Fixed BPMN cross-domain support issue
|
||||||
|
4. Fixed special character error in compressed package secondary reverse proxy
|
||||||
|
5. Fixed video cross-domain configuration causing video preview failure
|
||||||
|
6. Fixed TXT text pagination secondary loading issue
|
||||||
|
7. Fixed Drawio missing Base64 component issue
|
||||||
|
8. Fixed Markdown escaping issue
|
||||||
|
9. Fixed EPUB cross-domain error
|
||||||
|
10. Fixed URL special character issues
|
||||||
|
11. Fixed compressed package traversal vulnerability
|
||||||
|
12. Fixed compressed file path errors, image collection path errors, watermark issues, etc.
|
||||||
|
13. Fixed front-end parsing XLSX containing EMF format file errors
|
||||||
|
|
||||||
|
### Version 4.3.0 (July 5, 2023)
|
||||||
|
|
||||||
|
#### New Features
|
||||||
|
1. Added DCM medical digital imaging preview
|
||||||
|
2. Added drawio drawing preview
|
||||||
|
3. Added command to regenerate with cache enabled: &forceUpdatedCache=true
|
||||||
|
4. Added dwg CAD file preview
|
||||||
|
5. Added PDF file password support
|
||||||
|
6. Added DPI customization for PDF file image generation
|
||||||
|
7. Added configuration to delete converted OFFICE, CAD, TIFF, compressed package source files (enabled by default to save disk space)
|
||||||
|
8. Added front-end xlsx parsing method
|
||||||
|
9. Added support for pages, eps, iges, igs, dwt, dng, ifc, dwfx, stl, cf2, plt and other formats
|
||||||
|
|
||||||
|
#### Optimizations
|
||||||
|
1. Modified generated PDF file names to include file extensions to prevent duplicate names
|
||||||
|
2. Adjusted SQL file preview method
|
||||||
|
3. Optimized OFD preview compatibility
|
||||||
|
4. Beautified TXT text pagination box display
|
||||||
|
5. Upgraded Linux/Docker built-in office to LibreOffice-7.5.3
|
||||||
|
6. Upgraded Windows built-in office to LibreOffice-7.5.3 Portable
|
||||||
|
7. Other functional optimizations
|
||||||
|
|
||||||
|
#### Fixes
|
||||||
|
1. Fixed compressed package path errors in reverse proxy scenarios
|
||||||
|
2. Fixed .click error when image preview URLs contain &
|
||||||
|
3. Fixed known OFD preview issues
|
||||||
|
4. Fixed page error when clicking on file directories (tree nodes) in compressed package preview
|
||||||
|
5. Other known issue fixes
|
||||||
|
|
||||||
|
### Version 4.2.1 (April 18, 2023)
|
||||||
|
|
||||||
|
#### Change Log
|
||||||
|
1. Fixed null pointer bug in dwg file preview
|
||||||
|
|
||||||
|
### Version 4.2.0 (April 13, 2023)
|
||||||
|
|
||||||
|
#### New Features
|
||||||
|
1. Added SVG format file preview support
|
||||||
|
2. Added encrypted Office file preview support
|
||||||
|
3. Added encrypted zip, rar, and other compressed package file preview support
|
||||||
|
4. Added xmind software model file preview support
|
||||||
|
5. Added BPMN workflow model file preview support
|
||||||
|
6. Added eml email file preview support
|
||||||
|
7. Added EPUB e-book file preview support
|
||||||
|
8. Added office document format support: dotm, ett, xlt, xltm, wpt, dot, xlam, xla, dotx, etc.
|
||||||
|
9. Added 3D model file support: obj, 3ds, stl, ply, gltf, glb, off, 3dm, fbx, dae, wrl, 3mf, ifc, brep, step, iges, fcstd, bim, etc.
|
||||||
|
10. Added configurable high-risk file upload restrictions (e.g., exe files)
|
||||||
|
11. Added configurable site filing information
|
||||||
|
12. Added password requirement for demo site file deletion
|
||||||
|
|
||||||
|
#### Optimizations
|
||||||
|
1. Added caching for text document preview
|
||||||
|
2. Beautified 404, 500 error pages
|
||||||
|
3. Optimized invoice and other OFD file preview seal rendering compatibility
|
||||||
|
4. Removed office-plugin module, using new jodconverter component
|
||||||
|
5. Optimized Excel file preview effect
|
||||||
|
6. Optimized CAD file preview effect
|
||||||
|
7. Updated xstream, junrar, pdfbox, and other dependency versions
|
||||||
|
8. Updated TIF to PDF conversion plugin, added conversion cache
|
||||||
|
9. Optimized demo page UI deployment
|
||||||
|
10. Compressed package file preview supports directories
|
||||||
|
|
||||||
|
#### Fixes
|
||||||
|
1. Fixed XSS issues in some interfaces
|
||||||
|
2. Fixed console printed demo address not following content-path configuration
|
||||||
|
3. Fixed OFD file preview cross-domain issues
|
||||||
|
4. Fixed internal self-signed certificate HTTPS URL file download issues
|
||||||
|
5. Fixed special character file deletion issues
|
||||||
|
6. Fixed OOM caused by unreclaimed memory in PDF to image conversion
|
||||||
|
7. Fixed garbled preview for xlsx 7.4+ version files
|
||||||
|
8. Fixed TrustHostFilter not intercepting cross-domain interfaces (security issue - upgrade required if using TrustHost)
|
||||||
|
9. Fixed compressed package file preview filename garbled issue on Linux systems
|
||||||
|
10. Fixed OFD file preview only displaying 10 pages
|
||||||
|
|
||||||
|
|
||||||
### Changelog
|
### Changelog
|
||||||
> December 14, 2022, version 4.1.0 released:
|
> December 14, 2022, version 4.1.0 released:
|
||||||
|
|
||||||
|
|||||||
2
pom.xml
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
<groupId>cn.keking</groupId>
|
<groupId>cn.keking</groupId>
|
||||||
<artifactId>kkFileView-parent</artifactId>
|
<artifactId>kkFileView-parent</artifactId>
|
||||||
<version>4.4.0</version>
|
<version>5.0</version>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<!-- ========== Java 和编译配置 ========== -->
|
<!-- ========== Java 和编译配置 ========== -->
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>kkFileView-parent</artifactId>
|
<artifactId>kkFileView-parent</artifactId>
|
||||||
<groupId>cn.keking</groupId>
|
<groupId>cn.keking</groupId>
|
||||||
<version>4.4.0</version>
|
<version>5.0</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>kkFileView</artifactId>
|
<artifactId>kkFileView</artifactId>
|
||||||
|
|||||||
478
server/src/main/config/test.properties
Normal file
@@ -0,0 +1,478 @@
|
|||||||
|
###############################################################################
|
||||||
|
# 一、服务器基础配置(需要重启生效)
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
# 服务器端口号,默认8012
|
||||||
|
# 可以通过环境变量 KK_SERVER_PORT 覆盖
|
||||||
|
server.port = ${KK_SERVER_PORT:8012}
|
||||||
|
|
||||||
|
# 应用上下文路径,默认为根路径 /
|
||||||
|
# 可以通过环境变量 KK_CONTEXT_PATH 覆盖
|
||||||
|
server.servlet.context-path = ${KK_CONTEXT_PATH:/}
|
||||||
|
|
||||||
|
# 字符编码设置,统一使用UTF-8
|
||||||
|
server.servlet.encoding.charset = utf-8
|
||||||
|
|
||||||
|
# 启用响应压缩,减少网络传输
|
||||||
|
server.compression.enabled = true
|
||||||
|
server.compression.min-response-size = 2048
|
||||||
|
server.compression.mime-types = application/javascript,text/css,application/json,application/xml,text/html,text/xml,text/plain,font/woff,application/font-woff,font/eot,image/svg+xml,image/x-icon
|
||||||
|
|
||||||
|
# 文件上传大小限制,默认500MB
|
||||||
|
# 注意:需要同时设置spring.servlet.multipart.max-file-size和max-request-size
|
||||||
|
spring.servlet.multipart.max-file-size = 500MB
|
||||||
|
spring.servlet.multipart.max-request-size = 500MB
|
||||||
|
|
||||||
|
# FreeMarker模板引擎配置
|
||||||
|
spring.freemarker.template-loader-path = classpath:/web/
|
||||||
|
spring.freemarker.cache = false
|
||||||
|
spring.freemarker.charset = UTF-8
|
||||||
|
spring.freemarker.check-template-location = true
|
||||||
|
spring.freemarker.content-type = text/html
|
||||||
|
spring.freemarker.expose-request-attributes = true
|
||||||
|
spring.freemarker.expose-session-attributes = true
|
||||||
|
spring.freemarker.request-context-attribute = request
|
||||||
|
spring.freemarker.suffix = .ftl
|
||||||
|
|
||||||
|
# Spring Boot Actuator监控端点配置
|
||||||
|
management.endpoints.web.exposure.include = health,info,metrics
|
||||||
|
management.endpoint.health.show-details = always
|
||||||
|
management.health.defaults.enabled = true
|
||||||
|
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# 二、Office文档处理配置(部分支持动态配置)
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
# Office组件安装路径,默认为自动查找
|
||||||
|
# Windows示例(注意双反斜杠):C:\\Program Files (x86)\\OpenOffice 4
|
||||||
|
# Linux示例:/opt/libreoffice
|
||||||
|
# MacOS示例:/Applications/LibreOffice.app/Contents
|
||||||
|
office.home = ${KK_OFFICE_HOME:default}
|
||||||
|
|
||||||
|
# Office组件服务端口,支持多个端口实现负载均衡
|
||||||
|
office.plugin.server.ports = 2001,2002
|
||||||
|
|
||||||
|
# Office组件任务超时时间,默认5分钟
|
||||||
|
office.plugin.task.timeout = 5m
|
||||||
|
|
||||||
|
# 每个进程最大任务数,防止内存溢出
|
||||||
|
office.plugin.task.maxtasksperprocess = 200
|
||||||
|
|
||||||
|
# 任务执行超时时间,默认5分钟
|
||||||
|
office.plugin.task.taskexecutiontimeout = 5m
|
||||||
|
|
||||||
|
# Office文档分页范围,支持动态配置
|
||||||
|
# 默认false,开启后可以指定转换的页面范围
|
||||||
|
office.pagerange = ${KK_OFFICE_PAGERANGE:false}
|
||||||
|
|
||||||
|
# Office文档水印功能,支持动态配置
|
||||||
|
# 默认false,开启后会在Office文档上添加水印
|
||||||
|
office.watermark = ${KK_OFFICE_WATERMARK:false}
|
||||||
|
|
||||||
|
# Office图片质量,1-100,默认80
|
||||||
|
# 值越高图片质量越好,但文件越大
|
||||||
|
office.quality = ${KK_OFFICE_QUALITY:80}
|
||||||
|
|
||||||
|
# Office图片最大分辨率,默认150
|
||||||
|
# 控制生成图片的最大分辨率
|
||||||
|
office.maximageresolution = ${KK_OFFICE_MAXIMAGERESOLUTION:150}
|
||||||
|
|
||||||
|
# 导出Office书签,支持动态配置
|
||||||
|
# 默认true,转换PDF时保留书签
|
||||||
|
office.exportbookmarks = ${KK_OFFICE_EXPORTBOOKMARKS:true}
|
||||||
|
|
||||||
|
# 是否将Office文档中的批注作为PDF注释导出,默认为true(导出)
|
||||||
|
# 保留批注便于文档审阅
|
||||||
|
office.exportnotes = ${KK_OFFICE_EXPORTNOTES:true}
|
||||||
|
|
||||||
|
# 加密文档生成的PDF是否添加密码,默认为true(添加)
|
||||||
|
# 密码为原始加密文档的密码,增强文档安全性
|
||||||
|
office.documentopenpasswords = ${KK_OFFICE_DOCUMENTOPENPASSWORD:true}
|
||||||
|
|
||||||
|
# Excel文档(xlsx)的前端解析方式,默认为web(Web端解析)
|
||||||
|
# web: 使用前端SheetJS库解析,减轻服务器压力
|
||||||
|
# image: 服务器转换为图片,兼容性更好
|
||||||
|
office.type.web = ${KK_OFFICE_TYPE_WEB:web}
|
||||||
|
|
||||||
|
# Office文档预览类型
|
||||||
|
# 支持动态配置,可选值:image/pdf
|
||||||
|
office.preview.type = ${KK_OFFICE_PREVIEW_TYPE:image}
|
||||||
|
|
||||||
|
# 是否关闭Office预览模式切换开关,默认为false(允许切换)
|
||||||
|
# 设置为true时,用户无法在图片和PDF模式间切换
|
||||||
|
office.preview.switch.disabled = ${KK_OFFICE_PREVIEW_SWITCH_DISABLED:false}
|
||||||
|
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# 三、CAD文件处理配置(支持动态配置)
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
# CAD文件预览类型
|
||||||
|
# svg: 转换为SVG矢量格式(缩放不失真)
|
||||||
|
# pdf: 转换为PDF格式(便于打印和标注)
|
||||||
|
cad.preview.type = ${KK_CAD_PREVIEW_TYPE:svg}
|
||||||
|
|
||||||
|
# Cad转换模块设置(aspose-cad=1 ,cadviewer=3)
|
||||||
|
# aspose-cad 默认集成到系统,但是特别吃服务器性能 (支持转换格式为 svg、pdf)
|
||||||
|
# cadviewer 下载地址 https://cadviewer.com/alldownloads/autoxchange/ 更具自己系统下载转换包(支持转换格式为 svg、svgz、pdf)
|
||||||
|
# 1=aspose-cad 转换格式为 pdf,svg,tif 支持类型最多
|
||||||
|
# 2=cadviewer 转换格式为 pdf,svg 支持的类型 dwg dxf dwf
|
||||||
|
cad.conversionmodule = 2
|
||||||
|
|
||||||
|
# Cad 后端转换包路径 (linux 严格注意大小写)
|
||||||
|
# cadviewer windows 修改名称为 cadviewer.exe linux修改名称为 cadviewer 需要安装字体
|
||||||
|
# cadviewer 字体下载 https://cadviewer.com/downloads/fonts/fonts.tar.gz 放在 cad.file.path 目录里面的fonts.
|
||||||
|
cad.cadconverterpath = D:/github/AutoXChange/
|
||||||
|
|
||||||
|
|
||||||
|
# CAD文件处理线程数
|
||||||
|
cad.thread = ${KK_CAD_THREAD:5}
|
||||||
|
|
||||||
|
# CAD文件处理超时时间(秒)
|
||||||
|
cad.timeout = ${KK_CAD_TIMEOUT:90}
|
||||||
|
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# 四、PDF文件处理配置(支持动态配置)
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
# 是否禁止PDF演示模式,默认为true(禁止)
|
||||||
|
pdf.presentationMode.disable = ${KK_PDF_PRESENTATION_MODE_DISABLE:true}
|
||||||
|
|
||||||
|
# 是否禁止PDF文件菜单中的"打开文件"选项,默认为true(禁止)
|
||||||
|
pdf.openFile.disable = ${KK_PDF_OPEN_FILE_DISABLE:true}
|
||||||
|
|
||||||
|
# 是否禁止PDF打印功能,默认为true(禁止)
|
||||||
|
pdf.print.disable = ${KK_PDF_PRINT_DISABLE:true}
|
||||||
|
|
||||||
|
# 是否禁止PDF下载功能,默认为true(禁止)
|
||||||
|
pdf.download.disable = ${KK_PDF_DOWNLOAD_DISABLE:true}
|
||||||
|
|
||||||
|
# 是否禁止PDF书签/大纲功能,默认为true(禁止)
|
||||||
|
pdf.bookmark.disable = ${KK_PDF_BOOKMARK_DISABLE:true}
|
||||||
|
|
||||||
|
# 是否禁止PDF编辑功能(注释、表单等),默认为false(允许编辑)
|
||||||
|
pdf.disable.editing = ${KK_PDF_DISABLE_EDITING:false}
|
||||||
|
|
||||||
|
# PDF处理最大线程数,控制并发处理能力
|
||||||
|
pdf.max.threads = 10
|
||||||
|
|
||||||
|
# PDF处理超时配置
|
||||||
|
pdf.timeout.small = 90
|
||||||
|
pdf.timeout.medium = 180
|
||||||
|
pdf.timeout.large = 300
|
||||||
|
pdf.timeout.xlarge = 600
|
||||||
|
|
||||||
|
# PDF智能DPI优化
|
||||||
|
# 是否启用PDF DPI智能调整,默认为true(启用)
|
||||||
|
# 根据PDF页数自动调整DPI,平衡清晰度和性能
|
||||||
|
pdf.dpi.enabled = true
|
||||||
|
|
||||||
|
# PDF转图片的基准DPI,默认为144
|
||||||
|
# 当DPI优化禁用时使用此值
|
||||||
|
pdf2jpg.dpi = ${KK_PDF2JPG_DPI:144}
|
||||||
|
|
||||||
|
# 智能DPI分级配置
|
||||||
|
# 小文件(0-50页):150 DPI(高质量)
|
||||||
|
pdf.dpi.small = 150
|
||||||
|
# 中等文件(50-100页):120 DPI(平衡质量与性能)
|
||||||
|
pdf.dpi.medium = 120
|
||||||
|
# 大文件(100-200页):96 DPI(优化性能)
|
||||||
|
pdf.dpi.large = 96
|
||||||
|
# 超大文件(200-500页):72 DPI(快速转换)
|
||||||
|
pdf.dpi.xlarge = 72
|
||||||
|
# 巨量文件(>500页):72 DPI(最小资源消耗)
|
||||||
|
pdf.dpi.xxlarge = 72
|
||||||
|
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# 五、TIF文件处理配置(支持动态配置)
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
# TIF文件预览类型
|
||||||
|
# tif: 使用前端Tiff.js插件直接浏览(需要浏览器支持)
|
||||||
|
# jpg: 服务器转换为JPG格式后显示
|
||||||
|
# pdf: 服务器转换为PDF格式显示
|
||||||
|
tif.preview.type = ${KK_TIF_PREVIEW_TYPE:tif}
|
||||||
|
|
||||||
|
# TIF文件处理线程数
|
||||||
|
tif.thread = 5
|
||||||
|
|
||||||
|
# TIF文件处理超时时间(秒)
|
||||||
|
tif.timeout = 90
|
||||||
|
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# 六、媒体文件处理配置(支持动态配置)
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
# 媒体文件类型(音频、视频)
|
||||||
|
media = ${KK_MEDIA:mp3,wav,mp4,flv,mpd,m3u8,ts,mpeg,m4a}
|
||||||
|
|
||||||
|
# 需要转换的媒体文件类型
|
||||||
|
convertMedias = ${KK_CONVERTMEDIAS:avi,mov,wmv,mkv,3gp,rm,mpeg}
|
||||||
|
|
||||||
|
# 媒体文件超时控制
|
||||||
|
media.timeout.enabled = true
|
||||||
|
media.small.file.timeout = 30
|
||||||
|
media.medium.file.timeout = 60
|
||||||
|
media.large.file.timeout = 180
|
||||||
|
media.xl.file.timeout = 300
|
||||||
|
media.xxl.file.timeout = 600
|
||||||
|
media.xxxl.file.timeout = 1200
|
||||||
|
|
||||||
|
# 媒体文件转换最大大小(MB)
|
||||||
|
media.convert.max.size = 300
|
||||||
|
|
||||||
|
# 是否禁用视频格式转换功能,默认为false(禁用)
|
||||||
|
# ⚠️ 重要:视频转换非常消耗CPU和内存资源
|
||||||
|
media.convert.disable = ${KK_MEDIA_CONVERT_DISABLE:true}
|
||||||
|
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# 七、文件存储与缓存配置(支持动态配置)
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
# 预览生成资源的存储路径,默认为应用根路径下的file目录
|
||||||
|
# Windows示例:D:\\kkFileview\\(注意双反斜杠)
|
||||||
|
# Linux示例:/opt/kkfileview/file/
|
||||||
|
# 重要:确保应用有该目录的读写权限
|
||||||
|
file.dir = ${KK_FILE_DIR:default}
|
||||||
|
|
||||||
|
# 允许预览的本地文件夹路径,默认为default(禁止所有本地文件预览)
|
||||||
|
# ⚠️ 安全警告:配置此路径可能允许访问系统文件,请谨慎配置
|
||||||
|
# Windows示例(注意前面加反斜杠):\D:\\kkFileview\\1\\1.txt
|
||||||
|
# Linux示例(注意前面加正斜杠):/opt/1.txt
|
||||||
|
# 使用file协议访问:file://d:/1/1.txt(Windows)或 file:/opt/1.txt(Linux)
|
||||||
|
local.preview.dir = \D:\\
|
||||||
|
|
||||||
|
# 是否启用缓存,支持动态配置
|
||||||
|
# 默认true,开启缓存提高性能
|
||||||
|
cache.enabled = ${KK_CACHE_ENABLED:true}
|
||||||
|
|
||||||
|
# 缓存实现类型,默认为jdk(使用JDK内置对象实现)
|
||||||
|
# 可选值:
|
||||||
|
# jdk: JDK内置ConcurrentHashMap,单机部署推荐
|
||||||
|
# redis: Redis分布式缓存,集群部署推荐
|
||||||
|
# default: 内嵌RocksDB,支持持久化
|
||||||
|
cache.type = ${KK_CACHE_TYPE:jdk}
|
||||||
|
|
||||||
|
# Redis部署模式,默认为single(单机模式)
|
||||||
|
# 可选值:
|
||||||
|
# single: 单机模式(默认)
|
||||||
|
# cluster: 集群模式
|
||||||
|
# sentinel: 哨兵模式(高可用)
|
||||||
|
# master-slave: 主从模式
|
||||||
|
spring.redisson.mode = single
|
||||||
|
# Redis连接地址,支持多种格式:
|
||||||
|
# 单机模式:redis://127.0.0.1:6379
|
||||||
|
# 集群模式:redis://node1:6379,redis://node2:6379,redis://node3:6379
|
||||||
|
# 哨兵模式:redis://sentinel1:26379,redis://sentinel2:26379
|
||||||
|
spring.redisson.address = ${KK_SPRING_REDISSON_ADDRESS:redis://127.0.0.1:6379}
|
||||||
|
# Redis连接密码,无密码时留空
|
||||||
|
spring.redisson.password = ${KK_SPRING_REDISSON_PASSWORD:}
|
||||||
|
# Redis数据库索引,默认为0(0-15)
|
||||||
|
# 不同业务可使用不同数据库隔离
|
||||||
|
spring.redisson.database = ${KK_SPRING_REDISSON_DATABASE:0}
|
||||||
|
|
||||||
|
# 缓存清理配置
|
||||||
|
# 是否启用缓存自动清理,默认为true(启用)
|
||||||
|
# 定期清理过期缓存,避免磁盘空间无限增长
|
||||||
|
cache.clean.enabled = ${KK_CACHE_CLEAN_ENABLED:true}
|
||||||
|
# 缓存自动清理时间,使用Quartz cron表达式,默认为每天凌晨3点执行
|
||||||
|
# 表达式格式:秒 分 时 日 月 周 年(可选)
|
||||||
|
# 0 0 3 * * ? 表示每天3:00:00执行清理
|
||||||
|
cache.clean.cron = ${KK_CACHE_CLEAN_CRON:0 0 3 * * ?}
|
||||||
|
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# 八、安全与访问控制配置(支持动态配置)
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
# 提供预览服务的地址,默认从请求url读,如果使用nginx等反向代理,需要手动设置
|
||||||
|
# base.url = https://file.keking.cn
|
||||||
|
base.url = ${KK_BASE_URL:default}
|
||||||
|
|
||||||
|
# 信任站点白名单配置,多个用','隔开
|
||||||
|
# ⚠️ 安全提示:为防止SSRF攻击,强烈建议配置信任主机白名单
|
||||||
|
# ⚠️ 如果不配置,系统将默认拒绝所有外部文件预览请求
|
||||||
|
# 配置示例:
|
||||||
|
# trust.host = kkview.cn,yourdomain.com,cdn.example.com
|
||||||
|
# 如果需要允许所有域名(不推荐,仅用于测试环境),请设置为:
|
||||||
|
# trust.host = *
|
||||||
|
# 当前配置:默认本机测试 (正式启用请修改)
|
||||||
|
trust.host = *
|
||||||
|
|
||||||
|
# 不信任站点黑名单配置,多个用逗号隔开
|
||||||
|
# 黑名单优先级高于白名单,设置后将禁止预览来自这些站点的文件
|
||||||
|
# 建议配置:禁止访问内网地址和本地地址,防止内部信息泄露
|
||||||
|
# 配置示例:
|
||||||
|
# not.trust.host = localhost,127.0.0.1,0.0.0.0,192.168.*,10.*,172.16.*,172.17.*,172.18.*,172.19.*,172.20.*,172.21.*,172.22.*,172.23.*,172.24.*,172.25.*,172.26.*,172.27.*,172.28.*,172.29.*,172.30.*,172.31.*
|
||||||
|
not.trust.host = ${KK_NOT_TRUST_HOST:default}
|
||||||
|
|
||||||
|
# 禁止访问的文件类型,安全限制
|
||||||
|
# 支持动态配置,格式:exe,dll,dat
|
||||||
|
prohibit = ${KK_PROHIBIT:exe,dll,dat}
|
||||||
|
|
||||||
|
# 是否忽略SSL证书验证,默认为true(忽略)
|
||||||
|
# 用于开发环境或自签名证书场景
|
||||||
|
# 生产环境建议设置为false,启用完整的证书验证
|
||||||
|
kk.ignore.ssl = true
|
||||||
|
|
||||||
|
# 是否启用URL重定向功能,默认为true(启用)
|
||||||
|
# 用于处理文件下载、外部资源引用等场景
|
||||||
|
kk.enable.redirect = true
|
||||||
|
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# 九、水印配置(支持动态配置)
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
# 水印文本内容
|
||||||
|
# 可以通过环境变量 WATERMARK_TXT 覆盖
|
||||||
|
watermark.txt = ${WATERMARK_TXT:}
|
||||||
|
|
||||||
|
# 水印X轴间距
|
||||||
|
# 可以通过环境变量 WATERMARK_X_SPACE 覆盖
|
||||||
|
watermark.x.space = ${WATERMARK_X_SPACE:10}
|
||||||
|
|
||||||
|
# 水印Y轴间距
|
||||||
|
# 可以通过环境变量 WATERMARK_Y_SPACE 覆盖
|
||||||
|
watermark.y.space = ${WATERMARK_Y_SPACE:10}
|
||||||
|
|
||||||
|
# 水印字体
|
||||||
|
# 可以通过环境变量 WATERMARK_FONT 覆盖
|
||||||
|
watermark.font = ${WATERMARK_FONT:微软雅黑}
|
||||||
|
|
||||||
|
# 水印字体大小
|
||||||
|
# 可以通过环境变量 WATERMARK_FONTSIZE 覆盖
|
||||||
|
watermark.fontsize = ${WATERMARK_FONTSIZE:18px}
|
||||||
|
|
||||||
|
# 水印颜色
|
||||||
|
# 可以通过环境变量 WATERMARK_COLOR 覆盖
|
||||||
|
watermark.color = ${WATERMARK_COLOR:black}
|
||||||
|
|
||||||
|
# 水印透明度,0.0-1.0
|
||||||
|
# 可以通过环境变量 WATERMARK_ALPHA 覆盖
|
||||||
|
watermark.alpha = ${WATERMARK_ALPHA:0.2}
|
||||||
|
|
||||||
|
# 水印宽度
|
||||||
|
# 可以通过环境变量 WATERMARK_WIDTH 覆盖
|
||||||
|
watermark.width = ${WATERMARK_WIDTH:180}
|
||||||
|
|
||||||
|
# 水印高度
|
||||||
|
# 可以通过环境变量 WATERMARK_HEIGHT 覆盖
|
||||||
|
watermark.height = ${WATERMARK_HEIGHT:80}
|
||||||
|
|
||||||
|
# 水印旋转角度
|
||||||
|
# 可以通过环境变量 WATERMARK_ANGLE 覆盖
|
||||||
|
watermark.angle = ${WATERMARK_ANGLE:10}
|
||||||
|
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# 十、FTP文件访问配置(支持动态配置)
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
# FTP模块设置
|
||||||
|
# 预览源为FTP时,可在ftp url后面加参数?ftp.username=ftpuser&ftp.password=123456&ftp.control.encoding=GBK,指定,不指定默认用配置的 (为了安全我们强烈建议在配置中设置相关信息)
|
||||||
|
# ftp.control.encodin (根据FTP服务器操作系统选择,Linux一般为UTF-8,Windows一般为GBK)
|
||||||
|
# 使用方法,支持,分割第一个是域名或者IP地址后面是用户名在后面是密码,在后面是编码(用户名密码和编码用:分割, 域名用,分割),切记url不需要任何协议头
|
||||||
|
# ftp.username = 地址:端口:用户名:密码:编码,192.168.0.2:21:name:123456:UTF-8,www.xxx.com:21:admin:pass:UTF-8 多客户端,分割
|
||||||
|
# ftp.username =10.99.1.2:21:666:88888:GBK
|
||||||
|
ftp.username = false
|
||||||
|
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# 十一、首页与文件管理配置(支持动态配置)
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
# 是否禁用首页文件上传功能,默认为true(禁用)
|
||||||
|
# 设置为true可关闭上传功能,仅用于预览
|
||||||
|
file.upload.disable = false
|
||||||
|
|
||||||
|
# 网站备案信息,显示在首页底部,默认为空
|
||||||
|
beian = ${KK_BEIAN:default}
|
||||||
|
|
||||||
|
# 首页初始化加载的页码,默认为1(第一页)
|
||||||
|
home.pagenumber = ${DEFAULT_HOME_PAGENUMBER:1}
|
||||||
|
|
||||||
|
# 首页每页显示的文件数量,默认为20
|
||||||
|
home.pagesize = ${DEFAULT_HOME_PAGSIZE:20}
|
||||||
|
|
||||||
|
# 文件删除验证配置
|
||||||
|
# 是否启用验证码验证删除文件,默认为false(不启用)
|
||||||
|
# 启用后删除文件需要输入验证码,防止误删
|
||||||
|
delete.captcha = ${KK_DELETE_CAPTCHA:false}
|
||||||
|
|
||||||
|
# 删除文件密码,默认为123456
|
||||||
|
delete.password = ${KK_DELETE_PASSWORD:123456}
|
||||||
|
|
||||||
|
# 是否删除转换后的源文件,默认为true(删除)
|
||||||
|
# 启用可节约磁盘空间,但会丢失原始文件
|
||||||
|
delete.source.file = ${KK_DELETE_SOURCE_FILE:true}
|
||||||
|
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# 十二、权限与认证配置(支持动态配置)
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
# 是否启用图片预览权限,默认为true(启用)
|
||||||
|
# 设置为false可禁用所有图片预览功能
|
||||||
|
kk.Picturespreview = true
|
||||||
|
|
||||||
|
# 是否启用跨域文件获取权限,默认为true(启用)
|
||||||
|
kk.Getcorsfile = true
|
||||||
|
|
||||||
|
# 是否启用添加异步任务权限,默认为true(启用)
|
||||||
|
# 大文件转换通常使用异步任务处理
|
||||||
|
kk.addTask = true
|
||||||
|
|
||||||
|
# API密钥功能,默认为false(禁用)
|
||||||
|
# 启用后需要提供密钥才能调用API
|
||||||
|
kk.key = false
|
||||||
|
|
||||||
|
# AES加密密钥,必须为16位字符
|
||||||
|
# 启用AES加密时,接入方需使用相同的密钥
|
||||||
|
# 用于敏感数据传输加密
|
||||||
|
aes.key = 1234567890123456
|
||||||
|
|
||||||
|
# Basic认证配置,格式:域名:用户名:密码,多个用逗号分隔
|
||||||
|
# 用于保护特定域名的访问
|
||||||
|
# 示例:192.168.0.1:admin:pass123,example.com:user:pass456
|
||||||
|
basic.name = 10.99.1.2:aaa:bbb
|
||||||
|
|
||||||
|
# User-Agent验证字符串,默认不启用
|
||||||
|
# 可用于简单的客户端验证
|
||||||
|
useragent = false
|
||||||
|
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# 十三、高级功能与兼容性配置(支持动态配置)
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
# 异步配置刷新定时时间(秒)
|
||||||
|
kk.refreshschedule = 2
|
||||||
|
|
||||||
|
# 首页是否显示AES密钥 默认为false(禁用)
|
||||||
|
kk.isshowaeskey = false
|
||||||
|
|
||||||
|
# 是否允许XLSX编辑
|
||||||
|
kk.xlsxallowedit = true
|
||||||
|
|
||||||
|
# 是否显示XLSX工具栏
|
||||||
|
kk.xlsxshowtoolbar = true
|
||||||
|
|
||||||
|
# 首页是否显示key密钥 默认为false(禁用)
|
||||||
|
kk.isshowkey = true
|
||||||
|
|
||||||
|
# 预览html文件 是否启用JavaScript 默认为true(启用)
|
||||||
|
kk.scriptjs = true
|
||||||
|
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# 十四、文件类型分类配置(支持动态配置)
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
# 纯文本文件类型,直接显示
|
||||||
|
simText = ${KK_SIMTEXT:txt,html,htm,asp,jsp,xml,json,properties,md,gitignore,log,java,py,c,cpp,sql,sh,bat,m,bas,prg,cmd}
|
||||||
@@ -33,13 +33,15 @@ public enum FileType {
|
|||||||
EPUB("epubFilePreviewImpl"),
|
EPUB("epubFilePreviewImpl"),
|
||||||
BPMN("bpmnFilePreviewImpl"),
|
BPMN("bpmnFilePreviewImpl"),
|
||||||
DCM("dcmFilePreviewImpl"),
|
DCM("dcmFilePreviewImpl"),
|
||||||
|
MSG("msgFilePreviewImpl"),
|
||||||
DRAWIO("drawioFilePreviewImpl");
|
DRAWIO("drawioFilePreviewImpl");
|
||||||
|
|
||||||
private static final String[] OFFICE_TYPES = {"docx", "wps", "doc", "docm", "xls", "xlsx", "csv" ,"xlsm", "ppt", "pptx", "vsd", "rtf", "odt", "wmf", "emf", "dps", "et", "ods", "ots", "tsv", "odp", "otp", "sxi", "ott", "vsdx", "fodt", "fods", "xltx","tga","psd","dotm","ett","xlt","xltm","wpt","dot","xlam","dotx","xla","pages", "eps"};
|
private static final String[] OFFICE_TYPES = {"docx", "wps", "doc", "docm", "xls", "xlsx", "csv" ,"xlsm", "ppt", "pptx", "vsd", "rtf", "odt", "wmf", "emf", "dps", "et", "ods", "ots", "tsv", "odp", "otp", "sxi", "ott", "vsdx", "fodt", "fods", "xltx","tga","psd","dotm","ett","xlt","xltm","wpt","dot","xlam","dotx","xla","pages", "eps"};
|
||||||
private static final String[] PICTURE_TYPES = {"jpg", "jpeg", "png", "gif", "bmp", "ico", "jfif", "webp"};
|
private static final String[] PICTURE_TYPES = {"jpg", "jpeg", "png", "gif", "bmp", "ico", "jfif", "webp", "heic", "avif"};
|
||||||
private static final String[] ARCHIVE_TYPES = {"rar", "zip", "jar", "7-zip", "tar", "gzip", "7z"};
|
private static final String[] ARCHIVE_TYPES = {"rar", "zip", "jar", "7-zip", "tar", "gzip", "7z"};
|
||||||
private static final String[] ONLINE3D_TYPES = {"obj", "3ds", "stl", "ply", "off", "3dm", "fbx", "dae", "wrl", "3mf", "ifc","glb","o3dv","gltf","stp","bim","fcstd","step","iges","brep"};
|
private static final String[] ONLINE3D_TYPES = {"obj", "3ds", "stl", "ply", "off", "3dm", "fbx", "dae", "wrl", "3mf", "ifc","glb","o3dv","gltf","stp","bim","fcstd","step","iges","brep"};
|
||||||
private static final String[] EML_TYPES = {"eml"};
|
private static final String[] EML_TYPES = {"eml"};
|
||||||
|
private static final String[] MSG_TYPES = {"msg"};
|
||||||
private static final String[] XMIND_TYPES = {"xmind"};
|
private static final String[] XMIND_TYPES = {"xmind"};
|
||||||
private static final String[] EPUB_TYPES = {"epub"};
|
private static final String[] EPUB_TYPES = {"epub"};
|
||||||
private static final String[] DCM_TYPES = {"dcm"};
|
private static final String[] DCM_TYPES = {"dcm"};
|
||||||
@@ -96,6 +98,9 @@ public enum FileType {
|
|||||||
for (String eml : EML_TYPES) {
|
for (String eml : EML_TYPES) {
|
||||||
FILE_TYPE_MAPPER.put(eml, FileType.EML);
|
FILE_TYPE_MAPPER.put(eml, FileType.EML);
|
||||||
}
|
}
|
||||||
|
for (String msg : MSG_TYPES) {
|
||||||
|
FILE_TYPE_MAPPER.put(msg, FileType.MSG);
|
||||||
|
}
|
||||||
for (String xmind : XMIND_TYPES) {
|
for (String xmind : XMIND_TYPES) {
|
||||||
FILE_TYPE_MAPPER.put(xmind, FileType.XMIND);
|
FILE_TYPE_MAPPER.put(xmind, FileType.XMIND);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ public class CompressFileReader {
|
|||||||
|
|
||||||
FileType type = FileType.typeFromUrl(filePathInsideArchive.toString());
|
FileType type = FileType.typeFromUrl(filePathInsideArchive.toString());
|
||||||
if (type.equals(FileType.PICTURE)) { //图片缓存到集合,为了特殊符号需要进行编码
|
if (type.equals(FileType.PICTURE)) { //图片缓存到集合,为了特殊符号需要进行编码
|
||||||
imgUrls.add(baseUrl + URLEncoder.encode(fileName + packagePath+"/"+ folderPath.relativize(filePathInsideArchive).toString().replace("\\", "/"), "UTF-8"));
|
imgUrls.add(baseUrl + URLEncoder.encode(fileName + packagePath+"/"+ folderPath.relativize(filePathInsideArchive).toString().replace("\\", "/"), StandardCharsets.UTF_8).replaceAll("%2F", "/"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -264,8 +264,13 @@ public class FileHandlerService {
|
|||||||
.replaceAll("%3F", "?")
|
.replaceAll("%3F", "?")
|
||||||
.replaceAll("%26", "&")
|
.replaceAll("%26", "&")
|
||||||
.replaceAll("%3D", "=");
|
.replaceAll("%3D", "=");
|
||||||
|
|
||||||
}
|
}
|
||||||
originFileName = KkFileUtils.htmlEscape(originFileName); //文件名处理
|
originFileName = KkFileUtils.htmlEscape(originFileName); //文件名处理
|
||||||
|
if (!KkFileUtils.validateFileNameLength(originFileName)) {
|
||||||
|
// 处理逻辑:抛出异常、记录日志、返回错误等
|
||||||
|
throw new IllegalArgumentException("文件名超过系统限制");
|
||||||
|
}
|
||||||
boolean isHtmlView = suffix.equalsIgnoreCase("xls") || suffix.equalsIgnoreCase("xlsx") || suffix.equalsIgnoreCase("csv") || suffix.equalsIgnoreCase("xlsm") || suffix.equalsIgnoreCase("xlt") || suffix.equalsIgnoreCase("xltm") || suffix.equalsIgnoreCase("et") || suffix.equalsIgnoreCase("ett") || suffix.equalsIgnoreCase("xlam");
|
boolean isHtmlView = suffix.equalsIgnoreCase("xls") || suffix.equalsIgnoreCase("xlsx") || suffix.equalsIgnoreCase("csv") || suffix.equalsIgnoreCase("xlsm") || suffix.equalsIgnoreCase("xlt") || suffix.equalsIgnoreCase("xltm") || suffix.equalsIgnoreCase("et") || suffix.equalsIgnoreCase("ett") || suffix.equalsIgnoreCase("xlam");
|
||||||
String cacheFilePrefixName = null;
|
String cacheFilePrefixName = null;
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -34,6 +34,9 @@ public interface FilePreview {
|
|||||||
String NOT_SUPPORTED_FILE_PAGE = "fileNotSupported";
|
String NOT_SUPPORTED_FILE_PAGE = "fileNotSupported";
|
||||||
String XLSX_FILE_PREVIEW_PAGE = "officeweb";
|
String XLSX_FILE_PREVIEW_PAGE = "officeweb";
|
||||||
String CSV_FILE_PREVIEW_PAGE = "csv";
|
String CSV_FILE_PREVIEW_PAGE = "csv";
|
||||||
|
String MSG_FILE_PREVIEW_PAGE = "msg";
|
||||||
|
String HEIC_FILE_PREVIEW_PAGE = "heic";
|
||||||
|
String CADVIEWER_FILE_PREVIEW_PAGE = "cadviewer";
|
||||||
String WAITING_FILE_PREVIEW_PAGE = "waiting";
|
String WAITING_FILE_PREVIEW_PAGE = "waiting";
|
||||||
|
|
||||||
String filePreviewHandle(String url, Model model, FileAttribute fileAttribute);
|
String filePreviewHandle(String url, Model model, FileAttribute fileAttribute);
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ import java.util.*;
|
|||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PDF转JPG服务 - JDK 21 高性能优化版本(使用虚拟线程和结构化并发)
|
* PDF转JPG服务 - JDK 21 高性能优化版本(使用虚拟线程和结构化并发)
|
||||||
@@ -59,8 +58,7 @@ public class PdfToJpgService {
|
|||||||
// JDK 21: 使用虚拟线程调度器
|
// JDK 21: 使用虚拟线程调度器
|
||||||
private final ScheduledExecutorService virtualCacheCleanupScheduler;
|
private final ScheduledExecutorService virtualCacheCleanupScheduler;
|
||||||
|
|
||||||
// 使用读写锁保护缓存操作
|
|
||||||
private final ReentrantReadWriteLock cacheLock = new ReentrantReadWriteLock();
|
|
||||||
|
|
||||||
// 加密PDF缓存记录类
|
// 加密PDF缓存记录类
|
||||||
private static class EncryptedPdfCache {
|
private static class EncryptedPdfCache {
|
||||||
@@ -286,49 +284,6 @@ public class PdfToJpgService {
|
|||||||
logger.info("缓存清理任务已启动(每5分钟执行一次)");
|
logger.info("缓存清理任务已启动(每5分钟执行一次)");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 启动性能监控
|
|
||||||
*/
|
|
||||||
private void startPerformanceMonitoring() {
|
|
||||||
// 每10分钟记录一次性能统计
|
|
||||||
virtualCacheCleanupScheduler.scheduleAtFixedRate(() -> {
|
|
||||||
try {
|
|
||||||
logPerformanceStatistics();
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.error("性能监控任务执行失败", e);
|
|
||||||
}
|
|
||||||
}, 5, 10, TimeUnit.MINUTES);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 记录性能统计信息
|
|
||||||
*/
|
|
||||||
private void logPerformanceStatistics() {
|
|
||||||
try {
|
|
||||||
// 收集性能指标
|
|
||||||
int runningTasksCount = runningTasks.size();
|
|
||||||
int activeTasks = activeTaskCount.get();
|
|
||||||
int totalCompleted = totalCompletedTasks.get();
|
|
||||||
int cacheSize = encryptedPdfCacheMap.size();
|
|
||||||
|
|
||||||
// 计算内存使用
|
|
||||||
long totalMemory = Runtime.getRuntime().totalMemory();
|
|
||||||
long freeMemory = Runtime.getRuntime().freeMemory();
|
|
||||||
long usedMemory = totalMemory - freeMemory;
|
|
||||||
|
|
||||||
logger.info(
|
|
||||||
"PDF转换服务性能统计 - 运行中任务数: {}, 活跃任务数: {}, 累计完成任务数: {}, " +
|
|
||||||
"内存缓存数量: {}, 内存使用: {} MB / {} MB ({}%), 虚拟线程: {}",
|
|
||||||
runningTasksCount, activeTasks, totalCompleted, cacheSize,
|
|
||||||
usedMemory / 1024 / 1024, totalMemory / 1024 / 1024,
|
|
||||||
(usedMemory * 100 / totalMemory),
|
|
||||||
Thread.currentThread().isVirtual() ? "是" : "否"
|
|
||||||
);
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.error("记录性能统计时发生异常", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 监控缓存统计信息
|
* 监控缓存统计信息
|
||||||
@@ -527,84 +482,11 @@ public class PdfToJpgService {
|
|||||||
return imageUrls;
|
return imageUrls;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* PDF转JPG - 异步版本(虚拟线程优化)
|
|
||||||
|
|
||||||
public CompletableFuture<List<String>> pdf2jpgAsync(String fileNameFilePath, String pdfFilePath,
|
|
||||||
String pdfName, FileAttribute fileAttribute) {
|
|
||||||
CompletableFuture<List<String>> future = new CompletableFuture<>();
|
|
||||||
|
|
||||||
// 尝试获取信号量,如果获取不到,则立即拒绝任务
|
|
||||||
if (!concurrentTaskSemaphore.tryAcquire()) {
|
|
||||||
future.completeExceptionally(new RejectedExecutionException("系统繁忙,请稍后再试"));
|
|
||||||
return future;
|
|
||||||
}
|
|
||||||
|
|
||||||
// JDK 21: 使用虚拟线程提交任务
|
|
||||||
Future<?> taskFuture = virtualThreadExecutor.submit(() -> {
|
|
||||||
try {
|
|
||||||
List<String> result = pdf2jpg(fileNameFilePath, pdfFilePath, pdfName, fileAttribute);
|
|
||||||
future.complete(result);
|
|
||||||
} catch (Exception e) {
|
|
||||||
future.completeExceptionally(e);
|
|
||||||
} finally {
|
|
||||||
// 必须在finally中释放信号量
|
|
||||||
concurrentTaskSemaphore.release();
|
|
||||||
runningTasks.remove(pdfName);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 记录正在运行的任务
|
|
||||||
runningTasks.put(pdfName, taskFuture);
|
|
||||||
|
|
||||||
// 设置超时检查(使用虚拟线程)
|
|
||||||
scheduleVirtualTimeoutCheck(pdfName, future, taskFuture);
|
|
||||||
|
|
||||||
return future;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* 虚拟线程超时检查
|
|
||||||
*/
|
|
||||||
private void scheduleVirtualTimeoutCheck(String fileName, CompletableFuture<List<String>> taskFuture,
|
|
||||||
Future<?> future) {
|
|
||||||
CompletableFuture.runAsync(() -> {
|
|
||||||
try {
|
|
||||||
int timeout = calculateTimeoutByFileName();
|
|
||||||
taskFuture.get(timeout, TimeUnit.SECONDS);
|
|
||||||
} catch (TimeoutException e) {
|
|
||||||
handleConversionTimeout(fileName, taskFuture, future);
|
|
||||||
} catch (Exception e) {
|
|
||||||
// 正常完成或异常
|
|
||||||
}
|
|
||||||
}, virtualThreadExecutor);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理转换超时
|
|
||||||
*/
|
|
||||||
private void handleConversionTimeout(String fileName, CompletableFuture<List<String>> taskFuture,
|
|
||||||
Future<?> future) {
|
|
||||||
logger.error("PDF转换超时: {}", fileName);
|
|
||||||
|
|
||||||
// 取消正在运行的任务
|
|
||||||
if (future != null && !future.isDone()) {
|
|
||||||
boolean cancelled = future.cancel(true);
|
|
||||||
logger.info("尝试取消PDF转换任务 {}: {}", fileName, cancelled ? "成功" : "失败");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 从运行任务列表中移除
|
|
||||||
runningTasks.remove(fileName);
|
|
||||||
|
|
||||||
// 完成Future
|
|
||||||
taskFuture.completeExceptionally(new TimeoutException("PDF转换超时: " + fileName));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PDF转JPG - 高性能主方法
|
* PDF转JPG - 高性能主方法
|
||||||
*/
|
*/
|
||||||
public List<String> pdf2jpg(String fileNameFilePath, String pdfFilePath,
|
public List<String> pdf2jpg(String fileNameFilePath, String pdfFilePath,
|
||||||
String pdfName, FileAttribute fileAttribute) throws Exception {
|
FileAttribute fileAttribute) throws Exception {
|
||||||
boolean forceUpdatedCache = fileAttribute.forceUpdatedCache();
|
boolean forceUpdatedCache = fileAttribute.forceUpdatedCache();
|
||||||
boolean usePasswordCache = fileAttribute.getUsePasswordCache();
|
boolean usePasswordCache = fileAttribute.getUsePasswordCache();
|
||||||
String filePassword = fileAttribute.getFilePassword();
|
String filePassword = fileAttribute.getFilePassword();
|
||||||
@@ -951,12 +833,6 @@ public class PdfToJpgService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据文件名计算超时时间
|
|
||||||
*/
|
|
||||||
private int calculateTimeoutByFileName() {
|
|
||||||
return ConfigConstants.getPdfTimeoutMedium();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 按页码排序
|
* 按页码排序
|
||||||
@@ -975,107 +851,5 @@ public class PdfToJpgService {
|
|||||||
return sortedImageUrls;
|
return sortedImageUrls;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 强制取消指定文件的转换任务
|
|
||||||
*/
|
|
||||||
public boolean cancelConversion(String fileName) {
|
|
||||||
Future<?> future = runningTasks.get(fileName);
|
|
||||||
if (future != null) {
|
|
||||||
boolean cancelled = future.cancel(true);
|
|
||||||
if (cancelled) {
|
|
||||||
logger.info("成功取消PDF转换任务: {}", fileName);
|
|
||||||
runningTasks.remove(fileName);
|
|
||||||
}
|
|
||||||
return cancelled;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取正在运行的任务数量
|
|
||||||
*/
|
|
||||||
public int getRunningTaskCount() {
|
|
||||||
return runningTasks.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取所有正在运行的文件名
|
|
||||||
*/
|
|
||||||
public Set<String> getRunningTasks() {
|
|
||||||
return new HashSet<>(runningTasks.keySet());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取缓存统计信息(用于监控)
|
|
||||||
*/
|
|
||||||
public Map<String, Object> getCacheStatistics() {
|
|
||||||
Map<String, Object> stats = new HashMap<>();
|
|
||||||
cacheLock.readLock().lock();
|
|
||||||
try {
|
|
||||||
stats.put("cacheSize", encryptedPdfCacheMap.size());
|
|
||||||
stats.put("runningTasks", runningTasks.size());
|
|
||||||
stats.put("activeTasks", activeTaskCount.get());
|
|
||||||
stats.put("totalCompleted", totalCompletedTasks.get());
|
|
||||||
|
|
||||||
// 计算缓存过期情况
|
|
||||||
long expireTime = 10 * 60 * 1000L;
|
|
||||||
int expiredCount = 0;
|
|
||||||
for (EncryptedPdfCache cache : encryptedPdfCacheMap.values()) {
|
|
||||||
if (cache.isExpired(expireTime)) {
|
|
||||||
expiredCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stats.put("expiredCaches", expiredCount);
|
|
||||||
|
|
||||||
} finally {
|
|
||||||
cacheLock.readLock().unlock();
|
|
||||||
}
|
|
||||||
return stats;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 手动清理所有过期缓存(供管理接口调用)
|
|
||||||
*/
|
|
||||||
public int cleanupAllExpiredCaches() {
|
|
||||||
try {
|
|
||||||
// 使用虚拟线程执行清理
|
|
||||||
Future<Integer> future = virtualThreadExecutor.submit(() -> {
|
|
||||||
long expireTime = 10 * 60 * 1000L;
|
|
||||||
List<String> expiredKeys = new ArrayList<>();
|
|
||||||
|
|
||||||
cacheLock.readLock().lock();
|
|
||||||
try {
|
|
||||||
for (Map.Entry<String, EncryptedPdfCache> entry : encryptedPdfCacheMap.entrySet()) {
|
|
||||||
if (entry.getValue().isExpired(expireTime)) {
|
|
||||||
expiredKeys.add(entry.getKey());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
cacheLock.readLock().unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 清理
|
|
||||||
int cleaned = 0;
|
|
||||||
for (String key : expiredKeys) {
|
|
||||||
EncryptedPdfCache cache = encryptedPdfCacheMap.remove(key);
|
|
||||||
if (cache != null) {
|
|
||||||
try {
|
|
||||||
deleteCacheFolder(cache.outputFolder());
|
|
||||||
cleaned++;
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.warn("清理缓存文件失败: {}", cache.outputFolder(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return cleaned;
|
|
||||||
});
|
|
||||||
|
|
||||||
return future.get(30, TimeUnit.SECONDS);
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.error("手动清理缓存失败", e);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -6,10 +6,7 @@ import cn.keking.model.ReturnResponse;
|
|||||||
import cn.keking.service.CadToPdfService;
|
import cn.keking.service.CadToPdfService;
|
||||||
import cn.keking.service.FileHandlerService;
|
import cn.keking.service.FileHandlerService;
|
||||||
import cn.keking.service.FilePreview;
|
import cn.keking.service.FilePreview;
|
||||||
import cn.keking.utils.DownloadUtils;
|
import cn.keking.utils.*;
|
||||||
import cn.keking.utils.FileConvertStatusManager;
|
|
||||||
import cn.keking.utils.KkFileUtils;
|
|
||||||
import cn.keking.utils.WebUtils;
|
|
||||||
import cn.keking.web.filter.BaseUrlFilter;
|
import cn.keking.web.filter.BaseUrlFilter;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@@ -78,12 +75,14 @@ public class CadFilePreviewImpl implements FilePreview {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String filePath = response.getContent();
|
String filePath = response.getContent();
|
||||||
|
int refreshSchedule = ConfigConstants.getTime();
|
||||||
if (StringUtils.hasText(outFilePath)) {
|
if (StringUtils.hasText(outFilePath)) {
|
||||||
try {
|
try {
|
||||||
// 启动异步转换,并添加回调处理
|
// 启动异步转换,并添加回调处理
|
||||||
startAsyncConversion(filePath, outFilePath, cacheName, fileAttribute);
|
startAsyncConversion(filePath, outFilePath, cacheName, fileAttribute);
|
||||||
// 返回等待页面
|
// 返回等待页面
|
||||||
model.addAttribute("fileName", fileName);
|
model.addAttribute("fileName", fileName);
|
||||||
|
model.addAttribute("time", refreshSchedule);
|
||||||
model.addAttribute("message", "文件正在转换中,请稍候...");
|
model.addAttribute("message", "文件正在转换中,请稍候...");
|
||||||
return WAITING_FILE_PREVIEW_PAGE;
|
return WAITING_FILE_PREVIEW_PAGE;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@@ -101,14 +100,33 @@ public class CadFilePreviewImpl implements FilePreview {
|
|||||||
*/
|
*/
|
||||||
private void startAsyncConversion(String filePath, String outFilePath,
|
private void startAsyncConversion(String filePath, String outFilePath,
|
||||||
String cacheName, FileAttribute fileAttribute) {
|
String cacheName, FileAttribute fileAttribute) {
|
||||||
|
|
||||||
|
//获取cad转换路径
|
||||||
|
String cadConverterPath = ConfigConstants.getCadConverterPath();
|
||||||
|
int conversionModule= ConfigConstants.getConversionModule();
|
||||||
|
if(cadConverterPath.equals("false")){
|
||||||
|
//默认aspose-cad
|
||||||
|
conversionModule = 1;
|
||||||
|
}
|
||||||
|
CompletableFuture<Boolean> conversionFuture;
|
||||||
// 启动异步转换
|
// 启动异步转换
|
||||||
CompletableFuture<Boolean> conversionFuture = cadtopdfservice.cadToPdfAsync(
|
if(conversionModule==2){
|
||||||
|
conversionFuture = cadtopdfservice.cadViewerConvert(
|
||||||
|
filePath,
|
||||||
|
outFilePath,
|
||||||
|
cadConverterPath,
|
||||||
|
ConfigConstants.getCadPreviewType(),
|
||||||
|
cacheName
|
||||||
|
);
|
||||||
|
}else {
|
||||||
|
conversionFuture = cadtopdfservice.cadToPdfAsync(
|
||||||
filePath,
|
filePath,
|
||||||
outFilePath,
|
outFilePath,
|
||||||
cacheName,
|
cacheName,
|
||||||
ConfigConstants.getCadPreviewType(),
|
ConfigConstants.getCadPreviewType(),
|
||||||
fileAttribute
|
fileAttribute
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// 添加转换完成后的回调
|
// 添加转换完成后的回调
|
||||||
conversionFuture.whenCompleteAsync((success, throwable) -> {
|
conversionFuture.whenCompleteAsync((success, throwable) -> {
|
||||||
@@ -144,15 +162,20 @@ public class CadFilePreviewImpl implements FilePreview {
|
|||||||
FileAttribute fileAttribute) {
|
FileAttribute fileAttribute) {
|
||||||
cacheName = WebUtils.encodeFileName(cacheName);
|
cacheName = WebUtils.encodeFileName(cacheName);
|
||||||
String baseUrl = BaseUrlFilter.getBaseUrl();
|
String baseUrl = BaseUrlFilter.getBaseUrl();
|
||||||
|
int conversionModule= ConfigConstants.getConversionModule();
|
||||||
if ("tif".equalsIgnoreCase(cadPreviewType)) {
|
if ("tif".equalsIgnoreCase(cadPreviewType)) {
|
||||||
model.addAttribute("currentUrl", cacheName);
|
model.addAttribute("currentUrl", cacheName);
|
||||||
return TIFF_FILE_PREVIEW_PAGE;
|
return TIFF_FILE_PREVIEW_PAGE;
|
||||||
} else if ("svg".equalsIgnoreCase(cadPreviewType)) {
|
} else if ("svg".equalsIgnoreCase(cadPreviewType)) {
|
||||||
model.addAttribute("currentUrl", cacheName);
|
model.addAttribute("currentUrl", cacheName);
|
||||||
|
if(conversionModule==2){
|
||||||
|
return CADVIEWER_FILE_PREVIEW_PAGE;
|
||||||
|
}else {
|
||||||
return SVG_FILE_PREVIEW_PAGE;
|
return SVG_FILE_PREVIEW_PAGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if (baseUrl != null && (OFFICE_PREVIEW_TYPE_IMAGE.equals(officePreviewType) ||
|
if (baseUrl != null && (OFFICE_PREVIEW_TYPE_IMAGE.equals(officePreviewType) ||
|
||||||
OFFICE_PREVIEW_TYPE_ALL_IMAGES.equals(officePreviewType))) {
|
OFFICE_PREVIEW_TYPE_ALL_IMAGES.equals(officePreviewType))) {
|
||||||
return officefilepreviewimpl.getPreviewType(model, fileAttribute, officePreviewType, cacheName, outFilePath);
|
return officefilepreviewimpl.getPreviewType(model, fileAttribute, officePreviewType, cacheName, outFilePath);
|
||||||
|
|||||||
@@ -22,10 +22,8 @@ public class CodeFilePreviewImpl implements FilePreview {
|
|||||||
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
|
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
|
||||||
filePreviewHandle.filePreviewHandle(url, model, fileAttribute);
|
filePreviewHandle.filePreviewHandle(url, model, fileAttribute);
|
||||||
String suffix = fileAttribute.getSuffix();
|
String suffix = fileAttribute.getSuffix();
|
||||||
if(suffix.equalsIgnoreCase("htm") || suffix.equalsIgnoreCase("html") || suffix.equalsIgnoreCase("shtml") ){
|
boolean isHtmlFile = suffix.equalsIgnoreCase("htm") || suffix.equalsIgnoreCase("html") || suffix.equalsIgnoreCase("shtml");
|
||||||
model.addAttribute("pdfUrl", url);
|
model.addAttribute("isHtmlFile", isHtmlFile);
|
||||||
return TXT_FILE_PREVIEW_PAGE; //直接输出html
|
|
||||||
}
|
|
||||||
return CODE_FILE_PREVIEW_PAGE;
|
return CODE_FILE_PREVIEW_PAGE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package cn.keking.service.impl;
|
package cn.keking.service.impl;
|
||||||
|
|
||||||
|
import cn.keking.config.ConfigConstants;
|
||||||
import cn.keking.model.FileAttribute;
|
import cn.keking.model.FileAttribute;
|
||||||
import cn.keking.model.ReturnResponse;
|
import cn.keking.model.ReturnResponse;
|
||||||
import cn.keking.service.FileHandlerService;
|
import cn.keking.service.FileHandlerService;
|
||||||
@@ -10,6 +11,7 @@ import org.springframework.stereotype.Component;
|
|||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.ui.Model;
|
import org.springframework.ui.Model;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
|
import org.springframework.util.ObjectUtils;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -32,17 +34,26 @@ public class CommonPreviewImpl implements FilePreview {
|
|||||||
@Override
|
@Override
|
||||||
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
|
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
|
||||||
// 不是http开头,浏览器不能直接访问,需下载到本地
|
// 不是http开头,浏览器不能直接访问,需下载到本地
|
||||||
|
boolean forceUpdatedCache = fileAttribute.forceUpdatedCache(); //是否启用强制更新命令
|
||||||
|
String fileName = fileAttribute.getName(); //获取原始文件名
|
||||||
|
if (forceUpdatedCache || !fileHandlerService.listConvertedFiles().containsKey(fileName) || !ConfigConstants.isCacheEnabled()) {
|
||||||
if (url != null && !url.toLowerCase().startsWith("http")) {
|
if (url != null && !url.toLowerCase().startsWith("http")) {
|
||||||
ReturnResponse<String> response = DownloadUtils.downLoad(fileAttribute, null);
|
ReturnResponse<String> response = DownloadUtils.downLoad(fileAttribute, fileName);
|
||||||
if (response.isFailure()) {
|
if (response.isFailure()) {
|
||||||
return otherFilePreview.notSupportedFile(model, fileAttribute, response.getMsg());
|
return otherFilePreview.notSupportedFile(model, fileAttribute, response.getMsg());
|
||||||
} else {
|
} else {
|
||||||
String file = fileHandlerService.getRelativePath(response.getContent());
|
String file = fileHandlerService.getRelativePath(response.getContent());
|
||||||
model.addAttribute("currentUrl", file);
|
model.addAttribute("currentUrl", file);
|
||||||
|
if (ConfigConstants.isCacheEnabled()) {
|
||||||
|
fileHandlerService.addConvertedFile(fileName, file);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
model.addAttribute("currentUrl", url);
|
model.addAttribute("currentUrl", url);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
model.addAttribute("currentUrl", fileHandlerService.getConvertedFile(fileName));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -97,8 +97,10 @@ public class MediaFilePreviewImpl implements FilePreview {
|
|||||||
try {
|
try {
|
||||||
// 启动异步转换,并添加回调处理
|
// 启动异步转换,并添加回调处理
|
||||||
startAsyncConversion(filePath, outFilePath, cacheName, fileAttribute);
|
startAsyncConversion(filePath, outFilePath, cacheName, fileAttribute);
|
||||||
|
int refreshSchedule = ConfigConstants.getTime();
|
||||||
// 返回等待页面
|
// 返回等待页面
|
||||||
model.addAttribute("fileName", fileName);
|
model.addAttribute("fileName", fileName);
|
||||||
|
model.addAttribute("time", refreshSchedule);
|
||||||
model.addAttribute("message", "视频文件正在转换中,请稍候...");
|
model.addAttribute("message", "视频文件正在转换中,请稍候...");
|
||||||
return WAITING_FILE_PREVIEW_PAGE;
|
return WAITING_FILE_PREVIEW_PAGE;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package cn.keking.service.impl;
|
||||||
|
|
||||||
|
import cn.keking.model.FileAttribute;
|
||||||
|
import cn.keking.service.FilePreview;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.ui.Model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dcm 文件处理
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class MsgFilePreviewImpl implements FilePreview {
|
||||||
|
|
||||||
|
private final CommonPreviewImpl commonPreview;
|
||||||
|
|
||||||
|
public MsgFilePreviewImpl(CommonPreviewImpl commonPreview) {
|
||||||
|
this.commonPreview = commonPreview;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
|
||||||
|
commonPreview.filePreviewHandle(url,model,fileAttribute);
|
||||||
|
return MSG_FILE_PREVIEW_PAGE;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -112,8 +112,10 @@ public class OfficeFilePreviewImpl implements FilePreview {
|
|||||||
try {
|
try {
|
||||||
// 启动异步转换
|
// 启动异步转换
|
||||||
startAsyncOfficeConversion(filePath, outFilePath, cacheName, fileAttribute, officePreviewType);
|
startAsyncOfficeConversion(filePath, outFilePath, cacheName, fileAttribute, officePreviewType);
|
||||||
|
int refreshSchedule = ConfigConstants.getTime();
|
||||||
// 返回等待页面
|
// 返回等待页面
|
||||||
model.addAttribute("fileName", fileName);
|
model.addAttribute("fileName", fileName);
|
||||||
|
model.addAttribute("time", refreshSchedule);
|
||||||
model.addAttribute("message", "文件正在转换中,请稍候...");
|
model.addAttribute("message", "文件正在转换中,请稍候...");
|
||||||
return WAITING_FILE_PREVIEW_PAGE;
|
return WAITING_FILE_PREVIEW_PAGE;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@@ -160,7 +162,7 @@ public class OfficeFilePreviewImpl implements FilePreview {
|
|||||||
if (OFFICE_PREVIEW_TYPE_IMAGE.equals(officePreviewType) ||
|
if (OFFICE_PREVIEW_TYPE_IMAGE.equals(officePreviewType) ||
|
||||||
OFFICE_PREVIEW_TYPE_ALL_IMAGES.equals(officePreviewType)) {
|
OFFICE_PREVIEW_TYPE_ALL_IMAGES.equals(officePreviewType)) {
|
||||||
FileConvertStatusManager.updateProgress(cacheName, "正在转换PDF为图片", 90);
|
FileConvertStatusManager.updateProgress(cacheName, "正在转换PDF为图片", 90);
|
||||||
imageUrls = pdftojpgservice.pdf2jpg(outFilePath, outFilePath, cacheName, fileAttribute);
|
imageUrls = pdftojpgservice.pdf2jpg(outFilePath, outFilePath, fileAttribute);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 缓存处理
|
// 缓存处理
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import cn.keking.service.FilePreview;
|
|||||||
import cn.keking.service.PdfToJpgService;
|
import cn.keking.service.PdfToJpgService;
|
||||||
import cn.keking.utils.DownloadUtils;
|
import cn.keking.utils.DownloadUtils;
|
||||||
import cn.keking.utils.FileConvertStatusManager;
|
import cn.keking.utils.FileConvertStatusManager;
|
||||||
import cn.keking.utils.KkFileUtils;
|
|
||||||
import cn.keking.utils.WebUtils;
|
import cn.keking.utils.WebUtils;
|
||||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||||
import org.apache.poi.EncryptedDocumentException;
|
import org.apache.poi.EncryptedDocumentException;
|
||||||
@@ -37,16 +36,19 @@ public class PdfFilePreviewImpl implements FilePreview {
|
|||||||
private final FileHandlerService fileHandlerService;
|
private final FileHandlerService fileHandlerService;
|
||||||
private final OtherFilePreviewImpl otherFilePreview;
|
private final OtherFilePreviewImpl otherFilePreview;
|
||||||
private final PdfToJpgService pdftojpgservice;
|
private final PdfToJpgService pdftojpgservice;
|
||||||
|
private final OfficeFilePreviewImpl officefilepreviewimpl;
|
||||||
|
|
||||||
// 用于处理回调的线程池
|
// 用于处理回调的线程池
|
||||||
private static final ExecutorService callbackExecutor = Executors.newFixedThreadPool(3);
|
private static final ExecutorService callbackExecutor = Executors.newFixedThreadPool(3);
|
||||||
|
|
||||||
public PdfFilePreviewImpl(FileHandlerService fileHandlerService,
|
public PdfFilePreviewImpl(FileHandlerService fileHandlerService,
|
||||||
OtherFilePreviewImpl otherFilePreview,
|
OtherFilePreviewImpl otherFilePreview,
|
||||||
|
OfficeFilePreviewImpl officefilepreviewimpl,
|
||||||
PdfToJpgService pdftojpgservice) {
|
PdfToJpgService pdftojpgservice) {
|
||||||
this.fileHandlerService = fileHandlerService;
|
this.fileHandlerService = fileHandlerService;
|
||||||
this.otherFilePreview = otherFilePreview;
|
this.otherFilePreview = otherFilePreview;
|
||||||
this.pdftojpgservice = pdftojpgservice;
|
this.pdftojpgservice = pdftojpgservice;
|
||||||
|
this.officefilepreviewimpl = officefilepreviewimpl;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -56,35 +58,25 @@ public class PdfFilePreviewImpl implements FilePreview {
|
|||||||
boolean forceUpdatedCache = fileAttribute.forceUpdatedCache(); //是否启用强制更新命令
|
boolean forceUpdatedCache = fileAttribute.forceUpdatedCache(); //是否启用强制更新命令
|
||||||
String outFilePath = fileAttribute.getOutFilePath(); //生成的文件路径
|
String outFilePath = fileAttribute.getOutFilePath(); //生成的文件路径
|
||||||
String originFilePath; //原始文件路径
|
String originFilePath; //原始文件路径
|
||||||
String cacheName = fileAttribute.getCacheName();
|
String cacheName = pdfName+officePreviewType;
|
||||||
String filePassword = fileAttribute.getFilePassword(); // 获取密码
|
String filePassword = fileAttribute.getFilePassword(); // 获取密码
|
||||||
int refreshSchedule = ConfigConstants.getTime();
|
|
||||||
// 查询转换状态
|
// 查询转换状态
|
||||||
FileConvertStatusManager.ConvertStatus status = FileConvertStatusManager.getConvertStatus(cacheName);
|
String statusResult = officefilepreviewimpl.checkAndHandleConvertStatus(model, pdfName, cacheName, fileAttribute);
|
||||||
if (status != null) {
|
if (statusResult != null) {
|
||||||
if (status.getStatus() == FileConvertStatusManager.Status.CONVERTING) {
|
return statusResult;
|
||||||
// 正在转换中,返回等待页面
|
|
||||||
model.addAttribute("fileName", pdfName);
|
|
||||||
model.addAttribute("time", refreshSchedule);
|
|
||||||
model.addAttribute("message", status.getRealTimeMessage());
|
|
||||||
return WAITING_FILE_PREVIEW_PAGE;
|
|
||||||
} else if (status.getStatus() == FileConvertStatusManager.Status.TIMEOUT) {
|
|
||||||
// 超时状态,不允许重新转换
|
|
||||||
return otherFilePreview.notSupportedFile(model, fileAttribute, "文件转换已超时,无法继续转换");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean jiami=false;
|
boolean jiami=false;
|
||||||
if(!ObjectUtils.isEmpty(filePassword)){
|
if(!ObjectUtils.isEmpty(filePassword)){
|
||||||
jiami=pdftojpgservice.hasEncryptedPdfCacheSimple(outFilePath);
|
jiami=pdftojpgservice.hasEncryptedPdfCacheSimple(outFilePath);
|
||||||
}
|
}
|
||||||
if (OfficeFilePreviewImpl.OFFICE_PREVIEW_TYPE_IMAGE.equals(officePreviewType) ||
|
if (OfficeFilePreviewImpl.OFFICE_PREVIEW_TYPE_IMAGE.equals(officePreviewType) ||
|
||||||
OfficeFilePreviewImpl.OFFICE_PREVIEW_TYPE_ALL_IMAGES.equals(officePreviewType)) {
|
OfficeFilePreviewImpl.OFFICE_PREVIEW_TYPE_ALL_IMAGES.equals(officePreviewType)) {
|
||||||
|
|
||||||
// 判断之前是否已转换过,如果转换过,直接返回,否则执行转换
|
// 判断之前是否已转换过,如果转换过,直接返回,否则执行转换
|
||||||
if (forceUpdatedCache || !fileHandlerService.listConvertedFiles().containsKey(cacheName) || !ConfigConstants.isCacheEnabled()) {
|
if (forceUpdatedCache || !fileHandlerService.listConvertedFiles().containsKey(cacheName) || !ConfigConstants.isCacheEnabled()) {
|
||||||
if(jiami){
|
if(jiami){
|
||||||
return renderPreview(model, cacheName, outFilePath,
|
return renderPreview(model, cacheName, outFilePath,
|
||||||
officePreviewType, pdfName, fileAttribute);
|
officePreviewType, fileAttribute);
|
||||||
}
|
}
|
||||||
// 当文件不存在时,就去下载
|
// 当文件不存在时,就去下载
|
||||||
ReturnResponse<String> response = DownloadUtils.downLoad(fileAttribute, pdfName);
|
ReturnResponse<String> response = DownloadUtils.downLoad(fileAttribute, pdfName);
|
||||||
@@ -98,15 +90,17 @@ public class PdfFilePreviewImpl implements FilePreview {
|
|||||||
if (checkIfPdfNeedsPassword(originFilePath, cacheName, pdfName)) {
|
if (checkIfPdfNeedsPassword(originFilePath, cacheName, pdfName)) {
|
||||||
model.addAttribute("needFilePassword", true);
|
model.addAttribute("needFilePassword", true);
|
||||||
model.addAttribute("fileName", pdfName);
|
model.addAttribute("fileName", pdfName);
|
||||||
model.addAttribute("cacheName", cacheName);
|
model.addAttribute("cacheName", pdfName);
|
||||||
return EXEL_FILE_PREVIEW_PAGE;
|
return EXEL_FILE_PREVIEW_PAGE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
// 启动异步转换
|
// 启动异步转换
|
||||||
startAsyncPdfConversion(originFilePath, outFilePath, cacheName, pdfName, fileAttribute);
|
startAsyncPdfConversion(originFilePath, outFilePath, cacheName, pdfName, fileAttribute);
|
||||||
|
int refreshSchedule = ConfigConstants.getTime();
|
||||||
// 返回等待页面
|
// 返回等待页面
|
||||||
model.addAttribute("fileName", pdfName);
|
model.addAttribute("fileName", pdfName);
|
||||||
|
model.addAttribute("time", refreshSchedule);
|
||||||
model.addAttribute("message", "文件正在转换中,请稍候...");
|
model.addAttribute("message", "文件正在转换中,请稍候...");
|
||||||
return WAITING_FILE_PREVIEW_PAGE;
|
return WAITING_FILE_PREVIEW_PAGE;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@@ -116,7 +110,7 @@ public class PdfFilePreviewImpl implements FilePreview {
|
|||||||
} else {
|
} else {
|
||||||
// 如果已有缓存,直接渲染预览
|
// 如果已有缓存,直接渲染预览
|
||||||
return renderPreview(model, cacheName, outFilePath,
|
return renderPreview(model, cacheName, outFilePath,
|
||||||
officePreviewType, pdfName, fileAttribute);
|
officePreviewType, fileAttribute);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 处理普通PDF预览(非图片转换)
|
// 处理普通PDF预览(非图片转换)
|
||||||
@@ -175,13 +169,13 @@ public class PdfFilePreviewImpl implements FilePreview {
|
|||||||
FileConvertStatusManager.updateProgress(cacheName, "正在启动PDF转换", 10);
|
FileConvertStatusManager.updateProgress(cacheName, "正在启动PDF转换", 10);
|
||||||
|
|
||||||
List<String> imageUrls = pdftojpgservice.pdf2jpg(originFilePath, outFilePath,
|
List<String> imageUrls = pdftojpgservice.pdf2jpg(originFilePath, outFilePath,
|
||||||
pdfName, fileAttribute);
|
fileAttribute);
|
||||||
|
|
||||||
if (imageUrls != null && !imageUrls.isEmpty()) {
|
if (imageUrls != null && !imageUrls.isEmpty()) {
|
||||||
boolean usePasswordCache = fileAttribute.getUsePasswordCache();
|
boolean usePasswordCache = fileAttribute.getUsePasswordCache();
|
||||||
String filePassword = fileAttribute.getFilePassword();
|
String filePassword = fileAttribute.getFilePassword();
|
||||||
if (ConfigConstants.isCacheEnabled() && (ObjectUtils.isEmpty(filePassword) || usePasswordCache)) {
|
if (ConfigConstants.isCacheEnabled() && (ObjectUtils.isEmpty(filePassword) || usePasswordCache)) {
|
||||||
fileHandlerService.addConvertedFile(pdfName, fileHandlerService.getRelativePath(outFilePath));
|
fileHandlerService.addConvertedFile(cacheName, fileHandlerService.getRelativePath(outFilePath));
|
||||||
}
|
}
|
||||||
FileConvertStatusManager.updateProgress(cacheName, "转换完成", 100);
|
FileConvertStatusManager.updateProgress(cacheName, "转换完成", 100);
|
||||||
// 短暂延迟后清理状态
|
// 短暂延迟后清理状态
|
||||||
@@ -214,17 +208,7 @@ public class PdfFilePreviewImpl implements FilePreview {
|
|||||||
|
|
||||||
// 添加转换完成后的回调
|
// 添加转换完成后的回调
|
||||||
conversionFuture.whenCompleteAsync((imageUrls, throwable) -> {
|
conversionFuture.whenCompleteAsync((imageUrls, throwable) -> {
|
||||||
if (imageUrls != null && !imageUrls.isEmpty()) {
|
if (imageUrls == null || imageUrls.isEmpty()) {
|
||||||
try {
|
|
||||||
// 是否保留PDF源文件(只在转换成功后才删除)
|
|
||||||
if (!fileAttribute.isCompressFile() && ConfigConstants.getDeleteSourceFile()) {
|
|
||||||
KkFileUtils.deleteFileByPath(originFilePath);
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.error("PDF转换后续处理失败: {}", originFilePath, e);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 转换失败,保留源文件供排查问题
|
|
||||||
logger.error("PDF转换失败,保留源文件: {}", originFilePath);
|
logger.error("PDF转换失败,保留源文件: {}", originFilePath);
|
||||||
if (throwable != null) {
|
if (throwable != null) {
|
||||||
logger.error("转换失败原因: ", throwable);
|
logger.error("转换失败原因: ", throwable);
|
||||||
@@ -238,7 +222,7 @@ public class PdfFilePreviewImpl implements FilePreview {
|
|||||||
*/
|
*/
|
||||||
private String renderPreview(Model model, String cacheName,
|
private String renderPreview(Model model, String cacheName,
|
||||||
String outFilePath, String officePreviewType,
|
String outFilePath, String officePreviewType,
|
||||||
String pdfName, FileAttribute fileAttribute) {
|
FileAttribute fileAttribute) {
|
||||||
try {
|
try {
|
||||||
List<String> imageUrls;
|
List<String> imageUrls;
|
||||||
if(pdftojpgservice.hasEncryptedPdfCacheSimple(outFilePath)){
|
if(pdftojpgservice.hasEncryptedPdfCacheSimple(outFilePath)){
|
||||||
@@ -251,7 +235,7 @@ public class PdfFilePreviewImpl implements FilePreview {
|
|||||||
}
|
}
|
||||||
|
|
||||||
model.addAttribute("imgUrls", imageUrls);
|
model.addAttribute("imgUrls", imageUrls);
|
||||||
model.addAttribute("currentUrl", imageUrls.get(0));
|
model.addAttribute("currentUrl", imageUrls.getFirst());
|
||||||
|
|
||||||
if (OfficeFilePreviewImpl.OFFICE_PREVIEW_TYPE_IMAGE.equals(officePreviewType)) {
|
if (OfficeFilePreviewImpl.OFFICE_PREVIEW_TYPE_IMAGE.equals(officePreviewType)) {
|
||||||
return OFFICE_PICTURE_FILE_PREVIEW_PAGE;
|
return OFFICE_PICTURE_FILE_PREVIEW_PAGE;
|
||||||
|
|||||||
@@ -27,16 +27,28 @@ public class PictureFilePreviewImpl extends CommonPreviewImpl {
|
|||||||
@Override
|
@Override
|
||||||
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
|
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
|
||||||
url= KkFileUtils.htmlEscape(url);
|
url= KkFileUtils.htmlEscape(url);
|
||||||
|
String suffix = fileAttribute.getSuffix();
|
||||||
List<String> imgUrls = new ArrayList<>();
|
List<String> imgUrls = new ArrayList<>();
|
||||||
imgUrls.add(url);
|
imgUrls.add(url);
|
||||||
String compressFileKey = fileAttribute.getCompressFileKey();
|
String compressFileKey = fileAttribute.getCompressFileKey();
|
||||||
List<String> zipImgUrls = fileHandlerService.getImgCache(compressFileKey);
|
List<String> zipImgUrls = fileHandlerService.getImgCache(compressFileKey);
|
||||||
if (!CollectionUtils.isEmpty(zipImgUrls)) {
|
if (!CollectionUtils.isEmpty(zipImgUrls)) {
|
||||||
imgUrls.addAll(zipImgUrls);
|
imgUrls.addAll(zipImgUrls);
|
||||||
}
|
model.addAttribute("imgUrls", imgUrls);
|
||||||
|
}else {
|
||||||
// 不是http开头,浏览器不能直接访问,需下载到本地
|
// 不是http开头,浏览器不能直接访问,需下载到本地
|
||||||
super.filePreviewHandle(url, model, fileAttribute);
|
super.filePreviewHandle(url, model, fileAttribute);
|
||||||
model.addAttribute("imgUrls", imgUrls);
|
if ( url.toLowerCase().startsWith("file") || url.toLowerCase().startsWith("ftp")) {
|
||||||
|
model.addAttribute("imgUrls", fileAttribute.getName());
|
||||||
|
}else {
|
||||||
|
model.addAttribute("imgUrls", url);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if(suffix.equalsIgnoreCase("heic")){
|
||||||
|
return HEIC_FILE_PREVIEW_PAGE;
|
||||||
|
}else {
|
||||||
return PICTURE_FILE_PREVIEW_PAGE;
|
return PICTURE_FILE_PREVIEW_PAGE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -70,8 +70,10 @@ public class TiffFilePreviewImpl implements FilePreview {
|
|||||||
try {
|
try {
|
||||||
// 启动异步转换
|
// 启动异步转换
|
||||||
startAsyncTiffConversion(filePath, outFilePath, cacheName, fileName, fileAttribute, tifPreviewType, forceUpdatedCache);
|
startAsyncTiffConversion(filePath, outFilePath, cacheName, fileName, fileAttribute, tifPreviewType, forceUpdatedCache);
|
||||||
|
int refreshSchedule = ConfigConstants.getTime();
|
||||||
// 返回等待页面
|
// 返回等待页面
|
||||||
model.addAttribute("fileName", fileName);
|
model.addAttribute("fileName", fileName);
|
||||||
|
model.addAttribute("time", refreshSchedule);
|
||||||
model.addAttribute("message", "文件正在转换中,请稍候...");
|
model.addAttribute("message", "文件正在转换中,请稍候...");
|
||||||
return WAITING_FILE_PREVIEW_PAGE;
|
return WAITING_FILE_PREVIEW_PAGE;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
|||||||
@@ -97,9 +97,10 @@ public class DownloadUtils {
|
|||||||
|
|
||||||
factory.setHttpClient(httpClient);
|
factory.setHttpClient(httpClient);
|
||||||
restTemplate.setRequestFactory(factory);
|
restTemplate.setRequestFactory(factory);
|
||||||
|
String finalUrlStr = urlStr;
|
||||||
RequestCallback requestCallback = request -> {
|
RequestCallback requestCallback = request -> {
|
||||||
request.getHeaders().setAccept(Arrays.asList(MediaType.APPLICATION_OCTET_STREAM, MediaType.ALL));
|
request.getHeaders().setAccept(Arrays.asList(MediaType.APPLICATION_OCTET_STREAM, MediaType.ALL));
|
||||||
WebUtils.applyBasicAuthHeaders(request.getHeaders(), fileAttribute);
|
WebUtils.applyBasicAuthHeaders(request.getHeaders(), finalUrlStr);
|
||||||
String proxyAuthorization = fileAttribute.getKkProxyAuthorization();
|
String proxyAuthorization = fileAttribute.getKkProxyAuthorization();
|
||||||
if(StringUtils.hasText(proxyAuthorization)){
|
if(StringUtils.hasText(proxyAuthorization)){
|
||||||
Map<String, String> proxyAuthorizationMap = mapper.readValue(
|
Map<String, String> proxyAuthorizationMap = mapper.readValue(
|
||||||
|
|||||||
@@ -60,6 +60,18 @@ public class KkFileUtils {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
public static boolean validateFileNameLength(String fileName) {
|
||||||
|
if (fileName == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 文件名长度限制:255个字符(不包含路径)
|
||||||
|
int windowsMaxLength = 255;
|
||||||
|
if (fileName.length() > windowsMaxLength) {
|
||||||
|
System.err.println("文件名长度超过限制(255个字符)");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查是否是数字
|
* 检查是否是数字
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package cn.keking.utils;
|
package cn.keking.utils;
|
||||||
|
|
||||||
import cn.keking.config.ConfigConstants;
|
import cn.keking.config.ConfigConstants;
|
||||||
import cn.keking.model.FileAttribute;
|
|
||||||
import io.mola.galimatias.GalimatiasParseException;
|
import io.mola.galimatias.GalimatiasParseException;
|
||||||
import org.apache.commons.codec.binary.Base64;
|
import org.apache.commons.codec.binary.Base64;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
@@ -465,10 +464,8 @@ public class WebUtils {
|
|||||||
/**
|
/**
|
||||||
* 支持basic 下载方法
|
* 支持basic 下载方法
|
||||||
*/
|
*/
|
||||||
public static void applyBasicAuthHeaders(HttpHeaders headers, FileAttribute fileAttribute) {
|
public static void applyBasicAuthHeaders(HttpHeaders headers, String url) {
|
||||||
String url = fileAttribute.getUrl();
|
|
||||||
System.out.println(" T555.");
|
|
||||||
System.out.println(url);
|
|
||||||
// 从配置文件读取User-Agent,如果没有配置则使用默认值
|
// 从配置文件读取User-Agent,如果没有配置则使用默认值
|
||||||
String customUserAgent=ConfigConstants.getUserAgent();
|
String customUserAgent=ConfigConstants.getUserAgent();
|
||||||
String userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36";
|
String userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36";
|
||||||
|
|||||||
@@ -197,9 +197,10 @@ public class OnlinePreviewController {
|
|||||||
|
|
||||||
RestTemplate restTemplate = new RestTemplate();
|
RestTemplate restTemplate = new RestTemplate();
|
||||||
restTemplate.setRequestFactory(factory);
|
restTemplate.setRequestFactory(factory);
|
||||||
|
String finalUrlPath = urlPath;
|
||||||
RequestCallback requestCallback = request -> {
|
RequestCallback requestCallback = request -> {
|
||||||
request.getHeaders().setAccept(Arrays.asList(MediaType.APPLICATION_OCTET_STREAM, MediaType.ALL));
|
request.getHeaders().setAccept(Arrays.asList(MediaType.APPLICATION_OCTET_STREAM, MediaType.ALL));
|
||||||
WebUtils.applyBasicAuthHeaders(request.getHeaders(), fileAttribute);
|
WebUtils.applyBasicAuthHeaders(request.getHeaders(), finalUrlPath);
|
||||||
String proxyAuthorization = fileAttribute.getKkProxyAuthorization();
|
String proxyAuthorization = fileAttribute.getKkProxyAuthorization();
|
||||||
if(StringUtils.hasText(proxyAuthorization)){
|
if(StringUtils.hasText(proxyAuthorization)){
|
||||||
Map<String, String> proxyAuthorizationMap = mapper.readValue(
|
Map<String, String> proxyAuthorizationMap = mapper.readValue(
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
=> Java Version :: ${java.version}
|
=> Java Version :: ${java.version}
|
||||||
=> Spring Boot :: ${spring-boot.version}
|
=> Spring Boot :: ${spring-boot.version}
|
||||||
=> kkFileView :: 4.4.0
|
=> kkFileView :: 5.0
|
||||||
=> Home site :: https://kkview.cn
|
=> Home site :: https://kkview.cn
|
||||||
=> Github :: https://github.com/kekingcn/kkFileView
|
=> Github :: https://github.com/kekingcn/kkFileView
|
||||||
=> Gitee :: https://gitee.com/kekingcn/file-online-preview
|
=> Gitee :: https://gitee.com/kekingcn/file-online-preview
|
||||||
|
|||||||
479
server/src/main/resources/static/cadviewer/app/css/bootstrap-cadviewer.css
vendored
Normal file
@@ -0,0 +1,479 @@
|
|||||||
|
/*!
|
||||||
|
* Generated using the Bootstrap Customizer (https://getbootstrap.com/docs/3.4/customize/)
|
||||||
|
*/
|
||||||
|
/*!
|
||||||
|
* Bootstrap v3.4.1 (https://getbootstrap.com/)
|
||||||
|
* Copyright 2011-2019 Twitter, Inc.
|
||||||
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||||
|
*/
|
||||||
|
/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */
|
||||||
|
html {
|
||||||
|
font-family: sans-serif;
|
||||||
|
-ms-text-size-adjust: 100%;
|
||||||
|
-webkit-text-size-adjust: 100%;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
article,
|
||||||
|
aside,
|
||||||
|
details,
|
||||||
|
figcaption,
|
||||||
|
figure,
|
||||||
|
footer,
|
||||||
|
header,
|
||||||
|
hgroup,
|
||||||
|
main,
|
||||||
|
menu,
|
||||||
|
nav,
|
||||||
|
section,
|
||||||
|
summary {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
audio,
|
||||||
|
canvas,
|
||||||
|
progress,
|
||||||
|
video {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
audio:not([controls]) {
|
||||||
|
display: none;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
[hidden],
|
||||||
|
template {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
a:active,
|
||||||
|
a:hover {
|
||||||
|
outline: 0;
|
||||||
|
}
|
||||||
|
abbr[title] {
|
||||||
|
border-bottom: none;
|
||||||
|
text-decoration: underline;
|
||||||
|
text-decoration: underline dotted;
|
||||||
|
}
|
||||||
|
b,
|
||||||
|
strong {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
dfn {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
font-size: 2em;
|
||||||
|
margin: 0.67em 0;
|
||||||
|
}
|
||||||
|
mark {
|
||||||
|
background: #ff0;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
small {
|
||||||
|
font-size: 80%;
|
||||||
|
}
|
||||||
|
sub,
|
||||||
|
sup {
|
||||||
|
font-size: 75%;
|
||||||
|
line-height: 0;
|
||||||
|
position: relative;
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
sup {
|
||||||
|
top: -0.5em;
|
||||||
|
}
|
||||||
|
sub {
|
||||||
|
bottom: -0.25em;
|
||||||
|
}
|
||||||
|
img {
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
svg:not(:root) {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
figure {
|
||||||
|
margin: 1em 40px;
|
||||||
|
}
|
||||||
|
hr {
|
||||||
|
-webkit-box-sizing: content-box;
|
||||||
|
-moz-box-sizing: content-box;
|
||||||
|
box-sizing: content-box;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
pre {
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
code,
|
||||||
|
kbd,
|
||||||
|
pre,
|
||||||
|
samp {
|
||||||
|
font-family: monospace, monospace;
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
button,
|
||||||
|
input,
|
||||||
|
optgroup,
|
||||||
|
select,
|
||||||
|
textarea {
|
||||||
|
color: inherit;
|
||||||
|
font: inherit;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
button {
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
button,
|
||||||
|
select {
|
||||||
|
text-transform: none;
|
||||||
|
}
|
||||||
|
button,
|
||||||
|
html input[type="button"],
|
||||||
|
input[type="reset"],
|
||||||
|
input[type="submit"] {
|
||||||
|
-webkit-appearance: button;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
button[disabled],
|
||||||
|
html input[disabled] {
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
button::-moz-focus-inner,
|
||||||
|
input::-moz-focus-inner {
|
||||||
|
border: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
input {
|
||||||
|
line-height: normal;
|
||||||
|
}
|
||||||
|
input[type="checkbox"],
|
||||||
|
input[type="radio"] {
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
-moz-box-sizing: border-box;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
input[type="number"]::-webkit-inner-spin-button,
|
||||||
|
input[type="number"]::-webkit-outer-spin-button {
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
input[type="search"] {
|
||||||
|
-webkit-appearance: textfield;
|
||||||
|
-webkit-box-sizing: content-box;
|
||||||
|
-moz-box-sizing: content-box;
|
||||||
|
box-sizing: content-box;
|
||||||
|
}
|
||||||
|
input[type="search"]::-webkit-search-cancel-button,
|
||||||
|
input[type="search"]::-webkit-search-decoration {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
}
|
||||||
|
fieldset {
|
||||||
|
border: 1px solid #c0c0c0;
|
||||||
|
margin: 0 2px;
|
||||||
|
padding: 0.35em 0.625em 0.75em;
|
||||||
|
}
|
||||||
|
legend {
|
||||||
|
border: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
textarea {
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
optgroup {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
border-spacing: 0;
|
||||||
|
}
|
||||||
|
td,
|
||||||
|
th {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
* {
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
-moz-box-sizing: border-box;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
*:before,
|
||||||
|
*:after {
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
-moz-box-sizing: border-box;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
html {
|
||||||
|
font-size: 10px;
|
||||||
|
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.42857143;
|
||||||
|
color: #333333;
|
||||||
|
background-color: #ffffff;
|
||||||
|
}
|
||||||
|
input,
|
||||||
|
button,
|
||||||
|
select,
|
||||||
|
textarea {
|
||||||
|
font-family: inherit;
|
||||||
|
font-size: inherit;
|
||||||
|
line-height: inherit;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
color: #337ab7;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
a:hover,
|
||||||
|
a:focus {
|
||||||
|
color: #23527c;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
a:focus {
|
||||||
|
outline: 5px auto -webkit-focus-ring-color;
|
||||||
|
outline-offset: -2px;
|
||||||
|
}
|
||||||
|
figure {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
img {
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
.img-responsive {
|
||||||
|
display: block;
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
.img-rounded {
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
.img-thumbnail {
|
||||||
|
padding: 4px;
|
||||||
|
line-height: 1.42857143;
|
||||||
|
background-color: #ffffff;
|
||||||
|
border: 1px solid #dddddd;
|
||||||
|
border-radius: 4px;
|
||||||
|
-webkit-transition: all 0.2s ease-in-out;
|
||||||
|
-o-transition: all 0.2s ease-in-out;
|
||||||
|
transition: all 0.2s ease-in-out;
|
||||||
|
display: inline-block;
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
.img-circle {
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
hr {
|
||||||
|
margin-top: 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
border: 0;
|
||||||
|
border-top: 1px solid #eeeeee;
|
||||||
|
}
|
||||||
|
.sr-only {
|
||||||
|
position: absolute;
|
||||||
|
width: 1px;
|
||||||
|
height: 1px;
|
||||||
|
padding: 0;
|
||||||
|
margin: -1px;
|
||||||
|
overflow: hidden;
|
||||||
|
clip: rect(0, 0, 0, 0);
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
.sr-only-focusable:active,
|
||||||
|
.sr-only-focusable:focus {
|
||||||
|
position: static;
|
||||||
|
width: auto;
|
||||||
|
height: auto;
|
||||||
|
margin: 0;
|
||||||
|
overflow: visible;
|
||||||
|
clip: auto;
|
||||||
|
}
|
||||||
|
[role="button"] {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.caret {
|
||||||
|
display: inline-block;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
margin-left: 2px;
|
||||||
|
vertical-align: middle;
|
||||||
|
border-top: 4px dashed;
|
||||||
|
border-top: 4px solid \9;
|
||||||
|
border-right: 4px solid transparent;
|
||||||
|
border-left: 4px solid transparent;
|
||||||
|
}
|
||||||
|
.dropup,
|
||||||
|
.dropdown {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.dropdown-toggle:focus {
|
||||||
|
outline: 0;
|
||||||
|
}
|
||||||
|
.dropdown-menu {
|
||||||
|
position: absolute;
|
||||||
|
top: 100%;
|
||||||
|
left: 0;
|
||||||
|
z-index: 1000;
|
||||||
|
display: none;
|
||||||
|
float: left;
|
||||||
|
min-width: 160px;
|
||||||
|
padding: 5px 0;
|
||||||
|
margin: 2px 0 0;
|
||||||
|
font-size: 14px;
|
||||||
|
text-align: left;
|
||||||
|
list-style: none;
|
||||||
|
background-color: #ffffff;
|
||||||
|
-webkit-background-clip: padding-box;
|
||||||
|
background-clip: padding-box;
|
||||||
|
border: 1px solid #cccccc;
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.15);
|
||||||
|
border-radius: 4px;
|
||||||
|
-webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
|
||||||
|
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
|
||||||
|
}
|
||||||
|
.dropdown-menu.pull-right {
|
||||||
|
right: 0;
|
||||||
|
left: auto;
|
||||||
|
}
|
||||||
|
.dropdown-menu .divider {
|
||||||
|
height: 1px;
|
||||||
|
margin: 9px 0;
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: #e5e5e5;
|
||||||
|
}
|
||||||
|
.dropdown-menu > li > a {
|
||||||
|
display: block;
|
||||||
|
padding: 3px 20px;
|
||||||
|
clear: both;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 1.42857143;
|
||||||
|
color: #333333;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.dropdown-menu > li > a:hover,
|
||||||
|
.dropdown-menu > li > a:focus {
|
||||||
|
color: #262626;
|
||||||
|
text-decoration: none;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
}
|
||||||
|
.dropdown-menu > .active > a,
|
||||||
|
.dropdown-menu > .active > a:hover,
|
||||||
|
.dropdown-menu > .active > a:focus {
|
||||||
|
color: #ffffff;
|
||||||
|
text-decoration: none;
|
||||||
|
background-color: #337ab7;
|
||||||
|
outline: 0;
|
||||||
|
}
|
||||||
|
.dropdown-menu > .disabled > a,
|
||||||
|
.dropdown-menu > .disabled > a:hover,
|
||||||
|
.dropdown-menu > .disabled > a:focus {
|
||||||
|
color: #777777;
|
||||||
|
}
|
||||||
|
.dropdown-menu > .disabled > a:hover,
|
||||||
|
.dropdown-menu > .disabled > a:focus {
|
||||||
|
text-decoration: none;
|
||||||
|
cursor: not-allowed;
|
||||||
|
background-color: transparent;
|
||||||
|
background-image: none;
|
||||||
|
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
|
||||||
|
}
|
||||||
|
.open > .dropdown-menu {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.open > a {
|
||||||
|
outline: 0;
|
||||||
|
}
|
||||||
|
.dropdown-menu-right {
|
||||||
|
right: 0;
|
||||||
|
left: auto;
|
||||||
|
}
|
||||||
|
.dropdown-menu-left {
|
||||||
|
right: auto;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
.dropdown-header {
|
||||||
|
display: block;
|
||||||
|
padding: 3px 20px;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 1.42857143;
|
||||||
|
color: #777777;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.dropdown-backdrop {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: 990;
|
||||||
|
}
|
||||||
|
.pull-right > .dropdown-menu {
|
||||||
|
right: 0;
|
||||||
|
left: auto;
|
||||||
|
}
|
||||||
|
.dropup .caret,
|
||||||
|
.navbar-fixed-bottom .dropdown .caret {
|
||||||
|
content: "";
|
||||||
|
border-top: 0;
|
||||||
|
border-bottom: 4px dashed;
|
||||||
|
border-bottom: 4px solid \9;
|
||||||
|
}
|
||||||
|
.dropup .dropdown-menu,
|
||||||
|
.navbar-fixed-bottom .dropdown .dropdown-menu {
|
||||||
|
top: auto;
|
||||||
|
bottom: 100%;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
|
@media (min-width: 768px) {
|
||||||
|
.navbar-right .dropdown-menu {
|
||||||
|
right: 0;
|
||||||
|
left: auto;
|
||||||
|
}
|
||||||
|
.navbar-right .dropdown-menu-left {
|
||||||
|
right: auto;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.clearfix:before,
|
||||||
|
.clearfix:after {
|
||||||
|
display: table;
|
||||||
|
content: " ";
|
||||||
|
}
|
||||||
|
.clearfix:after {
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
.center-block {
|
||||||
|
display: block;
|
||||||
|
margin-right: auto;
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
.pull-right {
|
||||||
|
float: right !important;
|
||||||
|
}
|
||||||
|
.pull-left {
|
||||||
|
float: left !important;
|
||||||
|
}
|
||||||
|
.hide {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
.show {
|
||||||
|
display: block !important;
|
||||||
|
}
|
||||||
|
.invisible {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
.text-hide {
|
||||||
|
font: 0/0 a;
|
||||||
|
color: transparent;
|
||||||
|
text-shadow: none;
|
||||||
|
background-color: transparent;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
.hidden {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
.affix {
|
||||||
|
position: fixed;
|
||||||
|
}
|
||||||
1
server/src/main/resources/static/cadviewer/app/css/bootstrap-multiselect.css
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
span.multiselect-native-select{position:relative}span.multiselect-native-select select{border:0!important;clip:rect(0 0 0 0)!important;height:1px!important;margin:-1px -1px -1px -3px!important;overflow:hidden!important;padding:0!important;position:absolute!important;width:1px!important;left:50%;top:30px}.multiselect-container{position:absolute;list-style-type:none;margin:0;padding:0}.multiselect-container .input-group{margin:5px}.multiselect-container .multiselect-reset .input-group{width:93%}.multiselect-container>li{padding:0}.multiselect-container>li>a.multiselect-all label{font-weight:700}.multiselect-container>li.multiselect-group label{margin:0;padding:3px 20px;height:100%;font-weight:700}.multiselect-container>li.multiselect-group-clickable label{cursor:pointer}.multiselect-container>li>a{padding:0}.multiselect-container>li>a>label{margin:0;height:100%;cursor:pointer;font-weight:400;padding:3px 20px 3px 40px}.multiselect-container>li>a>label.checkbox,.multiselect-container>li>a>label.radio{margin:0}.multiselect-container>li>a>label>input[type=checkbox]{margin-bottom:5px}.btn-group>.btn-group:nth-child(2)>.multiselect.btn{border-top-left-radius:4px;border-bottom-left-radius:4px}.form-inline .multiselect-container label.checkbox,.form-inline .multiselect-container label.radio{padding:3px 20px 3px 40px}.form-inline .multiselect-container li a label.checkbox input[type=checkbox],.form-inline .multiselect-container li a label.radio input[type=radio]{margin-left:-20px;margin-right:0}
|
||||||
@@ -0,0 +1,444 @@
|
|||||||
|
.cadviewer-bootstrap {
|
||||||
|
/*!
|
||||||
|
* Generated using the Bootstrap Customizer (https://getbootstrap.com/docs/3.4/customize/)
|
||||||
|
*/
|
||||||
|
/*!
|
||||||
|
* Bootstrap v3.4.1 (https://getbootstrap.com/)
|
||||||
|
* Copyright 2011-2019 Twitter, Inc.
|
||||||
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||||
|
*/
|
||||||
|
/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap html {
|
||||||
|
font-family: sans-serif;
|
||||||
|
-ms-text-size-adjust: 100%;
|
||||||
|
-webkit-text-size-adjust: 100%;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap body {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap article, .cadviewer-bootstrap aside, .cadviewer-bootstrap details, .cadviewer-bootstrap figcaption, .cadviewer-bootstrap figure, .cadviewer-bootstrap footer, .cadviewer-bootstrap header, .cadviewer-bootstrap hgroup, .cadviewer-bootstrap main, .cadviewer-bootstrap menu, .cadviewer-bootstrap nav, .cadviewer-bootstrap section, .cadviewer-bootstrap summary {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap audio, .cadviewer-bootstrap canvas, .cadviewer-bootstrap progress, .cadviewer-bootstrap video {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap audio:not([controls]) {
|
||||||
|
display: none;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap [hidden], .cadviewer-bootstrap template {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap a {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap a:active, .cadviewer-bootstrap a:hover {
|
||||||
|
outline: 0;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap abbr[title] {
|
||||||
|
border-bottom: none;
|
||||||
|
text-decoration: underline;
|
||||||
|
text-decoration: underline dotted;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap b, .cadviewer-bootstrap strong {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap dfn {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap h1 {
|
||||||
|
font-size: 2em;
|
||||||
|
margin: 0.67em 0;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap mark {
|
||||||
|
background: #ff0;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap small {
|
||||||
|
font-size: 80%;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap sub, .cadviewer-bootstrap sup {
|
||||||
|
font-size: 75%;
|
||||||
|
line-height: 0;
|
||||||
|
position: relative;
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap sup {
|
||||||
|
top: -0.5em;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap sub {
|
||||||
|
bottom: -0.25em;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap img {
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap svg:not(:root) {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap figure {
|
||||||
|
margin: 1em 40px;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap hr {
|
||||||
|
-webkit-box-sizing: content-box;
|
||||||
|
-moz-box-sizing: content-box;
|
||||||
|
box-sizing: content-box;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap pre {
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap code, .cadviewer-bootstrap kbd, .cadviewer-bootstrap pre, .cadviewer-bootstrap samp {
|
||||||
|
font-family: monospace, monospace;
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap button, .cadviewer-bootstrap input, .cadviewer-bootstrap optgroup, .cadviewer-bootstrap select, .cadviewer-bootstrap textarea {
|
||||||
|
color: inherit;
|
||||||
|
font: inherit;
|
||||||
|
margin: 0;
|
||||||
|
/* 8.45.2 */
|
||||||
|
/*8.45.2*/
|
||||||
|
border-radius: 0px !important;
|
||||||
|
border-width : 1px !important;
|
||||||
|
border-color: #000 !important;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap button {
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap button, .cadviewer-bootstrap select {
|
||||||
|
text-transform: none;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap button, .cadviewer-bootstrap html input[type="button"], .cadviewer-bootstrap input[type="reset"], .cadviewer-bootstrap input[type="submit"] {
|
||||||
|
-webkit-appearance: button;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap button[disabled], .cadviewer-bootstrap html input[disabled] {
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap button::-moz-focus-inner, .cadviewer-bootstrap input::-moz-focus-inner {
|
||||||
|
border: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap input {
|
||||||
|
line-height: 22px;
|
||||||
|
/*8.45.2*/
|
||||||
|
border-radius: 0px !important;
|
||||||
|
border-width : 1px !important;
|
||||||
|
border-color: #000 !important;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap input[type="checkbox"], .cadviewer-bootstrap input[type="radio"] {
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
-moz-box-sizing: border-box;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 0;
|
||||||
|
border-radius: 0px;
|
||||||
|
height: 20px !important;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap input[type="number"]::-webkit-inner-spin-button, .cadviewer-bootstrap input[type="number"]::-webkit-outer-spin-button {
|
||||||
|
height: auto;
|
||||||
|
|
||||||
|
border-radius: 3px;
|
||||||
|
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap input[type="search"] {
|
||||||
|
-webkit-appearance: textfield;
|
||||||
|
-webkit-box-sizing: content-box;
|
||||||
|
-moz-box-sizing: content-box;
|
||||||
|
box-sizing: content-box;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap input[type="search"]::-webkit-search-cancel-button, .cadviewer-bootstrap input[type="search"]::-webkit-search-decoration {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap fieldset {
|
||||||
|
border: 1px solid #c0c0c0;
|
||||||
|
margin: 0 2px;
|
||||||
|
padding: 0.35em 0.625em 0.75em;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap legend {
|
||||||
|
border: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap textarea {
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap optgroup {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
border-spacing: 0;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap td, .cadviewer-bootstrap th {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap * {
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
-moz-box-sizing: border-box;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap *:before, .cadviewer-bootstrap *:after {
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
-moz-box-sizing: border-box;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap html {
|
||||||
|
font-size: 10px;
|
||||||
|
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap input, .cadviewer-bootstrap button, .cadviewer-bootstrap select, .cadviewer-bootstrap textarea {
|
||||||
|
font-family: inherit;
|
||||||
|
font-size: inherit;
|
||||||
|
line-height: inherit;
|
||||||
|
|
||||||
|
/*8.45.2*/
|
||||||
|
border-radius: 0px !important;
|
||||||
|
border-width : 1px !important;
|
||||||
|
border-color: #000 !important;
|
||||||
|
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap a {
|
||||||
|
color: #337ab7;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap #floorPlan_svg a:hover, .cadviewer-bootstrap #floorPlan_svg a:focus {
|
||||||
|
color: #23527c;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap a:focus {
|
||||||
|
outline: 5px auto -webkit-focus-ring-color;
|
||||||
|
outline-offset: -2px;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap figure {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap img {
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap .img-responsive {
|
||||||
|
display: block;
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap .img-rounded {
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap .img-thumbnail {
|
||||||
|
padding: 4px;
|
||||||
|
line-height: 1.42857143;
|
||||||
|
background-color: #ffffff;
|
||||||
|
border: 1px solid #dddddd;
|
||||||
|
border-radius: 4px;
|
||||||
|
-webkit-transition: all 0.2s ease-in-out;
|
||||||
|
-o-transition: all 0.2s ease-in-out;
|
||||||
|
transition: all 0.2s ease-in-out;
|
||||||
|
display: inline-block;
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap .img-circle {
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap hr {
|
||||||
|
margin-top: 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
border: 0;
|
||||||
|
border-top: 1px solid #eeeeee;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap .sr-only {
|
||||||
|
position: absolute;
|
||||||
|
width: 1px;
|
||||||
|
height: 1px;
|
||||||
|
padding: 0;
|
||||||
|
margin: -1px;
|
||||||
|
overflow: hidden;
|
||||||
|
clip: rect(0, 0, 0, 0);
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap .sr-only-focusable:active, .cadviewer-bootstrap .sr-only-focusable:focus {
|
||||||
|
position: static;
|
||||||
|
width: auto;
|
||||||
|
height: auto;
|
||||||
|
margin: 0;
|
||||||
|
overflow: visible;
|
||||||
|
clip: auto;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap [role="button"] {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap .caret {
|
||||||
|
display: inline-block;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
margin-left: 2px;
|
||||||
|
vertical-align: middle;
|
||||||
|
border-top: 4px dashed;
|
||||||
|
border-top: 4px solid \9;
|
||||||
|
border-right: 4px solid transparent;
|
||||||
|
border-left: 4px solid transparent;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap .dropup, .cadviewer-bootstrap .dropdown {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap .dropdown-toggle:focus {
|
||||||
|
outline: 0;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap .dropdown-menu {
|
||||||
|
position: absolute;
|
||||||
|
top: 100%;
|
||||||
|
left: 0;
|
||||||
|
z-index: 1000;
|
||||||
|
display: none;
|
||||||
|
float: left;
|
||||||
|
min-width: 160px;
|
||||||
|
padding: 5px 0;
|
||||||
|
margin: 2px 0 0;
|
||||||
|
font-size: 14px;
|
||||||
|
text-align: left;
|
||||||
|
list-style: none;
|
||||||
|
background-color: #ffffff;
|
||||||
|
-webkit-background-clip: padding-box;
|
||||||
|
background-clip: padding-box;
|
||||||
|
border: 1px solid #cccccc;
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.15);
|
||||||
|
border-radius: 4px;
|
||||||
|
-webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
|
||||||
|
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap .dropdown-menu.pull-right {
|
||||||
|
right: 0;
|
||||||
|
left: auto;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap .dropdown-menu .divider {
|
||||||
|
height: 1px;
|
||||||
|
margin: 9px 0;
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: #e5e5e5;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap .dropdown-menu > li > a {
|
||||||
|
display: block;
|
||||||
|
padding: 3px 20px;
|
||||||
|
clear: both;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 1.42857143;
|
||||||
|
color: #333333;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap .dropdown-menu > li > a:hover, .cadviewer-bootstrap .dropdown-menu > li > a:focus {
|
||||||
|
color: #262626;
|
||||||
|
text-decoration: none;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap .dropdown-menu > .active > a, .cadviewer-bootstrap .dropdown-menu > .active > a:hover, .cadviewer-bootstrap .dropdown-menu > .active > a:focus {
|
||||||
|
color: #ffffff;
|
||||||
|
text-decoration: none;
|
||||||
|
background-color: #337ab7;
|
||||||
|
outline: 0;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap .dropdown-menu > .disabled > a, .cadviewer-bootstrap .dropdown-menu > .disabled > a:hover, .cadviewer-bootstrap .dropdown-menu > .disabled > a:focus {
|
||||||
|
color: #777777;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap .dropdown-menu > .disabled > a:hover, .cadviewer-bootstrap .dropdown-menu > .disabled > a:focus {
|
||||||
|
text-decoration: none;
|
||||||
|
cursor: not-allowed;
|
||||||
|
background-color: transparent;
|
||||||
|
background-image: none;
|
||||||
|
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap .open > .dropdown-menu {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap .open > a {
|
||||||
|
outline: 0;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap .dropdown-menu-right {
|
||||||
|
right: 0;
|
||||||
|
left: auto;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap .dropdown-menu-left {
|
||||||
|
right: auto;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap .dropdown-header {
|
||||||
|
display: block;
|
||||||
|
padding: 3px 20px;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 1.42857143;
|
||||||
|
color: #777777;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap .dropdown-backdrop {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: 990;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap .pull-right > .dropdown-menu {
|
||||||
|
right: 0;
|
||||||
|
left: auto;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap .dropup .caret, .cadviewer-bootstrap .navbar-fixed-bottom .dropdown .caret {
|
||||||
|
content: "";
|
||||||
|
border-top: 0;
|
||||||
|
border-bottom: 4px dashed;
|
||||||
|
border-bottom: 4px solid \9;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap .dropup .dropdown-menu, .cadviewer-bootstrap .navbar-fixed-bottom .dropdown .dropdown-menu {
|
||||||
|
top: auto;
|
||||||
|
bottom: 100%;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
|
@media (min-width: 768px) {
|
||||||
|
.cadviewer-bootstrap .navbar-right .dropdown-menu {
|
||||||
|
right: 0;
|
||||||
|
left: auto;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap .navbar-right .dropdown-menu-left {
|
||||||
|
right: auto;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap .clearfix:before, .cadviewer-bootstrap .clearfix:after {
|
||||||
|
display: table;
|
||||||
|
content: " ";
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap .clearfix:after {
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap .center-block {
|
||||||
|
display: block;
|
||||||
|
margin-right: auto;
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap .pull-right {
|
||||||
|
float: right !important;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap .pull-left {
|
||||||
|
float: left !important;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap .hide {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap .show {
|
||||||
|
display: block !important;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap .invisible {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap .text-hide {
|
||||||
|
font: 0/0 a;
|
||||||
|
color: transparent;
|
||||||
|
text-shadow: none;
|
||||||
|
background-color: transparent;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap .hidden {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
.cadviewer-bootstrap .affix {
|
||||||
|
position: fixed;
|
||||||
|
}
|
||||||
391
server/src/main/resources/static/cadviewer/app/css/config.json
Normal file
@@ -0,0 +1,391 @@
|
|||||||
|
{
|
||||||
|
"vars": {
|
||||||
|
"@gray-base": "#000",
|
||||||
|
"@gray-darker": "lighten(@gray-base, 13.5%)",
|
||||||
|
"@gray-dark": "lighten(@gray-base, 20%)",
|
||||||
|
"@gray": "lighten(@gray-base, 33.5%)",
|
||||||
|
"@gray-light": "lighten(@gray-base, 46.7%)",
|
||||||
|
"@gray-lighter": "lighten(@gray-base, 93.5%)",
|
||||||
|
"@brand-primary": "darken(#428bca, 6.5%)",
|
||||||
|
"@brand-success": "#5cb85c",
|
||||||
|
"@brand-info": "#5bc0de",
|
||||||
|
"@brand-warning": "#f0ad4e",
|
||||||
|
"@brand-danger": "#d9534f",
|
||||||
|
"@body-bg": "#fff",
|
||||||
|
"@text-color": "@gray-dark",
|
||||||
|
"@link-color": "@brand-primary",
|
||||||
|
"@link-hover-color": "darken(@link-color, 15%)",
|
||||||
|
"@link-hover-decoration": "underline",
|
||||||
|
"@font-family-sans-serif": "\"Helvetica Neue\", Helvetica, Arial, sans-serif",
|
||||||
|
"@font-family-serif": "Georgia, \"Times New Roman\", Times, serif",
|
||||||
|
"@font-family-monospace": "Menlo, Monaco, Consolas, \"Courier New\", monospace",
|
||||||
|
"@font-family-base": "@font-family-sans-serif",
|
||||||
|
"@font-size-base": "14px",
|
||||||
|
"@font-size-large": "ceil((@font-size-base * 1.25))",
|
||||||
|
"@font-size-small": "ceil((@font-size-base * .85))",
|
||||||
|
"@font-size-h1": "floor((@font-size-base * 2.6))",
|
||||||
|
"@font-size-h2": "floor((@font-size-base * 2.15))",
|
||||||
|
"@font-size-h3": "ceil((@font-size-base * 1.7))",
|
||||||
|
"@font-size-h4": "ceil((@font-size-base * 1.25))",
|
||||||
|
"@font-size-h5": "@font-size-base",
|
||||||
|
"@font-size-h6": "ceil((@font-size-base * .85))",
|
||||||
|
"@line-height-base": "1.428571429",
|
||||||
|
"@line-height-computed": "floor((@font-size-base * @line-height-base))",
|
||||||
|
"@headings-font-family": "inherit",
|
||||||
|
"@headings-font-weight": "500",
|
||||||
|
"@headings-line-height": "1.1",
|
||||||
|
"@headings-color": "inherit",
|
||||||
|
"@icon-font-path": "\"../fonts/\"",
|
||||||
|
"@icon-font-name": "\"glyphicons-halflings-regular\"",
|
||||||
|
"@icon-font-svg-id": "\"glyphicons_halflingsregular\"",
|
||||||
|
"@padding-base-vertical": "6px",
|
||||||
|
"@padding-base-horizontal": "12px",
|
||||||
|
"@padding-large-vertical": "10px",
|
||||||
|
"@padding-large-horizontal": "16px",
|
||||||
|
"@padding-small-vertical": "5px",
|
||||||
|
"@padding-small-horizontal": "10px",
|
||||||
|
"@padding-xs-vertical": "1px",
|
||||||
|
"@padding-xs-horizontal": "5px",
|
||||||
|
"@line-height-large": "1.3333333",
|
||||||
|
"@line-height-small": "1.5",
|
||||||
|
"@border-radius-base": "4px",
|
||||||
|
"@border-radius-large": "6px",
|
||||||
|
"@border-radius-small": "3px",
|
||||||
|
"@component-active-color": "#fff",
|
||||||
|
"@component-active-bg": "@brand-primary",
|
||||||
|
"@caret-width-base": "4px",
|
||||||
|
"@caret-width-large": "5px",
|
||||||
|
"@table-cell-padding": "8px",
|
||||||
|
"@table-condensed-cell-padding": "5px",
|
||||||
|
"@table-bg": "transparent",
|
||||||
|
"@table-bg-accent": "#f9f9f9",
|
||||||
|
"@table-bg-hover": "#f5f5f5",
|
||||||
|
"@table-bg-active": "@table-bg-hover",
|
||||||
|
"@table-border-color": "#ddd",
|
||||||
|
"@btn-font-weight": "normal",
|
||||||
|
"@btn-default-color": "#333",
|
||||||
|
"@btn-default-bg": "#fff",
|
||||||
|
"@btn-default-border": "#ccc",
|
||||||
|
"@btn-primary-color": "#fff",
|
||||||
|
"@btn-primary-bg": "@brand-primary",
|
||||||
|
"@btn-primary-border": "darken(@btn-primary-bg, 5%)",
|
||||||
|
"@btn-success-color": "#fff",
|
||||||
|
"@btn-success-bg": "@brand-success",
|
||||||
|
"@btn-success-border": "darken(@btn-success-bg, 5%)",
|
||||||
|
"@btn-info-color": "#fff",
|
||||||
|
"@btn-info-bg": "@brand-info",
|
||||||
|
"@btn-info-border": "darken(@btn-info-bg, 5%)",
|
||||||
|
"@btn-warning-color": "#fff",
|
||||||
|
"@btn-warning-bg": "@brand-warning",
|
||||||
|
"@btn-warning-border": "darken(@btn-warning-bg, 5%)",
|
||||||
|
"@btn-danger-color": "#fff",
|
||||||
|
"@btn-danger-bg": "@brand-danger",
|
||||||
|
"@btn-danger-border": "darken(@btn-danger-bg, 5%)",
|
||||||
|
"@btn-link-disabled-color": "@gray-light",
|
||||||
|
"@btn-border-radius-base": "@border-radius-base",
|
||||||
|
"@btn-border-radius-large": "@border-radius-large",
|
||||||
|
"@btn-border-radius-small": "@border-radius-small",
|
||||||
|
"@input-bg": "#fff",
|
||||||
|
"@input-bg-disabled": "@gray-lighter",
|
||||||
|
"@input-color": "@gray",
|
||||||
|
"@input-border": "#ccc",
|
||||||
|
"@input-border-radius": "@border-radius-base",
|
||||||
|
"@input-border-radius-large": "@border-radius-large",
|
||||||
|
"@input-border-radius-small": "@border-radius-small",
|
||||||
|
"@input-border-focus": "#66afe9",
|
||||||
|
"@input-color-placeholder": "#999",
|
||||||
|
"@input-height-base": "(@line-height-computed + (@padding-base-vertical * 2) + 2)",
|
||||||
|
"@input-height-large": "(ceil(@font-size-large * @line-height-large) + (@padding-large-vertical * 2) + 2)",
|
||||||
|
"@input-height-small": "(floor(@font-size-small * @line-height-small) + (@padding-small-vertical * 2) + 2)",
|
||||||
|
"@form-group-margin-bottom": "15px",
|
||||||
|
"@legend-color": "@gray-dark",
|
||||||
|
"@legend-border-color": "#e5e5e5",
|
||||||
|
"@input-group-addon-bg": "@gray-lighter",
|
||||||
|
"@input-group-addon-border-color": "@input-border",
|
||||||
|
"@cursor-disabled": "not-allowed",
|
||||||
|
"@dropdown-bg": "#fff",
|
||||||
|
"@dropdown-border": "rgba(0, 0, 0, .15)",
|
||||||
|
"@dropdown-fallback-border": "#ccc",
|
||||||
|
"@dropdown-divider-bg": "#e5e5e5",
|
||||||
|
"@dropdown-link-color": "@gray-dark",
|
||||||
|
"@dropdown-link-hover-color": "darken(@gray-dark, 5%)",
|
||||||
|
"@dropdown-link-hover-bg": "#f5f5f5",
|
||||||
|
"@dropdown-link-active-color": "@component-active-color",
|
||||||
|
"@dropdown-link-active-bg": "@component-active-bg",
|
||||||
|
"@dropdown-link-disabled-color": "@gray-light",
|
||||||
|
"@dropdown-header-color": "@gray-light",
|
||||||
|
"@dropdown-caret-color": "#000",
|
||||||
|
"@screen-xs": "480px",
|
||||||
|
"@screen-xs-min": "@screen-xs",
|
||||||
|
"@screen-phone": "@screen-xs-min",
|
||||||
|
"@screen-sm": "768px",
|
||||||
|
"@screen-sm-min": "@screen-sm",
|
||||||
|
"@screen-tablet": "@screen-sm-min",
|
||||||
|
"@screen-md": "992px",
|
||||||
|
"@screen-md-min": "@screen-md",
|
||||||
|
"@screen-desktop": "@screen-md-min",
|
||||||
|
"@screen-lg": "1200px",
|
||||||
|
"@screen-lg-min": "@screen-lg",
|
||||||
|
"@screen-lg-desktop": "@screen-lg-min",
|
||||||
|
"@screen-xs-max": "(@screen-sm-min - 1)",
|
||||||
|
"@screen-sm-max": "(@screen-md-min - 1)",
|
||||||
|
"@screen-md-max": "(@screen-lg-min - 1)",
|
||||||
|
"@grid-columns": "12",
|
||||||
|
"@grid-gutter-width": "30px",
|
||||||
|
"@grid-float-breakpoint": "@screen-sm-min",
|
||||||
|
"@grid-float-breakpoint-max": "(@grid-float-breakpoint - 1)",
|
||||||
|
"@container-tablet": "(720px + @grid-gutter-width)",
|
||||||
|
"@container-sm": "@container-tablet",
|
||||||
|
"@container-desktop": "(940px + @grid-gutter-width)",
|
||||||
|
"@container-md": "@container-desktop",
|
||||||
|
"@container-large-desktop": "(1140px + @grid-gutter-width)",
|
||||||
|
"@container-lg": "@container-large-desktop",
|
||||||
|
"@navbar-height": "50px",
|
||||||
|
"@navbar-margin-bottom": "@line-height-computed",
|
||||||
|
"@navbar-border-radius": "@border-radius-base",
|
||||||
|
"@navbar-padding-horizontal": "floor((@grid-gutter-width / 2))",
|
||||||
|
"@navbar-padding-vertical": "((@navbar-height - @line-height-computed) / 2)",
|
||||||
|
"@navbar-collapse-max-height": "340px",
|
||||||
|
"@navbar-default-color": "#777",
|
||||||
|
"@navbar-default-bg": "#f8f8f8",
|
||||||
|
"@navbar-default-border": "darken(@navbar-default-bg, 6.5%)",
|
||||||
|
"@navbar-default-link-color": "#777",
|
||||||
|
"@navbar-default-link-hover-color": "#333",
|
||||||
|
"@navbar-default-link-hover-bg": "transparent",
|
||||||
|
"@navbar-default-link-active-color": "#555",
|
||||||
|
"@navbar-default-link-active-bg": "darken(@navbar-default-bg, 6.5%)",
|
||||||
|
"@navbar-default-link-disabled-color": "#ccc",
|
||||||
|
"@navbar-default-link-disabled-bg": "transparent",
|
||||||
|
"@navbar-default-brand-color": "@navbar-default-link-color",
|
||||||
|
"@navbar-default-brand-hover-color": "darken(@navbar-default-brand-color, 10%)",
|
||||||
|
"@navbar-default-brand-hover-bg": "transparent",
|
||||||
|
"@navbar-default-toggle-hover-bg": "#ddd",
|
||||||
|
"@navbar-default-toggle-icon-bar-bg": "#888",
|
||||||
|
"@navbar-default-toggle-border-color": "#ddd",
|
||||||
|
"@navbar-inverse-color": "lighten(@gray-light, 15%)",
|
||||||
|
"@navbar-inverse-bg": "#222",
|
||||||
|
"@navbar-inverse-border": "darken(@navbar-inverse-bg, 10%)",
|
||||||
|
"@navbar-inverse-link-color": "lighten(@gray-light, 15%)",
|
||||||
|
"@navbar-inverse-link-hover-color": "#fff",
|
||||||
|
"@navbar-inverse-link-hover-bg": "transparent",
|
||||||
|
"@navbar-inverse-link-active-color": "@navbar-inverse-link-hover-color",
|
||||||
|
"@navbar-inverse-link-active-bg": "darken(@navbar-inverse-bg, 10%)",
|
||||||
|
"@navbar-inverse-link-disabled-color": "#444",
|
||||||
|
"@navbar-inverse-link-disabled-bg": "transparent",
|
||||||
|
"@navbar-inverse-brand-color": "@navbar-inverse-link-color",
|
||||||
|
"@navbar-inverse-brand-hover-color": "#fff",
|
||||||
|
"@navbar-inverse-brand-hover-bg": "transparent",
|
||||||
|
"@navbar-inverse-toggle-hover-bg": "#333",
|
||||||
|
"@navbar-inverse-toggle-icon-bar-bg": "#fff",
|
||||||
|
"@navbar-inverse-toggle-border-color": "#333",
|
||||||
|
"@nav-link-padding": "10px 15px",
|
||||||
|
"@nav-link-hover-bg": "@gray-lighter",
|
||||||
|
"@nav-disabled-link-color": "@gray-light",
|
||||||
|
"@nav-disabled-link-hover-color": "@gray-light",
|
||||||
|
"@nav-tabs-border-color": "#ddd",
|
||||||
|
"@nav-tabs-link-hover-border-color": "@gray-lighter",
|
||||||
|
"@nav-tabs-active-link-hover-bg": "@body-bg",
|
||||||
|
"@nav-tabs-active-link-hover-color": "@gray",
|
||||||
|
"@nav-tabs-active-link-hover-border-color": "#ddd",
|
||||||
|
"@nav-tabs-justified-link-border-color": "#ddd",
|
||||||
|
"@nav-tabs-justified-active-link-border-color": "@body-bg",
|
||||||
|
"@nav-pills-border-radius": "@border-radius-base",
|
||||||
|
"@nav-pills-active-link-hover-bg": "@component-active-bg",
|
||||||
|
"@nav-pills-active-link-hover-color": "@component-active-color",
|
||||||
|
"@pagination-color": "@link-color",
|
||||||
|
"@pagination-bg": "#fff",
|
||||||
|
"@pagination-border": "#ddd",
|
||||||
|
"@pagination-hover-color": "@link-hover-color",
|
||||||
|
"@pagination-hover-bg": "@gray-lighter",
|
||||||
|
"@pagination-hover-border": "#ddd",
|
||||||
|
"@pagination-active-color": "#fff",
|
||||||
|
"@pagination-active-bg": "@brand-primary",
|
||||||
|
"@pagination-active-border": "@brand-primary",
|
||||||
|
"@pagination-disabled-color": "@gray-light",
|
||||||
|
"@pagination-disabled-bg": "#fff",
|
||||||
|
"@pagination-disabled-border": "#ddd",
|
||||||
|
"@pager-bg": "@pagination-bg",
|
||||||
|
"@pager-border": "@pagination-border",
|
||||||
|
"@pager-border-radius": "15px",
|
||||||
|
"@pager-hover-bg": "@pagination-hover-bg",
|
||||||
|
"@pager-active-bg": "@pagination-active-bg",
|
||||||
|
"@pager-active-color": "@pagination-active-color",
|
||||||
|
"@pager-disabled-color": "@pagination-disabled-color",
|
||||||
|
"@jumbotron-padding": "30px",
|
||||||
|
"@jumbotron-color": "inherit",
|
||||||
|
"@jumbotron-bg": "@gray-lighter",
|
||||||
|
"@jumbotron-heading-color": "inherit",
|
||||||
|
"@jumbotron-font-size": "ceil((@font-size-base * 1.5))",
|
||||||
|
"@jumbotron-heading-font-size": "ceil((@font-size-base * 4.5))",
|
||||||
|
"@state-success-text": "#3c763d",
|
||||||
|
"@state-success-bg": "#dff0d8",
|
||||||
|
"@state-success-border": "darken(spin(@state-success-bg, -10), 5%)",
|
||||||
|
"@state-info-text": "#31708f",
|
||||||
|
"@state-info-bg": "#d9edf7",
|
||||||
|
"@state-info-border": "darken(spin(@state-info-bg, -10), 7%)",
|
||||||
|
"@state-warning-text": "#8a6d3b",
|
||||||
|
"@state-warning-bg": "#fcf8e3",
|
||||||
|
"@state-warning-border": "darken(spin(@state-warning-bg, -10), 5%)",
|
||||||
|
"@state-danger-text": "#a94442",
|
||||||
|
"@state-danger-bg": "#f2dede",
|
||||||
|
"@state-danger-border": "darken(spin(@state-danger-bg, -10), 5%)",
|
||||||
|
"@tooltip-max-width": "200px",
|
||||||
|
"@tooltip-color": "#fff",
|
||||||
|
"@tooltip-bg": "#000",
|
||||||
|
"@tooltip-opacity": ".9",
|
||||||
|
"@tooltip-arrow-width": "5px",
|
||||||
|
"@tooltip-arrow-color": "@tooltip-bg",
|
||||||
|
"@popover-bg": "#fff",
|
||||||
|
"@popover-max-width": "276px",
|
||||||
|
"@popover-border-color": "rgba(0, 0, 0, .2)",
|
||||||
|
"@popover-fallback-border-color": "#ccc",
|
||||||
|
"@popover-title-bg": "darken(@popover-bg, 3%)",
|
||||||
|
"@popover-arrow-width": "10px",
|
||||||
|
"@popover-arrow-color": "@popover-bg",
|
||||||
|
"@popover-arrow-outer-width": "(@popover-arrow-width + 1)",
|
||||||
|
"@popover-arrow-outer-color": "fadein(@popover-border-color, 5%)",
|
||||||
|
"@popover-arrow-outer-fallback-color": "darken(@popover-fallback-border-color, 20%)",
|
||||||
|
"@label-default-bg": "@gray-light",
|
||||||
|
"@label-primary-bg": "@brand-primary",
|
||||||
|
"@label-success-bg": "@brand-success",
|
||||||
|
"@label-info-bg": "@brand-info",
|
||||||
|
"@label-warning-bg": "@brand-warning",
|
||||||
|
"@label-danger-bg": "@brand-danger",
|
||||||
|
"@label-color": "#fff",
|
||||||
|
"@label-link-hover-color": "#fff",
|
||||||
|
"@modal-inner-padding": "15px",
|
||||||
|
"@modal-title-padding": "15px",
|
||||||
|
"@modal-title-line-height": "@line-height-base",
|
||||||
|
"@modal-content-bg": "#fff",
|
||||||
|
"@modal-content-border-color": "rgba(0, 0, 0, .2)",
|
||||||
|
"@modal-content-fallback-border-color": "#999",
|
||||||
|
"@modal-backdrop-bg": "#000",
|
||||||
|
"@modal-backdrop-opacity": ".5",
|
||||||
|
"@modal-header-border-color": "#e5e5e5",
|
||||||
|
"@modal-footer-border-color": "@modal-header-border-color",
|
||||||
|
"@modal-lg": "900px",
|
||||||
|
"@modal-md": "600px",
|
||||||
|
"@modal-sm": "300px",
|
||||||
|
"@alert-padding": "15px",
|
||||||
|
"@alert-border-radius": "@border-radius-base",
|
||||||
|
"@alert-link-font-weight": "bold",
|
||||||
|
"@alert-success-bg": "@state-success-bg",
|
||||||
|
"@alert-success-text": "@state-success-text",
|
||||||
|
"@alert-success-border": "@state-success-border",
|
||||||
|
"@alert-info-bg": "@state-info-bg",
|
||||||
|
"@alert-info-text": "@state-info-text",
|
||||||
|
"@alert-info-border": "@state-info-border",
|
||||||
|
"@alert-warning-bg": "@state-warning-bg",
|
||||||
|
"@alert-warning-text": "@state-warning-text",
|
||||||
|
"@alert-warning-border": "@state-warning-border",
|
||||||
|
"@alert-danger-bg": "@state-danger-bg",
|
||||||
|
"@alert-danger-text": "@state-danger-text",
|
||||||
|
"@alert-danger-border": "@state-danger-border",
|
||||||
|
"@progress-bg": "#f5f5f5",
|
||||||
|
"@progress-bar-color": "#fff",
|
||||||
|
"@progress-border-radius": "@border-radius-base",
|
||||||
|
"@progress-bar-bg": "@brand-primary",
|
||||||
|
"@progress-bar-success-bg": "@brand-success",
|
||||||
|
"@progress-bar-warning-bg": "@brand-warning",
|
||||||
|
"@progress-bar-danger-bg": "@brand-danger",
|
||||||
|
"@progress-bar-info-bg": "@brand-info",
|
||||||
|
"@list-group-bg": "#fff",
|
||||||
|
"@list-group-border": "#ddd",
|
||||||
|
"@list-group-border-radius": "@border-radius-base",
|
||||||
|
"@list-group-hover-bg": "#f5f5f5",
|
||||||
|
"@list-group-active-color": "@component-active-color",
|
||||||
|
"@list-group-active-bg": "@component-active-bg",
|
||||||
|
"@list-group-active-border": "@list-group-active-bg",
|
||||||
|
"@list-group-active-text-color": "lighten(@list-group-active-bg, 40%)",
|
||||||
|
"@list-group-disabled-color": "@gray-light",
|
||||||
|
"@list-group-disabled-bg": "@gray-lighter",
|
||||||
|
"@list-group-disabled-text-color": "@list-group-disabled-color",
|
||||||
|
"@list-group-link-color": "#555",
|
||||||
|
"@list-group-link-hover-color": "@list-group-link-color",
|
||||||
|
"@list-group-link-heading-color": "#333",
|
||||||
|
"@panel-bg": "#fff",
|
||||||
|
"@panel-body-padding": "15px",
|
||||||
|
"@panel-heading-padding": "10px 15px",
|
||||||
|
"@panel-footer-padding": "@panel-heading-padding",
|
||||||
|
"@panel-border-radius": "@border-radius-base",
|
||||||
|
"@panel-inner-border": "#ddd",
|
||||||
|
"@panel-footer-bg": "#f5f5f5",
|
||||||
|
"@panel-default-text": "@gray-dark",
|
||||||
|
"@panel-default-border": "#ddd",
|
||||||
|
"@panel-default-heading-bg": "#f5f5f5",
|
||||||
|
"@panel-primary-text": "#fff",
|
||||||
|
"@panel-primary-border": "@brand-primary",
|
||||||
|
"@panel-primary-heading-bg": "@brand-primary",
|
||||||
|
"@panel-success-text": "@state-success-text",
|
||||||
|
"@panel-success-border": "@state-success-border",
|
||||||
|
"@panel-success-heading-bg": "@state-success-bg",
|
||||||
|
"@panel-info-text": "@state-info-text",
|
||||||
|
"@panel-info-border": "@state-info-border",
|
||||||
|
"@panel-info-heading-bg": "@state-info-bg",
|
||||||
|
"@panel-warning-text": "@state-warning-text",
|
||||||
|
"@panel-warning-border": "@state-warning-border",
|
||||||
|
"@panel-warning-heading-bg": "@state-warning-bg",
|
||||||
|
"@panel-danger-text": "@state-danger-text",
|
||||||
|
"@panel-danger-border": "@state-danger-border",
|
||||||
|
"@panel-danger-heading-bg": "@state-danger-bg",
|
||||||
|
"@thumbnail-padding": "4px",
|
||||||
|
"@thumbnail-bg": "@body-bg",
|
||||||
|
"@thumbnail-border": "#ddd",
|
||||||
|
"@thumbnail-border-radius": "@border-radius-base",
|
||||||
|
"@thumbnail-caption-color": "@text-color",
|
||||||
|
"@thumbnail-caption-padding": "9px",
|
||||||
|
"@well-bg": "#f5f5f5",
|
||||||
|
"@well-border": "darken(@well-bg, 7%)",
|
||||||
|
"@badge-color": "#fff",
|
||||||
|
"@badge-link-hover-color": "#fff",
|
||||||
|
"@badge-bg": "@gray-light",
|
||||||
|
"@badge-active-color": "@link-color",
|
||||||
|
"@badge-active-bg": "#fff",
|
||||||
|
"@badge-font-weight": "bold",
|
||||||
|
"@badge-line-height": "1",
|
||||||
|
"@badge-border-radius": "10px",
|
||||||
|
"@breadcrumb-padding-vertical": "8px",
|
||||||
|
"@breadcrumb-padding-horizontal": "15px",
|
||||||
|
"@breadcrumb-bg": "#f5f5f5",
|
||||||
|
"@breadcrumb-color": "#ccc",
|
||||||
|
"@breadcrumb-active-color": "@gray-light",
|
||||||
|
"@breadcrumb-separator": "\"/\"",
|
||||||
|
"@carousel-text-shadow": "0 1px 2px rgba(0, 0, 0, .6)",
|
||||||
|
"@carousel-control-color": "#fff",
|
||||||
|
"@carousel-control-width": "15%",
|
||||||
|
"@carousel-control-opacity": ".5",
|
||||||
|
"@carousel-control-font-size": "20px",
|
||||||
|
"@carousel-indicator-active-bg": "#fff",
|
||||||
|
"@carousel-indicator-border-color": "#fff",
|
||||||
|
"@carousel-caption-color": "#fff",
|
||||||
|
"@close-font-weight": "bold",
|
||||||
|
"@close-color": "#000",
|
||||||
|
"@close-text-shadow": "0 1px 0 #fff",
|
||||||
|
"@code-color": "#c7254e",
|
||||||
|
"@code-bg": "#f9f2f4",
|
||||||
|
"@kbd-color": "#fff",
|
||||||
|
"@kbd-bg": "#333",
|
||||||
|
"@pre-bg": "#f5f5f5",
|
||||||
|
"@pre-color": "@gray-dark",
|
||||||
|
"@pre-border-color": "#ccc",
|
||||||
|
"@pre-scrollable-max-height": "340px",
|
||||||
|
"@component-offset-horizontal": "180px",
|
||||||
|
"@text-muted": "@gray-light",
|
||||||
|
"@abbr-border-color": "@gray-light",
|
||||||
|
"@headings-small-color": "@gray-light",
|
||||||
|
"@blockquote-small-color": "@gray-light",
|
||||||
|
"@blockquote-font-size": "(@font-size-base * 1.25)",
|
||||||
|
"@blockquote-border-color": "@gray-lighter",
|
||||||
|
"@page-header-border-color": "@gray-lighter",
|
||||||
|
"@dl-horizontal-offset": "@component-offset-horizontal",
|
||||||
|
"@dl-horizontal-breakpoint": "@grid-float-breakpoint",
|
||||||
|
"@hr-border": "@gray-lighter"
|
||||||
|
},
|
||||||
|
"css": [
|
||||||
|
"dropdowns.less"
|
||||||
|
],
|
||||||
|
"js": [
|
||||||
|
"button.js",
|
||||||
|
"dropdown.js"
|
||||||
|
]
|
||||||
|
}
|
||||||
10425
server/src/main/resources/static/cadviewer/app/css/cvjs-core-styles.css
Normal file
6891
server/src/main/resources/static/cadviewer/app/css/cvjs_6.1.0.css
Normal file
6960
server/src/main/resources/static/cadviewer/app/css/cvjs_6.4.css
Normal file
7182
server/src/main/resources/static/cadviewer/app/css/cvjs_6.5.css
Normal file
7264
server/src/main/resources/static/cadviewer/app/css/cvjs_7.css
Normal file
1
server/src/main/resources/static/cadviewer/app/css/cvjs_jquery.qtip.min.css
vendored
Normal file
4
server/src/main/resources/static/cadviewer/app/css/font-awesome.min.css
vendored
Normal file
|
After Width: | Height: | Size: 418 B |
|
After Width: | Height: | Size: 312 B |
|
After Width: | Height: | Size: 205 B |
|
After Width: | Height: | Size: 262 B |
|
After Width: | Height: | Size: 348 B |
|
After Width: | Height: | Size: 207 B |
|
After Width: | Height: | Size: 5.7 KiB |
|
After Width: | Height: | Size: 278 B |