mirror of
https://gitee.com/kekingcn/file-online-preview.git
synced 2026-09-13 08:24:55 +00:00
Compare commits
2 Commits
pr731
...
codex/rede
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dd6e369e6a | ||
|
|
bd20546b6d |
@@ -52,6 +52,12 @@
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-devtools</artifactId>
|
||||
<scope>runtime</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- ========== 文档格式转换 ========== -->
|
||||
<dependency>
|
||||
@@ -366,4 +372,4 @@
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
</project>
|
||||
|
||||
16
server/src/main/bin/dev.sh
Executable file
16
server/src/main/bin/dev.sh
Executable file
@@ -0,0 +1,16 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
ROOT_DIR=$(cd "$(dirname "$0")/../../../.." || exit 1; pwd)
|
||||
SERVER_DIR="$ROOT_DIR/server"
|
||||
|
||||
if [ -n "$JAVA_HOME" ]; then
|
||||
export PATH="$JAVA_HOME/bin:$PATH"
|
||||
fi
|
||||
|
||||
cd "$SERVER_DIR" || exit 1
|
||||
|
||||
mvn spring-boot:run \
|
||||
-Dspring-boot.run.addResources=true \
|
||||
-Dspring-boot.run.jvmArguments="-Dfile.encoding=UTF-8 -Dspring.config.location=$SERVER_DIR/src/main/config/application.properties"
|
||||
@@ -46,12 +46,6 @@ public class WebConfig implements WebMvcConfigurer {
|
||||
filterUri.add("/onlinePreview");
|
||||
filterUri.add("/picturesPreview");
|
||||
filterUri.add("/getCorsFile");
|
||||
filterUri.add("/addTask");
|
||||
filterUri.add("/pdfjs/web/viewer.html");
|
||||
filterUri.add("/msg/index.html");
|
||||
filterUri.add("/eml/index.html");
|
||||
filterUri.add("/heic/index.html");
|
||||
filterUri.add("/drawio/index.html");
|
||||
TrustHostFilter filter = new TrustHostFilter();
|
||||
FilterRegistrationBean<TrustHostFilter> registrationBean = new FilterRegistrationBean<>();
|
||||
registrationBean.setFilter(filter);
|
||||
@@ -65,7 +59,6 @@ public class WebConfig implements WebMvcConfigurer {
|
||||
filterUri.add("/onlinePreview");
|
||||
filterUri.add("/picturesPreview");
|
||||
filterUri.add("/getCorsFile");
|
||||
filterUri.add("/addTask");
|
||||
TrustDirFilter filter = new TrustDirFilter();
|
||||
FilterRegistrationBean<TrustDirFilter> registrationBean = new FilterRegistrationBean<>();
|
||||
registrationBean.setFilter(filter);
|
||||
|
||||
@@ -38,7 +38,7 @@ public enum FileType {
|
||||
|
||||
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", "pptm"};
|
||||
private static final String[] PICTURE_TYPES = {"jpg", "jpeg", "png", "gif", "bmp", "ico", "jfif", "webp", "heic", "avif", "heif"};
|
||||
private static final String[] ARCHIVE_TYPES = {"rar", "zip", "jar", "7-zip", "tar", "gzip", "7z", "tgz"};
|
||||
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[] EML_TYPES = {"eml"};
|
||||
private static final String[] MSG_TYPES = {"msg"};
|
||||
|
||||
@@ -3,8 +3,6 @@ package cn.keking.service;
|
||||
import cn.keking.model.FileAttribute;
|
||||
import cn.keking.model.FileType;
|
||||
import cn.keking.service.cache.CacheService;
|
||||
import cn.keking.web.filter.TrustDirFilter;
|
||||
import cn.keking.web.filter.TrustHostFilter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -60,10 +58,6 @@ public class FileConvertQueueTask {
|
||||
try {
|
||||
url = cacheService.takeQueueTask();
|
||||
if (url != null) {
|
||||
if (!TrustHostFilter.isTrustedSourceUrl(url) || !TrustDirFilter.isTrustedFileUrl(url)) {
|
||||
logger.warn("拒绝处理不受信任的预览转换任务,url:{}", url);
|
||||
continue;
|
||||
}
|
||||
FileAttribute fileAttribute = fileHandlerService.getFileAttribute(url, null);
|
||||
FileType fileType = fileAttribute.getType();
|
||||
logger.info("正在处理预览转换任务,url:{},预览类型:{}", url, fileType);
|
||||
|
||||
@@ -29,7 +29,6 @@ import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.file.DirectoryStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.InvalidPathException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
@@ -148,28 +147,6 @@ public class FileController {
|
||||
}
|
||||
}
|
||||
|
||||
private Path getDemoBasePath() {
|
||||
return Paths.get(fileDir, demoDir).toAbsolutePath().normalize();
|
||||
}
|
||||
|
||||
private Path resolveDemoPath(String path) {
|
||||
Path demoBasePath = getDemoBasePath();
|
||||
try {
|
||||
if (ObjectUtils.isEmpty(path)) {
|
||||
return demoBasePath;
|
||||
}
|
||||
Path normalizedPath = demoBasePath.resolve(path).normalize();
|
||||
if (!normalizedPath.startsWith(demoBasePath)) {
|
||||
logger.warn("检测到非法目录访问,path:{}", path);
|
||||
return null;
|
||||
}
|
||||
return normalizedPath;
|
||||
} catch (InvalidPathException e) {
|
||||
logger.warn("解析目录路径失败,path:{}", path, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/fileUpload")
|
||||
public ReturnResponse<Object> fileUpload(@RequestParam("file") MultipartFile file,
|
||||
@RequestParam(value = "path", defaultValue = "") String path) {
|
||||
@@ -364,20 +341,17 @@ public class FileController {
|
||||
}
|
||||
|
||||
// ==================== 2. 构建路径和验证 ====================
|
||||
Path resolvedPath = resolveDemoPath(path);
|
||||
if (resolvedPath == null) {
|
||||
result.put("total", 0);
|
||||
result.put("data", Collections.emptyList());
|
||||
return result;
|
||||
String basePath = fileDir + demoPath;
|
||||
if (!ObjectUtils.isEmpty(path)) {
|
||||
basePath += path + File.separator;
|
||||
}
|
||||
|
||||
File currentDir = resolvedPath.toFile();
|
||||
File currentDir = new File(basePath);
|
||||
if (!currentDir.exists() || !currentDir.isDirectory()) {
|
||||
result.put("total", 0);
|
||||
result.put("data", Collections.emptyList());
|
||||
return result;
|
||||
}
|
||||
String basePath = resolvedPath.toString();
|
||||
|
||||
// ==================== 3. 收集所有文件路径 ====================
|
||||
List<Path> allPaths = new ArrayList<>();
|
||||
|
||||
@@ -31,6 +31,11 @@ public class IndexController {
|
||||
return "/main/integrated";
|
||||
}
|
||||
|
||||
@GetMapping( "/contact")
|
||||
public String go2Contact(){
|
||||
return "/main/contact";
|
||||
}
|
||||
|
||||
@GetMapping( "/")
|
||||
public String root() {
|
||||
return "/main/index";
|
||||
|
||||
@@ -8,8 +8,6 @@ import cn.keking.service.FilePreviewFactory;
|
||||
import cn.keking.service.cache.CacheService;
|
||||
import cn.keking.service.impl.OtherFilePreviewImpl;
|
||||
import cn.keking.utils.*;
|
||||
import cn.keking.web.filter.TrustDirFilter;
|
||||
import cn.keking.web.filter.TrustHostFilter;
|
||||
import fr.opensagres.xdocreport.core.io.IOUtils;
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
|
||||
@@ -233,11 +231,6 @@ public class OnlinePreviewController {
|
||||
logger.info("{},url:{}", errorMsg, fileUrls);
|
||||
return errorMsg;
|
||||
}
|
||||
if (!TrustHostFilter.isTrustedSourceUrl(fileUrls) || !TrustDirFilter.isTrustedFileUrl(fileUrls)) {
|
||||
String errorMsg = "访问不合法:来源地址不受信任!";
|
||||
logger.info("{},url:{}", errorMsg, fileUrls);
|
||||
return errorMsg;
|
||||
}
|
||||
logger.info("添加转码队列url:{}", fileUrls);
|
||||
cacheService.addQueueTask(fileUrls);
|
||||
return "success";
|
||||
|
||||
@@ -28,7 +28,7 @@ import java.util.Locale;
|
||||
public class TrustDirFilter implements Filter {
|
||||
|
||||
private String notTrustDirView;
|
||||
private static final Logger logger = LoggerFactory.getLogger(TrustDirFilter.class);
|
||||
private final Logger logger = LoggerFactory.getLogger(TrustDirFilter.class);
|
||||
|
||||
|
||||
@Override
|
||||
@@ -59,47 +59,6 @@ public class TrustDirFilter implements Filter {
|
||||
|
||||
}
|
||||
|
||||
public static boolean isTrustedFileUrl(String urlPath) {
|
||||
// 判断URL是否合法
|
||||
if (KkFileUtils.isIllegalFileName(urlPath) || !StringUtils.hasText(urlPath) || !WebUtils.isValidUrl(urlPath)) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
URL url = WebUtils.normalizedURL(urlPath);
|
||||
|
||||
if ("file".equals(url.getProtocol().toLowerCase(Locale.ROOT))) {
|
||||
String filePath = URLDecoder.decode(url.getPath(), StandardCharsets.UTF_8.name());
|
||||
// 将文件路径转换为File对象
|
||||
File targetFile = new File(filePath);
|
||||
// 将配置目录也转换为File对象
|
||||
File fileDir = new File(ConfigConstants.getFileDir());
|
||||
File localPreviewDir = new File(ConfigConstants.getLocalPreviewDir());
|
||||
try {
|
||||
// 获取规范路径
|
||||
String canonicalFilePath = targetFile.getCanonicalPath();
|
||||
String canonicalFileDir = fileDir.getCanonicalPath();
|
||||
String canonicalLocalPreviewDir = localPreviewDir.getCanonicalPath();
|
||||
return isSubDirectory(canonicalFileDir, canonicalFilePath) || isSubDirectory(canonicalLocalPreviewDir, canonicalFilePath);
|
||||
} catch (IOException e) {
|
||||
LoggerFactory.getLogger(TrustDirFilter.class).warn("获取规范路径失败,使用原始路径比较", e);
|
||||
String absFilePath = targetFile.getAbsolutePath();
|
||||
String absFileDir = fileDir.getAbsolutePath();
|
||||
String absLocalPreviewDir = localPreviewDir.getAbsolutePath();
|
||||
absFilePath = absFilePath.replace('\\', '/');
|
||||
absFileDir = absFileDir.replace('\\', '/');
|
||||
absLocalPreviewDir = absLocalPreviewDir.replace('\\', '/');
|
||||
if (!absFileDir.endsWith("/")) absFileDir += "/";
|
||||
if (!absLocalPreviewDir.endsWith("/")) absLocalPreviewDir += "/";
|
||||
return absFilePath.startsWith(absFileDir) || absFilePath.startsWith(absLocalPreviewDir);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} catch (IOException | GalimatiasParseException e) {
|
||||
LoggerFactory.getLogger(TrustDirFilter.class).error("解析URL异常,url:{}", urlPath, e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean allowPreview(String urlPath) {
|
||||
// 判断URL是否合法
|
||||
if (KkFileUtils.isIllegalFileName(urlPath) || !StringUtils.hasText(urlPath) || !WebUtils.isValidUrl(urlPath)) {
|
||||
@@ -148,7 +107,7 @@ public class TrustDirFilter implements Filter {
|
||||
/**
|
||||
* 检查子路径是否在父路径下(跨平台)
|
||||
*/
|
||||
private static boolean isSubDirectory(String parentDir, String childPath) {
|
||||
private boolean isSubDirectory(String parentDir, String childPath) {
|
||||
try {
|
||||
File parent = new File(parentDir);
|
||||
File child = new File(childPath);
|
||||
|
||||
@@ -48,10 +48,7 @@ public class TrustHostFilter implements Filter {
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
|
||||
String url = request.getParameter("file");
|
||||
if (url == null || url.trim().isEmpty()) {
|
||||
url = WebUtils.getSourceUrl(request);
|
||||
}
|
||||
String url = WebUtils.getSourceUrl(request);
|
||||
String host = WebUtils.getHost(url);
|
||||
if (isNotTrustHost(host) || !WebUtils.isValidUrl(url)) {
|
||||
String currentHost = host == null ? "UNKNOWN" : host;
|
||||
@@ -70,14 +67,6 @@ public class TrustHostFilter implements Filter {
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isTrustedSourceUrl(String url) {
|
||||
if (!WebUtils.isValidUrl(url)) {
|
||||
return false;
|
||||
}
|
||||
String host = WebUtils.getHost(url);
|
||||
return !new TrustHostFilter().isNotTrustHost(host);
|
||||
}
|
||||
|
||||
public boolean isNotTrustHost(String host) {
|
||||
if (host == null || host.trim().isEmpty()) {
|
||||
logger.warn("主机名为空或无效,拒绝访问");
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,302 @@
|
||||
|
||||
<div id="IconMenuPanel">
|
||||
<div id="rdialogx_d" class="float_dialog2_fixed">
|
||||
<div id="icon_menu_panel" style="border:1" class="div_icon_menu_panel" >
|
||||
|
||||
<table id="savelinksHeaderTable" width="270" border="0" cellspacing="0" border-spacing="0" id="savelinks_table">
|
||||
<tr>
|
||||
<td>
|
||||
<div id="cv_link2">
|
||||
<div id="dummy_header" class="tagSaveLinkHeader" style="text-indent: 1em;">Location Setup</div>
|
||||
<div style="float:right;margin-right:-34px;margin-top:-24px;" id="CloseObjectMenuX"></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
<table id="savelinksTable" width="270" border="0" cellspacing="0" border-spacing="0">
|
||||
<tr>
|
||||
<td>
|
||||
<div id="dummy">
|
||||
<canvas width="5" height="5"></canvas>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="whiteUnderbar">
|
||||
xxxx
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div id="save_drawing">
|
||||
<img id="save_drawing_image" class="icon_img" src="../app/images/tools/SaveChanges_240x22_Inactive.png" border="0">
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<div id="dummy">
|
||||
<canvas width="5" height="5"></canvas>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
<div id="link_tags_table">
|
||||
|
||||
<table id="savelinksTable_select" width="270" border="0" cellspacing="0" border-spacing="0" id="savelinks_table">
|
||||
<tr>
|
||||
<td>
|
||||
<div class="whiteUnderbar">
|
||||
____
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div id="unlink_location" class="select_link_text">Unlink Location</div>
|
||||
</td>
|
||||
<td>
|
||||
<div id="done_editing_location" class="select_link_text"></div>
|
||||
</td>
|
||||
<td>
|
||||
<div id="edit_cancel_location" class="select_link_text">Edit Fields</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<div id="dummy">
|
||||
<canvas width="5" height="5"></canvas>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
||||
<div id="location_text_dynamic">
|
||||
|
||||
<table id="locationTagsTable2" width="270" border="0" cellspacing="0" border-spacing="0">
|
||||
<tr>
|
||||
<td>
|
||||
<div id="cv_link10_id_datalayer_name">
|
||||
<div id="loc_text" class="location_text">Connector</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="whiteUnderbar">
|
||||
_
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div id="cv_link11" class="dropdown">
|
||||
<span class="dropdown-toggle" role="button" data-toggle="dropdown" href="#" data-target="#" id="drop_link_spaces">None Selected<b class="caret"></b></span>
|
||||
<ul id="spaces_drawing" class="dropdown-menu" role="menu" aria-labelledby="drop_link_spaces">
|
||||
</ul>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<canvas width="10" height="10"></canvas>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<div id="cv_link12A">
|
||||
<div id="layer_text" class="location_text">Layer</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="whiteUnderbar">
|
||||
_
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div id="cv_link13A">
|
||||
<input id="layer_tag" type="text" class="input_tags" value=""/>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<div id="cv_link12">
|
||||
<div id="loc_text" class="location_text">Type</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="whiteUnderbar">
|
||||
_
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div id="cv_link13">
|
||||
<input id="type_tag" type="text" class="input_tags" value=""/>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<div id="cv_link14">
|
||||
<div id="loc_text" class="location_text">Occupancy</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="whiteUnderbar">
|
||||
_
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<input id="occupancy_tag" type="text" class="input_tags" value=""/>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td VALIGN=TOP>
|
||||
<div id="loc_text" class="location_text_tags">Tags</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="whiteUnderbar">
|
||||
_
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div id="cv_link16">
|
||||
<textarea id="other_tags" class="styled_text_area"></textarea>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div id="location_text_static">
|
||||
|
||||
<table id="locationTagsTable" width="270" border="0" cellspacing="0" border-spacing="0" >
|
||||
<tr>
|
||||
<td>
|
||||
<div id="cv_link10_s">
|
||||
<div id="loc_text" class="location_text">Name</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="whiteUnderbar">
|
||||
_
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div id="cv_link11_s" class="location_text">
|
||||
<div id="location_s" class="location_text2">None Selected</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<div id="cv_link12A_s">
|
||||
<div id="loc_text" class="location_text">Layer</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="whiteUnderbar">
|
||||
_
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div id="cv_link13A_s">
|
||||
<div id="layer_s" class="location_text2">-</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<div id="cv_link12_s">
|
||||
<div id="loc_text" class="location_text">Type</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="whiteUnderbar">
|
||||
_
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div id="cv_link13_s">
|
||||
<div id="type_s" class="location_text2">-</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<div id="cv_link14_s">
|
||||
<div id="loc_text" class="location_text">Occupancy</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="whiteUnderbar">
|
||||
_
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div id="cv_link15_s">
|
||||
|
||||
<div id="occupancy_s" class="location_text2">-</div>
|
||||
|
||||
</div
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td VALIGN=TOP>
|
||||
<div id="cv_link16_s">
|
||||
<div id="loc_text" class="location_text_tags2">Tags</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="whiteUnderbar">
|
||||
_
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div id="cv_link17_s">
|
||||
<div id="tags_s" class="location_text2">-</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,308 @@
|
||||
|
||||
<div id="IconMenuPanel">
|
||||
<div id="rdialogx_d" class="float_dialog2_fixed">
|
||||
<div id="icon_menu_panel" style="border:1" class="div_icon_menu_panel" >
|
||||
|
||||
<table id="savelinksHeaderTable" width="270" border="0" cellspacing="0" border-spacing="0" id="savelinks_table">
|
||||
<tr>
|
||||
<td>
|
||||
<div id="cv_link2">
|
||||
<div id="dummy_header" class="tagSaveLinkHeader" style="text-indent: 1em;">Location Setup</div>
|
||||
<div style="float:right;margin-right:-34px;margin-top:-24px;" id="CloseObjectMenuX"></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
<table id="savelinksTable" width="270" border="0" cellspacing="0" border-spacing="0">
|
||||
<tr>
|
||||
<td>
|
||||
<div id="dummy">
|
||||
<canvas width="5" height="5"></canvas>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="whiteUnderbar">
|
||||
xxxx
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div id="save_drawing">
|
||||
<img id="save_drawing_image" class="icon_img" src="../app/images/tools/SaveChanges_240x22_Inactive.png" border="0">
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<div id="dummy">
|
||||
<canvas width="5" height="5"></canvas>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
<div id="link_tags_table">
|
||||
|
||||
<table id="savelinksTable_select" width="270" border="0" cellspacing="0" border-spacing="0" id="savelinks_table">
|
||||
<tr>
|
||||
<td>
|
||||
<div class="whiteUnderbar">
|
||||
____
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div id="unlink_location" class="select_link_text">Unlink Location</div>
|
||||
</td>
|
||||
<td>
|
||||
<div id="done_editing_location" class="select_link_text"></div>
|
||||
</td>
|
||||
<td>
|
||||
<div id="edit_cancel_location" class="select_link_text">Edit Fields</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<div id="dummy">
|
||||
<canvas width="5" height="5"></canvas>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
||||
<div id="location_text_dynamic">
|
||||
|
||||
<table id="locationTagsTable2" width="270" border="0" cellspacing="0" border-spacing="0">
|
||||
<tr>
|
||||
<td>
|
||||
<div id="cv_link10_id_datalayer_name">
|
||||
<div id="loc_text" class="location_text">Connector</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="whiteUnderbar">
|
||||
_
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div id="cv_link11" class="dropdown">
|
||||
<span class="dropdown-toggle" role="button" data-toggle="dropdown" href="#" data-target="#" id="drop_link_spaces">None Selected<b class="caret"></b></span>
|
||||
<ul id="spaces_drawing" class="dropdown-menu" role="menu" aria-labelledby="drop_link_spaces">
|
||||
</ul>
|
||||
</div>
|
||||
<div id="cv_link11_B2">
|
||||
<input id="spaces_manual_tag" type="text" class="input_tags" value=""/>
|
||||
</div>
|
||||
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<div id="cv_link11_B3">
|
||||
<canvas width="10" height="10"></canvas>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<div id="cv_link12A">
|
||||
<div id="layer_text" class="location_text">Layer</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="whiteUnderbar">
|
||||
_
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div id="cv_link13A">
|
||||
<input id="layer_tag" type="text" class="input_tags" value=""/>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<div id="cv_link12">
|
||||
<div id="loc_text" class="location_text">Type</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="whiteUnderbar">
|
||||
_
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div id="cv_link13">
|
||||
<input id="type_tag" type="text" class="input_tags" value=""/>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<div id="cv_link14">
|
||||
<div id="loc_text" class="location_text">Occupancy</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="whiteUnderbar">
|
||||
_
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<input id="occupancy_tag" type="text" class="input_tags" value=""/>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td VALIGN=TOP>
|
||||
<div id="loc_text" class="location_text_tags">Tags</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="whiteUnderbar">
|
||||
_
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div id="cv_link16">
|
||||
<textarea id="other_tags" class="styled_text_area"></textarea>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div id="location_text_static">
|
||||
|
||||
<table id="locationTagsTable" width="270" border="0" cellspacing="0" border-spacing="0" >
|
||||
<tr>
|
||||
<td>
|
||||
<div id="cv_link10_s">
|
||||
<div id="loc_text" class="location_text">Name</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="whiteUnderbar">
|
||||
_
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div id="cv_link11_s" class="location_text">
|
||||
<div id="location_s" class="location_text2">None Selected</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<div id="cv_link12A_s">
|
||||
<div id="loc_text" class="location_text">Layer</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="whiteUnderbar">
|
||||
_
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div id="cv_link13A_s">
|
||||
<div id="layer_s" class="location_text2">-</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<div id="cv_link12_s">
|
||||
<div id="loc_text" class="location_text">Type</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="whiteUnderbar">
|
||||
_
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div id="cv_link13_s">
|
||||
<div id="type_s" class="location_text2">-</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<div id="cv_link14_s">
|
||||
<div id="loc_text" class="location_text">Occupancy</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="whiteUnderbar">
|
||||
_
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div id="cv_link15_s">
|
||||
|
||||
<div id="occupancy_s" class="location_text2">-</div>
|
||||
|
||||
</div
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td VALIGN=TOP>
|
||||
<div id="cv_link16_s">
|
||||
<div id="loc_text" class="location_text_tags2">Tags</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="whiteUnderbar">
|
||||
_
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div id="cv_link17_s">
|
||||
<div id="tags_s" class="location_text2">-</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1356
server/src/main/resources/static/css/main-pages.css
Normal file
1356
server/src/main/resources/static/css/main-pages.css
Normal file
File diff suppressed because it is too large
Load Diff
120722
server/src/main/resources/static/drawio/js/app.min.js
vendored
120722
server/src/main/resources/static/drawio/js/app.min.js
vendored
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Microsoft Excel</title><path d="M23 1.5q.41 0 .7.3.3.29.3.7v19q0 .41-.3.7-.29.3-.7.3H7q-.41 0-.7-.3-.3-.29-.3-.7V18H1q-.41 0-.7-.3-.3-.29-.3-.7V7q0-.41.3-.7Q.58 6 1 6h5V2.5q0-.41.3-.7.29-.3.7-.3zM6 13.28l1.42 2.66h2.14l-2.38-3.87 2.34-3.8H7.46l-1.3 2.4-.05.08-.04.09-.64-1.28-.66-1.29H2.59l2.27 3.82-2.48 3.85h2.16zM14.25 21v-3H7.5v3zm0-4.5v-3.75H12v3.75zm0-5.25V7.5H12v3.75zm0-5.25V3H7.5v3zm8.25 15v-3h-6.75v3zm0-4.5v-3.75h-6.75v3.75zm0-5.25V7.5h-6.75v3.75zm0-5.25V3h-6.75v3Z"/></svg>
|
||||
|
After Width: | Height: | Size: 563 B |
@@ -0,0 +1 @@
|
||||
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Adobe Acrobat Reader</title><path d="M23.63 15.3c-.71-.745-2.166-1.17-4.224-1.17-1.1 0-2.377.106-3.761.354a19.443 19.443 0 0 1-2.307-2.661c-.532-.71-.994-1.49-1.42-2.236.817-2.484 1.207-4.507 1.207-5.962 0-1.632-.603-3.336-2.342-3.336-.532 0-1.065.32-1.349.781-.78 1.384-.425 4.4.923 7.381a60.277 60.277 0 0 1-1.703 4.507c-.568 1.349-1.207 2.733-1.917 4.01C2.834 18.53.314 20.34.03 21.758c-.106.533.071 1.03.462 1.42.142.107.639.533 1.49.533 2.59 0 5.323-4.188 6.707-6.707 1.065-.355 2.13-.71 3.194-.994a34.963 34.963 0 0 1 3.407-.745c2.732 2.448 5.145 2.839 6.352 2.839 1.49 0 2.023-.604 2.2-1.1.32-.64.106-1.349-.213-1.704zm-1.42 1.03c-.107.532-.64.887-1.384.887-.213 0-.39-.036-.604-.071-1.348-.32-2.626-.994-3.903-2.059a17.717 17.717 0 0 1 2.98-.248c.746 0 1.385.035 1.81.142.497.106 1.278.426 1.1 1.348zm-7.524-1.668a38.01 38.01 0 0 0-2.945.674 39.68 39.68 0 0 0-2.52.745 40.05 40.05 0 0 0 1.207-2.555c.426-.994.78-2.023 1.136-2.981.354.603.745 1.207 1.135 1.739a50.127 50.127 0 0 0 1.987 2.378zM10.038 1.46a.768.768 0 0 1 .674-.425c.745 0 .887.851.887 1.526 0 1.135-.355 2.874-.958 4.861-1.03-2.768-1.1-5.074-.603-5.962zM6.134 17.997c-1.81 2.981-3.549 4.826-4.613 4.826a.872.872 0 0 1-.532-.177c-.213-.213-.32-.461-.249-.745.213-1.065 2.271-2.555 5.394-3.904Z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
@@ -0,0 +1 @@
|
||||
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Microsoft PowerPoint</title><path d="M13.5 1.5q1.453 0 2.795.375 1.342.375 2.508 1.06 1.166.686 2.12 1.641.956.955 1.641 2.121.686 1.166 1.061 2.508Q24 10.547 24 12q0 1.453-.375 2.795-.375 1.342-1.06 2.508-.686 1.166-1.641 2.12-.955.956-2.121 1.641-1.166.686-2.508 1.061-1.342.375-2.795.375-1.29 0-2.52-.305-1.23-.304-2.337-.884-1.108-.58-2.063-1.418-.955-.838-1.693-1.893H.997q-.411 0-.704-.293T0 17.004V6.996q0-.41.293-.703T.996 6h3.89q.739-1.055 1.694-1.893.955-.837 2.063-1.418 1.107-.58 2.337-.884Q12.21 1.5 13.5 1.5zm.75 1.535v8.215h8.215q-.14-1.64-.826-3.076-.686-1.436-1.782-2.531-1.095-1.096-2.537-1.782-1.441-.685-3.07-.826zm-5.262 7.57q0-.68-.228-1.166-.229-.486-.627-.79-.399-.305-.938-.446-.539-.14-1.172-.14H2.848v7.863h1.84v-2.742H5.93q.574 0 1.119-.17t.978-.493q.434-.322.698-.802.263-.48.263-1.114zM13.5 21q1.172 0 2.262-.287t2.056-.82q.967-.534 1.776-1.278.808-.744 1.418-1.664.61-.92.984-1.986.375-1.067.469-2.227h-9.703V3.035q-1.735.14-3.27.908T6.797 6h4.207q.41 0 .703.293t.293.703v10.008q0 .41-.293.703t-.703.293H6.797q.644.715 1.412 1.271.768.557 1.623.944.855.387 1.781.586Q12.54 21 13.5 21zM5.812 9.598q.575 0 .915.228.34.229.34.838 0 .27-.124.44-.123.17-.31.275-.188.105-.422.146-.234.041-.445.041H4.687V9.598Z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
@@ -0,0 +1 @@
|
||||
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Microsoft Word</title><path d="M23.004 1.5q.41 0 .703.293t.293.703v19.008q0 .41-.293.703t-.703.293H6.996q-.41 0-.703-.293T6 21.504V18H.996q-.41 0-.703-.293T0 17.004V6.996q0-.41.293-.703T.996 6H6V2.496q0-.41.293-.703t.703-.293zM6.035 11.203l1.442 4.735h1.64l1.57-7.876H9.036l-.937 4.653-1.325-4.5H5.38l-1.406 4.523-.938-4.675H1.312l1.57 7.874h1.641zM22.5 21v-3h-15v3zm0-4.5v-3.75H12v3.75zm0-5.25V7.5H12v3.75zm0-5.25V3h-15v3Z"/></svg>
|
||||
|
After Width: | Height: | Size: 510 B |
File diff suppressed because one or more lines are too long
@@ -23083,26 +23083,24 @@ initCom(PDFViewerApplication);
|
||||
}
|
||||
{
|
||||
const HOSTED_VIEWER_ORIGINS = new Set(["null", "http://mozilla.github.io", "https://mozilla.github.io"]);
|
||||
var validateFileURL = function (file) {
|
||||
if (!file) {
|
||||
return;
|
||||
}
|
||||
const viewerOrigin = URL.parse(window.location)?.origin || "null";
|
||||
if (HOSTED_VIEWER_ORIGINS.has(viewerOrigin)) {
|
||||
return;
|
||||
}
|
||||
/* 注释掉跨域检查
|
||||
const fileOrigin = URL.parse(file, window.location)?.origin;
|
||||
if (fileOrigin === viewerOrigin) {
|
||||
return;
|
||||
}
|
||||
const ex = new Error("file origin does not match viewer's");
|
||||
PDFViewerApplication._documentError("pdfjs-loading-error", {
|
||||
message: ex.message
|
||||
});
|
||||
throw ex;
|
||||
*/
|
||||
};
|
||||
var validateFileURL = function (file) {
|
||||
if (!file) {
|
||||
return;
|
||||
}
|
||||
const viewerOrigin = URL.parse(window.location)?.origin || "null";
|
||||
if (HOSTED_VIEWER_ORIGINS.has(viewerOrigin)) {
|
||||
return;
|
||||
}
|
||||
const fileOrigin = URL.parse(file, window.location)?.origin;
|
||||
if (fileOrigin === viewerOrigin) {
|
||||
return;
|
||||
}
|
||||
const ex = new Error("file origin does not match viewer's");
|
||||
PDFViewerApplication._documentError("pdfjs-loading-error", {
|
||||
message: ex.message
|
||||
});
|
||||
throw ex;
|
||||
};
|
||||
var onFileInputChange = function (evt) {
|
||||
if (this.pdfViewer?.isInPresentationMode) {
|
||||
return;
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
|
||||
<!-- modeler distro -->
|
||||
<script src="bpmn/bpmn-modeler.development.js"></script>
|
||||
<script src="js/jquery-3.7.1.min.js"></script>
|
||||
<script src="js/jquery-3.6.1.min.js"></script>
|
||||
|
||||
<!-- app -->
|
||||
<script>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<link href="cadviewer/app/css/jquery-ui-1.13.2.min.css" media="screen" rel="stylesheet" type="text/css" />
|
||||
|
||||
<!-- 核心脚本 - 最小化依赖 -->
|
||||
<script src="js/jquery-3.7.1.min.js" type="text/javascript"></script>
|
||||
<script src="js/jquery-3.6.1.min.js" type="text/javascript"></script>
|
||||
<script src="cadviewer/app/js/jquery-ui-1.13.2.min.js" type="text/javascript"></script>
|
||||
<script src="cadviewer/app/js/eve.js" type="text/javascript"></script>
|
||||
<script src="cadviewer/app/js/xml2json.min.js" type="text/javascript"></script>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<meta name="viewport" content="width=device-width, user-scalable=yes, initial-scale=1.0">
|
||||
<title>${file.name}代码预览</title>
|
||||
<#include "*/commonHeader.ftl">
|
||||
<script src="js/jquery-3.7.1.min.js" type="text/javascript"></script>
|
||||
<script src="js/jquery-3.6.1.min.js" type="text/javascript"></script>
|
||||
<link rel="stylesheet" href="bootstrap/css/bootstrap.min.css"/>
|
||||
<script src="bootstrap/js/bootstrap.min.js" type="text/javascript"></script>
|
||||
<link rel="stylesheet" href="highlight/default.min.css">
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>${file.name}压缩包预览</title>
|
||||
<script src="js/jquery-3.7.1.min.js"></script>
|
||||
<script src="js/jquery-3.6.1.min.js"></script>
|
||||
<#include "*/commonHeader.ftl">
|
||||
<script src="js/base64.min.js" type="text/javascript"></script>
|
||||
<link href="css/zTreeStyle.css" rel="stylesheet" type="text/css">
|
||||
|
||||
@@ -1,79 +1,43 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh">
|
||||
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, user-scalable=yes, initial-scale=1.0">
|
||||
<title>draw.io 文件预览</title>
|
||||
<title>drawio文件预览</title>
|
||||
<#include "*/commonHeader.ftl">
|
||||
<script src="js/base64.min.js" type="text/javascript"></script>
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
iframe {
|
||||
display: block;
|
||||
width: 100%;
|
||||
border: none;
|
||||
}
|
||||
</style>
|
||||
<script src="js/base64.min.js" type="text/javascript"></script>
|
||||
</head>
|
||||
<body>
|
||||
<iframe id="drawioFrame" title="draw.io 预览"></iframe>
|
||||
|
||||
<iframe src="" width="100%" frameborder="0"></iframe>
|
||||
<#if currentUrl?contains("http://") || currentUrl?contains("https://")>
|
||||
<#assign finalUrl = "${currentUrl}">
|
||||
<#assign finalUrl="${currentUrl}">
|
||||
<#else>
|
||||
<#assign finalUrl = "${baseUrl}${currentUrl}">
|
||||
<#assign finalUrl="${baseUrl}${currentUrl}">
|
||||
</#if>
|
||||
<script>
|
||||
var url = '${finalUrl}';
|
||||
var kkagent = '${kkagent}';
|
||||
var baseUrl = '${baseUrl}'.endsWith('/') ? '${baseUrl}' : '${baseUrl}' + '/';
|
||||
if (kkagent === 'true' || !url.startsWith(baseUrl)) {
|
||||
url = baseUrl + 'getCorsFile?urlPath=' + encodeURIComponent(Base64.encode(url))+ "&key=${kkkey}";
|
||||
}
|
||||
document.getElementsByTagName('iframe')[0].src = "${baseUrl}drawio/index.html?lightbox=1&gapi=0&db=0&od=0&tr=0&gh=0&gl=0&edit=_blank&lang=zh#U"+ encodeURIComponent(url)+"";
|
||||
document.getElementsByTagName('iframe')[0].height = document.documentElement.clientHeight - 10;
|
||||
/**
|
||||
* 页面变化调整高度
|
||||
*/
|
||||
window.onresize = function () {
|
||||
var fm = document.getElementsByTagName("iframe")[0];
|
||||
fm.height = window.document.documentElement.clientHeight - 10;
|
||||
}
|
||||
|
||||
<script>
|
||||
(function() {
|
||||
// 获取最终文件地址
|
||||
var fileUrl = '${finalUrl}';
|
||||
var kkagent = '${kkagent}';
|
||||
var baseUrl = '${baseUrl}';
|
||||
if (!baseUrl.endsWith('/')) baseUrl += '/';
|
||||
|
||||
// 跨域或代理处理
|
||||
if (kkagent === 'true' || !fileUrl.startsWith(baseUrl)) {
|
||||
fileUrl = baseUrl + 'getCorsFile?urlPath=' + encodeURIComponent(Base64.encode(fileUrl)) + "&key=${kkkey}";
|
||||
}
|
||||
|
||||
var encodedUrl = encodeURIComponent(fileUrl);
|
||||
var drawioBase = baseUrl + "drawio/index.html";
|
||||
|
||||
// 构建查询参数(保留原有所有参数,增加 file=)
|
||||
var params = new URLSearchParams({
|
||||
lightbox: '1',
|
||||
gapi: '0',
|
||||
db: '0',
|
||||
od: '0',
|
||||
tr: '0',
|
||||
gh: '0',
|
||||
gl: '0',
|
||||
edit: '_blank',
|
||||
lang: 'zh',
|
||||
file: fileUrl // 新增 ?file= 参数
|
||||
});
|
||||
|
||||
// 最终 URL:查询参数 + 原有的 #Uhash
|
||||
var iframeSrc = drawioBase + '?' + params.toString() + '#Uhttp://127.0.0.1/1.drawio';
|
||||
|
||||
var iframe = document.getElementById('drawioFrame');
|
||||
iframe.src = iframeSrc;
|
||||
iframe.height = document.documentElement.clientHeight - 10;
|
||||
|
||||
// 窗口大小变化时调整 iframe 高度
|
||||
window.addEventListener('resize', function() {
|
||||
iframe.height = document.documentElement.clientHeight - 10;
|
||||
});
|
||||
|
||||
// 可选:初始化水印(假设 initWaterMark 已定义)
|
||||
if (typeof initWaterMark === 'function') {
|
||||
window.addEventListener('load', initWaterMark);
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
/*初始化水印*/
|
||||
window.onload = function () {
|
||||
initWaterMark();
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
</html>
|
||||
|
||||
@@ -1,159 +1,44 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>暂不支持预览</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
<meta charset="utf-8"/>
|
||||
<style type="text/css">
|
||||
body {
|
||||
font-family: 'Segoe UI', Roboto, 'Helvetica Neue', sans-serif;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 20px;
|
||||
margin: 0 auto;
|
||||
width: 900px;
|
||||
background-color: #CCB;
|
||||
}
|
||||
|
||||
.error-card {
|
||||
max-width: 600px;
|
||||
width: 100%;
|
||||
background: #ffffff;
|
||||
border-radius: 32px;
|
||||
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
|
||||
text-align: center;
|
||||
padding: 40px 32px 48px;
|
||||
transition: transform 0.2s ease;
|
||||
.container {
|
||||
width: 700px;
|
||||
height: 700px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.error-card:hover {
|
||||
transform: translateY(-4px);
|
||||
img {
|
||||
width: auto;
|
||||
height: auto;
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
padding-bottom: 36px;
|
||||
}
|
||||
|
||||
.icon-container {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.icon-container img {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 28px;
|
||||
font-weight: 700;
|
||||
color: #1e293b;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.file-type-badge {
|
||||
background: #f1f5f9;
|
||||
color: #0f172a;
|
||||
font-weight: 600;
|
||||
display: inline-block;
|
||||
padding: 6px 16px;
|
||||
border-radius: 40px;
|
||||
font-size: 14px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.reason-box {
|
||||
background: #fef2f2;
|
||||
border-left: 4px solid #dc2626;
|
||||
padding: 16px 20px;
|
||||
border-radius: 16px;
|
||||
margin: 20px 0;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.reason-label {
|
||||
font-weight: 600;
|
||||
color: #991b1b;
|
||||
margin-bottom: 8px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.reason-message {
|
||||
color: #1e293b;
|
||||
font-size: 15px;
|
||||
line-height: 1.5;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.community-link {
|
||||
background: #f8fafc;
|
||||
border-radius: 24px;
|
||||
padding: 16px 20px;
|
||||
margin-top: 28px;
|
||||
border: 1px solid #e2e8f0;
|
||||
}
|
||||
|
||||
.community-link p {
|
||||
font-size: 15px;
|
||||
color: #334155;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.community-link a {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
background: #3b82f6;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
padding: 10px 24px;
|
||||
border-radius: 40px;
|
||||
font-weight: 500;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
|
||||
.community-link a:hover {
|
||||
background: #2563eb;
|
||||
}
|
||||
|
||||
.footer-note {
|
||||
margin-top: 24px;
|
||||
font-size: 13px;
|
||||
color: #94a3b8;
|
||||
span {
|
||||
display: block;
|
||||
font-size: 20px;
|
||||
color: blue;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="error-card">
|
||||
<div class="icon-container">
|
||||
<!-- Base64 内嵌 SVG:文档 + 问号,表示不支持 -->
|
||||
<img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iI2Y1OTAwYiIgd2lkdGg9IjEyMCIgaGVpZ2h0PSIxMjAiPgogIDxwYXRoIGQ9Ik0yMCA2aC04bC0yLTJINGMyLTEuMSAwLTEgMCAwdjE0YzAgMS4xLjkgMiAyIDJoMTZjMS4xIDAgMi0uOSAyLTJWN2MwLTEuMS0uOS0yLTItMnptLTIgMTJINlY4aDQuMjFsMiAySDE4djh6bS01LTRoLTR2LTJoNHYyem0wLTNoLTRWOWg0djJ6Ii8+Cjwvc3ZnPg==" alt="不支持预览">
|
||||
</div>
|
||||
<h1>暂不支持在线预览</h1>
|
||||
<div class="file-type-badge">
|
||||
📄 文件类型:${fileType}
|
||||
</div>
|
||||
<div class="reason-box">
|
||||
<div class="reason-label">
|
||||
⚠️ 具体原因
|
||||
</div>
|
||||
<div class="reason-message">
|
||||
${msg}
|
||||
</div>
|
||||
</div>
|
||||
<div class="community-link">
|
||||
<p>有任何疑问,欢迎加入 kk 开源社区知识星球咨询</p>
|
||||
<a href="https://t.zsxq.com/09ZHSXbsQ" target="_blank" rel="noopener noreferrer">
|
||||
🔗 加入知识星球
|
||||
</a>
|
||||
</div>
|
||||
<div class="footer-note">
|
||||
系统暂不支持此格式在线查看,建议下载后使用本地软件打开
|
||||
</div>
|
||||
<div class="container">
|
||||
<img src="images/sorry.jpg"/>
|
||||
<span>
|
||||
该(${fileType})文件,系统暂不支持在线预览,具体原因如下:
|
||||
<p style="color: red;">${msg}</p>
|
||||
</span>
|
||||
<p>有任何疑问,请加入kk开源社区知识星球咨询:<a href="https://t.zsxq.com/09ZHSXbsQ">https://t.zsxq.com/09ZHSXbsQ</a><br></p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<meta name="viewport" content="width=device-width, user-scalable=yes, initial-scale=1.0">
|
||||
<title>JSON文件预览</title>
|
||||
<#include "*/commonHeader.ftl">
|
||||
<script src="js/jquery-3.7.1.min.js" type="text/javascript"></script>
|
||||
<script src="js/jquery-3.6.1.min.js" type="text/javascript"></script>
|
||||
<link rel="stylesheet" href="bootstrap/css/bootstrap.min.css"/>
|
||||
<script src="bootstrap/js/bootstrap.min.js" type="text/javascript"></script>
|
||||
<script src="js/base64.min.js" type="text/javascript"></script>
|
||||
|
||||
104
server/src/main/resources/web/main/contact.ftl
Normal file
104
server/src/main/resources/web/main/contact.ftl
Normal file
@@ -0,0 +1,104 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<title>kkFileView 技术支持</title>
|
||||
<link rel="icon" href="./favicon.ico" type="image/x-icon">
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@400;500;600;700&family=JetBrains+Mono:wght@400;600&family=Space+Grotesk:wght@500;700&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="bootstrap/css/bootstrap.min.css"/>
|
||||
<link rel="stylesheet" href="css/theme.css"/>
|
||||
<link rel="stylesheet" href="css/main-pages.css"/>
|
||||
<script type="text/javascript" src="js/jquery-3.6.1.min.js"></script>
|
||||
<script type="text/javascript" src="bootstrap/js/bootstrap.min.js"></script>
|
||||
</head>
|
||||
|
||||
<body class="app-shell">
|
||||
<nav class="site-nav navbar navbar-inverse navbar-fixed-top">
|
||||
<div class="container">
|
||||
<div class="navbar-header">
|
||||
<a class="navbar-brand" href="https://kkview.cn" target="_blank">kkFileView</a>
|
||||
</div>
|
||||
<ul class="nav navbar-nav">
|
||||
<li><a href="./index">首页</a></li>
|
||||
<li><a href="./integrated">接入说明</a></li>
|
||||
<li><a href="./record">版本发布记录</a></li>
|
||||
<li><a href="./sponsor">赞助开源</a></li>
|
||||
<li class="active"><a href="./contact">技术支持</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="page-shell">
|
||||
<div class="container" role="main">
|
||||
<section class="hero-section release-hero">
|
||||
<div class="hero-copy">
|
||||
<div class="contact-hero-layout">
|
||||
<div class="contact-hero-copy">
|
||||
<span class="eyebrow">Contact Us</span>
|
||||
<h1 class="hero-title">技术支持</h1>
|
||||
<p class="hero-subtitle">
|
||||
如果你在部署、安装、接入或日常使用 kkFileView 时需要更直接的支持,
|
||||
可以加入我们的付费知识星球,获取安装使用技术支持。
|
||||
</p>
|
||||
<div class="hero-actions">
|
||||
<a class="hero-link primary" href="https://wx.zsxq.com/group/48844125114258" target="_blank">加入知识星球</a>
|
||||
<a class="hero-link secondary" href="./integrated">查看接入说明</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="contact-hero-side">
|
||||
<div class="support-summary">
|
||||
<div class="support-summary-item">
|
||||
<span class="tag brand">安装支持</span>
|
||||
<p>提供最新的安装发行包,公示安全补丁等。</p>
|
||||
</div>
|
||||
<div class="support-summary-item">
|
||||
<span class="tag">使用咨询</span>
|
||||
<p>围绕接入、配置和日常使用问题提供支持。</p>
|
||||
</div>
|
||||
<div class="support-summary-item">
|
||||
<span class="tag highlight">付费知识星球</span>
|
||||
<p>通过知识星球联系,我们提供更直接的技术支持。</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="sponsor-grid">
|
||||
<section class="doc-card">
|
||||
<div class="doc-card-header">
|
||||
<div>
|
||||
<span class="eyebrow">Support Scope</span>
|
||||
<h3>支持内容</h3>
|
||||
</div>
|
||||
</div>
|
||||
<p>如果你希望更快完成部署和落地,可以通过知识星球联系我们,获得更直接的安装使用支持。</p>
|
||||
<ul>
|
||||
<li>安装部署相关问题。</li>
|
||||
<li>配置、接入和常见使用问题。</li>
|
||||
<li>围绕实际使用场景的排查与建议。</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section class="doc-card">
|
||||
<div class="doc-card-header">
|
||||
<div>
|
||||
<span class="eyebrow">Knowledge Planet</span>
|
||||
<h3>加入方式</h3>
|
||||
</div>
|
||||
</div>
|
||||
<p>知识星球地址:</p>
|
||||
<p><a href="https://wx.zsxq.com/group/48844125114258" target="_blank">https://wx.zsxq.com/group/48844125114258</a></p>
|
||||
<div class="note-row">
|
||||
<span class="tag brand"><a href="https://wx.zsxq.com/group/48844125114258" target="_blank">立即加入</a></span>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,118 +1,254 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html lang="en" xmlns="http://www.w3.org/1999/html">
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<title>接入说明</title>
|
||||
<title>kkFileView 接入说明</title>
|
||||
<link rel="icon" href="./favicon.ico" type="image/x-icon">
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@400;500;600;700&family=JetBrains+Mono:wght@400;600&family=Space+Grotesk:wght@500;700&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="bootstrap/css/bootstrap.min.css"/>
|
||||
<link rel="stylesheet" href="css/theme.css"/>
|
||||
<script type="text/javascript" src="js/jquery-3.7.1.min.js"></script>
|
||||
<link rel="stylesheet" href="css/main-pages.css"/>
|
||||
<script type="text/javascript" src="js/jquery-3.6.1.min.js"></script>
|
||||
<script type="text/javascript" src="bootstrap/js/bootstrap.min.js"></script>
|
||||
<script type="text/javascript" src="highlight/highlight.min.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<nav class="navbar navbar-inverse navbar-fixed-top">
|
||||
<body class="app-shell">
|
||||
<nav class="site-nav navbar navbar-inverse navbar-fixed-top">
|
||||
<div class="container">
|
||||
<div class="navbar-header">
|
||||
<a class="navbar-brand" href="https://kkview.cn" target='_blank'>kkFileView</a>
|
||||
<a class="navbar-brand" href="https://kkview.cn" target="_blank">kkFileView</a>
|
||||
</div>
|
||||
<ul class="nav navbar-nav">
|
||||
<li><a href="./index">首页</a></li>
|
||||
<li class="active"><a href="./integrated">接入说明</a></li>
|
||||
<li><a href="./record">版本发布记录</a></li>
|
||||
<li><a href="./sponsor">赞助开源</a></li>
|
||||
<li><a href="./contact">技术支持</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container theme-showcase" role="main">
|
||||
<#-- 接入说明 -->
|
||||
<div class="page-header">
|
||||
<h1>接入说明</h1>
|
||||
本文档针对前端项目接入 kkFileView 的说明,并假设 kkFileView 的服务地址为:http://127.0.0.1:8012。
|
||||
</div>
|
||||
<div class="well">
|
||||
<div class="page-shell">
|
||||
<div class="container" role="main">
|
||||
<section class="hero-section release-hero">
|
||||
<div class="hero-copy">
|
||||
<span class="eyebrow">Integration Guide</span>
|
||||
<h1 class="hero-title">5 分钟把 kkFileView 接进你的业务项目。</h1>
|
||||
<p class="hero-subtitle hero-subtitle-inline">
|
||||
这里按常见接入场景提供示例,方便你直接按需选用。默认假设服务地址为 <span class="text-highlight">${baseUrl}</span>。
|
||||
</p>
|
||||
<div class="note-row">
|
||||
<span class="tag brand">HTTP / HTTPS</span>
|
||||
<span class="tag">FTP</span>
|
||||
<span class="tag highlight">AES</span>
|
||||
<span class="tag warn">附加参数</span>
|
||||
</div>
|
||||
<div class="summary-grid">
|
||||
<div class="summary-panel">
|
||||
<strong>URL</strong>
|
||||
<span>所有预览能力统一汇总到 `onlinePreview` 入口。</span>
|
||||
</div>
|
||||
<div class="summary-panel">
|
||||
<strong>Base64</strong>
|
||||
<span>普通接入默认对原始文件地址做 Base64 编码后再传入。</span>
|
||||
</div>
|
||||
<div class="summary-panel">
|
||||
<strong>参数扩展</strong>
|
||||
<span>支持页码、高亮、水印、密码、跨域、AES 和秘钥等控制项。</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div style="font-size: 16px;">
|
||||
【http/https 资源文件预览】如果你的项目需要接入文件预览项目,达到对docx、excel、ppt、jpg等文件的预览效果,那么通过在你的项目中加入下面的代码就可以成功实现:
|
||||
<p style="background-color: #2f332a;color: #cccccc;font-size: 14px;padding:10px;margin-top:10px;">
|
||||
var url = 'http://127.0.0.1:8080/file/test.txt'; //要预览文件的访问地址 <br>
|
||||
window.open('${baseUrl}onlinePreview?url='+encodeURIComponent(base64Encode(url)));
|
||||
</p>
|
||||
</div>
|
||||
<br>
|
||||
<div style="font-size: 16px;">
|
||||
【http/https 流资源文件预览】很多系统内不是直接暴露文件下载地址,而是请求通过id、code等参数到通过统一的接口,后端通过id或code等参数定位文件,再通过OutputStream输出下载,此时下载url是不带文件后缀名的,预览时需要拿到文件名,传一个参数fullfilename=xxx.xxx来指定文件名,示例如下
|
||||
<p style="background-color: #2f332a;color: #cccccc;font-size: 14px;padding:10px;margin-top:10px;">
|
||||
var originUrl = 'http://127.0.0.1:8080/filedownload?fileId=1'; //要预览文件的访问地址<br>
|
||||
var previewUrl = originUrl + '&fullfilename=test.txt'<br>
|
||||
window.open('${baseUrl}onlinePreview?url='+encodeURIComponent(Base64.encode(previewUrl)));
|
||||
</p>
|
||||
</div>
|
||||
<br>
|
||||
<div style="font-size: 16px;">
|
||||
【ftp 资源文件预览】如果要预览的FTP url是可以匿名访问的(不需要用户名密码),则可以直接通过下载url预览,示例如下
|
||||
<p style="background-color: #2f332a;color: #cccccc;font-size: 14px;padding:10px;margin-top:10px;">
|
||||
var url = 'ftp://127.0.0.1/file/test.txt'; //要预览文件的访问地址<br>
|
||||
window.open('${baseUrl}onlinePreview?url='+encodeURIComponent(Base64.encode(url)));
|
||||
</p>
|
||||
</div>
|
||||
<br>
|
||||
<div style="font-size: 16px;">
|
||||
【ftp 加密资源文件预览】如果 FTP 需要认证访问服,可以通过在 url 中加入用户名密码等参数预览,示例如下
|
||||
<p style="background-color: #2f332a;color: #cccccc;font-size: 14px;padding:10px;margin-top:10px;">
|
||||
var originUrl = 'ftp://127.0.0.1/file/test.txt'; //要预览文件的访问地址<br>
|
||||
var previewUrl = originUrl + '?ftp.control.port=xx&ftp.username=xx&ftp.password=xx&ftp.control.encoding=(gbk,utf8等)'; //(为了安全强烈建议在配置中设置相关信息)<br>
|
||||
window.open('${baseUrl}onlinePreview?url='+encodeURIComponent(Base64.encode(previewUrl)));
|
||||
</p>
|
||||
</div>
|
||||
<div style="font-size: 16px;">
|
||||
【Basic 鉴权资源文件预览】如果需要认证访问服,可以通过在url中加入用户名密码等参数预览,示例如下
|
||||
<p style="background-color: #2f332a;color: #cccccc;font-size: 14px;padding:10px;margin-top:10px;">
|
||||
var originUrl = 'http://127.0.0.1/file/test.txt'; //要预览文件的访问地址<br>
|
||||
var previewUrl = originUrl + '?basic.name=admin&basic.pass=123456'; //(为了安全强烈建议在配置中设置相关信息)<br>
|
||||
window.open('${baseUrl}onlinePreview?url='+encodeURIComponent(Base64.encode(previewUrl)));
|
||||
</p>
|
||||
</div>
|
||||
<div style="font-size: 16px;">
|
||||
AES加密接入方法,示例如下
|
||||
<p style="background-color: #2f332a;color: #cccccc;font-size: 14px;padding:10px;margin-top:10px;">
|
||||
主要事项:首先引入下面js 在把url转换成AES,注意前后端key必须相同(注意:JS下载到你接入服务器的网址)<br>
|
||||
<script src="${baseUrl}js/crypto-js.js"></script><br>
|
||||
<script src="${baseUrl}js/aes.js"></script><br>
|
||||
function aesEncrypt(encryptString, key) { <br>
|
||||
var key = CryptoJS.enc.Utf8.parse(key); <br>
|
||||
var srcs = CryptoJS.enc.Utf8.parse(encryptString); <br>
|
||||
var encrypted = CryptoJS.AES.encrypt(srcs, key, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7 }); <br>
|
||||
return encrypted.toString(); <br>
|
||||
}<br>
|
||||
var key = "1234567890123456"; // AES秘钥16位数字<br>
|
||||
var url = "http://127.0.0.1/file/test.txt";<br>
|
||||
window.open('${baseUrl}onlinePreview?url='+encodeURIComponent(aesEncrypt(url, key))+'&encryption=aes');
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div style="font-size: 16px;">
|
||||
其他参数,示例如下
|
||||
<p style="background-color: #2f332a;color: #cccccc;font-size: 14px;padding:10px;margin-top:10px;">
|
||||
密码参数:&filePassword=加密文件的密码<br>
|
||||
页码参数:&page=选择第几页预览<br>
|
||||
高亮参数:&highlightall=关键字 突出显示 <br>
|
||||
水印参数:&watermarkTxt=你的水印<br>
|
||||
重生参数:&forceUpdatedCache=true <br>
|
||||
跨域参数:&kkagent=true <br>
|
||||
加密缓存:&usePasswordCache=true <br>
|
||||
秘钥参数:&key= 访问秘钥 <br>
|
||||
主要事项:以上参数是把url转换成base64后面在添加<br>
|
||||
var url = 'http://127.0.0.1:8080/file/test.txt'<br>
|
||||
window.open('${baseUrl}onlinePreview?url='+encodeURIComponent(base64Encode(url))+'&filePassword=123&page=1&highlightall=kkfileview&watermarkTxt=kkfileview&kkagent=false&key=123');
|
||||
</p>
|
||||
<div class="docs-layout">
|
||||
<aside class="page-toc">
|
||||
<h3>快速导航</h3>
|
||||
<ul>
|
||||
<li><a href="#quick-start">快速开始</a></li>
|
||||
<li><a href="#http-preview">HTTP 文件预览</a></li>
|
||||
<li><a href="#stream-preview">流式接口预览</a></li>
|
||||
<li><a href="#ftp-preview">FTP 预览</a></li>
|
||||
<li><a href="#basic-auth">Basic 鉴权</a></li>
|
||||
<li><a href="#aes-preview">AES 加密</a></li>
|
||||
<li><a href="#extra-params">附加参数</a></li>
|
||||
</ul>
|
||||
</aside>
|
||||
|
||||
<div class="docs-content">
|
||||
<section class="doc-card" id="quick-start">
|
||||
<div class="doc-card-header">
|
||||
<div>
|
||||
<span class="eyebrow">Quick Start</span>
|
||||
<h3>接入思路</h3>
|
||||
</div>
|
||||
<div class="tags">
|
||||
<span class="tag brand">推荐入口</span>
|
||||
</div>
|
||||
</div>
|
||||
<p>前端只需要拿到可访问的文件 URL,然后把它编码后拼到 `${baseUrl}onlinePreview` 上即可。对于大多数业务系统,这是最快的落地路径。</p>
|
||||
<ul>
|
||||
<li>普通 HTTP/HTTPS 文件地址:直接 Base64 编码后传入。</li>
|
||||
<li>下载流接口没有后缀名:补充 `fullfilename=xxx.xxx`。</li>
|
||||
<li>鉴权或加密场景:附加 Basic、FTP、AES 等参数。</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section class="doc-card" id="http-preview">
|
||||
<div class="doc-card-header">
|
||||
<div>
|
||||
<span class="eyebrow">HTTP / HTTPS</span>
|
||||
<h3>普通文件地址预览</h3>
|
||||
</div>
|
||||
<button class="copy-btn" type="button" onclick="copyCode(this)">复制代码</button>
|
||||
</div>
|
||||
<p>适用于系统已经直接暴露出可下载文件地址的情况。前端只需要编码后打开新窗口。</p>
|
||||
<div class="code-block">
|
||||
<code class="language-javascript">var url = 'http://127.0.0.1:8080/file/test.txt';
|
||||
window.open('${baseUrl}onlinePreview?url=' + encodeURIComponent(base64Encode(url)));</code>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="doc-card" id="stream-preview">
|
||||
<div class="doc-card-header">
|
||||
<div>
|
||||
<span class="eyebrow">Streaming</span>
|
||||
<h3>流式接口预览</h3>
|
||||
</div>
|
||||
<button class="copy-btn" type="button" onclick="copyCode(this)">复制代码</button>
|
||||
</div>
|
||||
<p>很多业务系统通过 `fileId`、`code` 等参数走统一下载接口,此时原始 URL 没有后缀名,需要额外指定完整文件名。</p>
|
||||
<div class="code-block">
|
||||
<code class="language-javascript">var originUrl = 'http://127.0.0.1:8080/filedownload?fileId=1';
|
||||
var previewUrl = originUrl + '&fullfilename=test.txt';
|
||||
window.open('${baseUrl}onlinePreview?url=' + encodeURIComponent(Base64.encode(previewUrl)));</code>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="doc-card" id="ftp-preview">
|
||||
<div class="doc-card-header">
|
||||
<div>
|
||||
<span class="eyebrow">FTP</span>
|
||||
<h3>FTP 资源预览</h3>
|
||||
</div>
|
||||
<button class="copy-btn" type="button" onclick="copyCode(this)">复制代码</button>
|
||||
</div>
|
||||
<p>FTP 如果允许匿名访问,可以直接预览;如果需要认证,则把连接参数拼到 URL 后面传入。</p>
|
||||
<div class="code-block">
|
||||
<code class="language-javascript">// 匿名 FTP
|
||||
var url = 'ftp://127.0.0.1/file/test.txt';
|
||||
window.open('${baseUrl}onlinePreview?url=' + encodeURIComponent(Base64.encode(url)));
|
||||
|
||||
// 认证 FTP
|
||||
var originUrl = 'ftp://127.0.0.1/file/test.txt';
|
||||
var previewUrl = originUrl + '?ftp.control.port=21&ftp.username=admin&ftp.password=123456&ftp.control.encoding=utf8';
|
||||
window.open('${baseUrl}onlinePreview?url=' + encodeURIComponent(Base64.encode(previewUrl)));</code>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="doc-card" id="basic-auth">
|
||||
<div class="doc-card-header">
|
||||
<div>
|
||||
<span class="eyebrow">Basic Auth</span>
|
||||
<h3>带 Basic 鉴权的 HTTP 资源</h3>
|
||||
</div>
|
||||
<button class="copy-btn" type="button" onclick="copyCode(this)">复制代码</button>
|
||||
</div>
|
||||
<p>如果文件源本身需要用户名和密码,可以直接把 Basic 鉴权参数拼到地址中,再交给 kkFileView。</p>
|
||||
<div class="code-block">
|
||||
<code class="language-javascript">var originUrl = 'http://127.0.0.1/file/test.txt';
|
||||
var previewUrl = originUrl + '?basic.name=admin&basic.pass=123456';
|
||||
window.open('${baseUrl}onlinePreview?url=' + encodeURIComponent(Base64.encode(previewUrl)));</code>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="doc-card" id="aes-preview">
|
||||
<div class="doc-card-header">
|
||||
<div>
|
||||
<span class="eyebrow">AES</span>
|
||||
<h3>前后端同秘钥加密接入</h3>
|
||||
</div>
|
||||
<button class="copy-btn" type="button" onclick="copyCode(this)">复制代码</button>
|
||||
</div>
|
||||
<p>如果不希望明文传递原始文件地址,可以在前端先做 AES 加密,再通过 `encryption=aes` 告知服务端按 AES 方式解密。</p>
|
||||
<div class="code-block">
|
||||
<code class="language-javascript"><script src="${baseUrl}js/crypto-js.js"></script>
|
||||
<script src="${baseUrl}js/aes.js"></script>
|
||||
|
||||
function aesEncrypt(encryptString, key) {
|
||||
var keyBytes = CryptoJS.enc.Utf8.parse(key);
|
||||
var srcs = CryptoJS.enc.Utf8.parse(encryptString);
|
||||
var encrypted = CryptoJS.AES.encrypt(srcs, keyBytes, {
|
||||
mode: CryptoJS.mode.ECB,
|
||||
padding: CryptoJS.pad.Pkcs7
|
||||
});
|
||||
return encrypted.toString();
|
||||
}
|
||||
|
||||
var key = '1234567890123456';
|
||||
var url = 'http://127.0.0.1/file/test.txt';
|
||||
window.open('${baseUrl}onlinePreview?url=' + encodeURIComponent(aesEncrypt(url, key)) + '&encryption=aes');</code>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="doc-card" id="extra-params">
|
||||
<div class="doc-card-header">
|
||||
<div>
|
||||
<span class="eyebrow">Parameters</span>
|
||||
<h3>常用附加参数</h3>
|
||||
</div>
|
||||
<button class="copy-btn" type="button" onclick="copyCode(this)">复制代码</button>
|
||||
</div>
|
||||
<p>这些参数都应该在原始 URL 编码完成之后,再附加到预览地址后面。</p>
|
||||
<ul>
|
||||
<li>`filePassword`:加密文件的密码。</li>
|
||||
<li>`page`:指定预览页码。</li>
|
||||
<li>`highlightall`:关键字高亮。</li>
|
||||
<li>`watermarkTxt`:动态水印文本。</li>
|
||||
<li>`forceUpdatedCache=true`:强制刷新缓存。</li>
|
||||
<li>`kkagent=true`:需要 kkFileView 代理跨域时启用。</li>
|
||||
<li>`usePasswordCache=true`:开启密码缓存。</li>
|
||||
<li>`key`:实例启用秘钥后传入访问秘钥。</li>
|
||||
</ul>
|
||||
<div class="code-block">
|
||||
<code class="language-javascript">var url = 'http://127.0.0.1:8080/file/test.txt';
|
||||
window.open(
|
||||
'${baseUrl}onlinePreview?url=' +
|
||||
encodeURIComponent(base64Encode(url)) +
|
||||
'&filePassword=123' +
|
||||
'&page=1' +
|
||||
'&highlightall=kkfileview' +
|
||||
'&watermarkTxt=kkfileview' +
|
||||
'&kkagent=false' +
|
||||
'&key=123'
|
||||
);</code>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
if (window.hljs) {
|
||||
document.querySelectorAll('.code-block code').forEach(function (block) {
|
||||
hljs.highlightBlock(block);
|
||||
});
|
||||
}
|
||||
|
||||
function copyCode(button) {
|
||||
var code = button.parentNode.parentNode.querySelector('code').innerText;
|
||||
var originalText = button.textContent;
|
||||
navigator.clipboard.writeText(code).then(function () {
|
||||
button.textContent = '已复制';
|
||||
setTimeout(function () {
|
||||
button.textContent = originalText;
|
||||
}, 1500);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,72 +1,127 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html lang="en" xmlns="http://www.w3.org/1999/html">
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<title>赞助开源</title>
|
||||
<title>kkFileView 赞助开源</title>
|
||||
<link rel="icon" href="./favicon.ico" type="image/x-icon">
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@400;500;600;700&family=JetBrains+Mono:wght@400;600&family=Space+Grotesk:wght@500;700&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="bootstrap/css/bootstrap.min.css"/>
|
||||
<link rel="stylesheet" href="css/theme.css"/>
|
||||
<script type="text/javascript" src="js/jquery-3.7.1.min.js"></script>
|
||||
<link rel="stylesheet" href="css/main-pages.css"/>
|
||||
<script type="text/javascript" src="js/jquery-3.6.1.min.js"></script>
|
||||
<script type="text/javascript" src="bootstrap/js/bootstrap.min.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<!-- Fixed navbar -->
|
||||
<nav class="navbar navbar-inverse navbar-fixed-top">
|
||||
<body class="app-shell">
|
||||
<nav class="site-nav navbar navbar-inverse navbar-fixed-top">
|
||||
<div class="container">
|
||||
<div class="navbar-header">
|
||||
<a class="navbar-brand" href="https://kkview.cn" target='_blank'>kkFileView</a>
|
||||
<a class="navbar-brand" href="https://kkview.cn" target="_blank">kkFileView</a>
|
||||
</div>
|
||||
<ul class="nav navbar-nav">
|
||||
<li><a href="./index">首页</a></li>
|
||||
<li><a href="./integrated">接入说明</a></li>
|
||||
<li><a href="./record">版本发布记录</a></li>
|
||||
<li class="active"><a href="./sponsor">赞助开源</a></li>
|
||||
<li><a href="./contact">技术支持</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container theme-showcase" role="main">
|
||||
<#-- 接入说明 -->
|
||||
<div class="page-header">
|
||||
<h1>赞助开源</h1>
|
||||
<ul style="font-size: 16px;">
|
||||
<li>kkFileView 开源至今已 6 个年头,积累 <a target="_blank" href="https://gitee.com/kekingcn/file-online-preview">Gitee(16.9K)</a>、<a target="_blank" href="https://github.com/kekingcn/kkFileView">GitHub(8k)</a> 多的 star</li>
|
||||
<li>kkFileView 被广泛应用于金融、教育、银行、政务、计算机等行业, 不完全统计有 200+ 企业在使用</li>
|
||||
<li>kkFileView 每年的文档站点、演示站点的服务器、CDN 资源, 至少在 1000元以上</li>
|
||||
<li>kkFileView 是一款完全开源的在线预览项目,如果你觉得 kkFileView 对你有帮助,可以通过下面的方式来赞助我们,谢谢!</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<div style="font-size: 16px; text-align: center;">
|
||||
<img width="400px" height="550px" alt="alipay" src="../images/alipay.jpeg"/> <img width="400px" height="550px" alt="wxpay" src="../images/wxpay.jpeg"/>
|
||||
<div class="page-shell">
|
||||
<div class="container" role="main">
|
||||
<section class="hero-section release-hero">
|
||||
<div class="hero-copy">
|
||||
<span class="eyebrow">Sponsor Open Source</span>
|
||||
<h1 class="hero-title">赞助开源</h1>
|
||||
<p class="hero-subtitle">
|
||||
kkFileView 已持续维护多年,被广泛用于金融、教育、银行、政务和企业内部系统。
|
||||
赞助会直接用于文档站、演示站、服务器和 CDN 等基础开销。
|
||||
</p>
|
||||
<div class="summary-grid">
|
||||
<div class="summary-panel">
|
||||
<strong>多年维护</strong>
|
||||
<span>项目长期迭代,持续补格式、补安全、补性能。</span>
|
||||
</div>
|
||||
<div class="summary-panel">
|
||||
<strong>广泛使用</strong>
|
||||
<span>不完全统计已有 200+ 企业或团队在使用。</span>
|
||||
</div>
|
||||
<div class="summary-panel">
|
||||
<strong>基础成本</strong>
|
||||
<span>文档站、演示站和 CDN 等年成本至少在千元级。</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="note-row">
|
||||
<span class="tag brand"><a target="_blank" href="https://gitee.com/kekingcn/file-online-preview">Gitee</a></span>
|
||||
<span class="tag brand"><a target="_blank" href="https://github.com/kekingcn/kkFileView">GitHub</a></span>
|
||||
<span class="tag highlight">完全开源</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="sponsor-grid">
|
||||
<section class="doc-card">
|
||||
<div class="doc-card-header">
|
||||
<div>
|
||||
<span class="eyebrow">Ways To Sponsor</span>
|
||||
<h3>赞助方式</h3>
|
||||
</div>
|
||||
</div>
|
||||
<p>如果你觉得 kkFileView 对你有帮助,可以通过下面的方式赞助项目,支持它继续长期维护。</p>
|
||||
<ul>
|
||||
<li>kkFileView 开源至今已多年,社区持续反馈并推动演进。</li>
|
||||
<li>项目 star 与使用规模已经证明它不是“玩具 demo”,而是被真实系统接入的基础能力。</li>
|
||||
<li>赞助记录为手动录入,存在周级延迟;如有遗漏,可联系作者补录。</li>
|
||||
</ul>
|
||||
|
||||
<div class="donation-wall">
|
||||
<div class="qr-card">
|
||||
<h4>支付宝</h4>
|
||||
<img alt="支付宝赞助码" src="../images/alipay.jpeg"/>
|
||||
</div>
|
||||
<div class="qr-card">
|
||||
<h4>微信支付</h4>
|
||||
<img alt="微信赞助码" src="../images/wxpay.jpeg"/>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="doc-card">
|
||||
<div class="doc-card-header">
|
||||
<div>
|
||||
<span class="eyebrow">Sponsor Log</span>
|
||||
<h3>赞助记录</h3>
|
||||
</div>
|
||||
<div class="tags">
|
||||
<span class="tag">2023-03-14 开启赞助通道</span>
|
||||
</div>
|
||||
</div>
|
||||
<p>赞助记录为手动维护,如有遗漏,请联系作者补充。</p>
|
||||
<table class="table sponsor-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>赞助人</th>
|
||||
<th>赞助金额</th>
|
||||
<th>赞助时间</th>
|
||||
<th>备注</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>陈**</td>
|
||||
<td class="sponsor-amount">99</td>
|
||||
<td>2023-03-14</td>
|
||||
<td>首批赞助记录</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h3>赞助记录</h3>
|
||||
2023-03-14 开启赞助通道,赞助记录为手动录入的,存在周级别延迟,如有遗漏,请联系作者补充
|
||||
<br/>
|
||||
<table class="table table-striped table-bordered">
|
||||
<tr>
|
||||
<th>赞助人</th>
|
||||
<th>赞助金额</th>
|
||||
<th>赞助时间</th>
|
||||
<th>备注</th>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>陈**</td>
|
||||
<td>99</td>
|
||||
<td>2023-03-14</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<meta name="viewport" content="width=device-width, user-scalable=yes, initial-scale=1.0">
|
||||
<title>${file.name}文本预览</title>
|
||||
<#include "*/commonHeader.ftl">
|
||||
<script src="js/jquery-3.7.1.min.js" type="text/javascript"></script>
|
||||
<script src="js/jquery-3.6.1.min.js" type="text/javascript"></script>
|
||||
<link rel="stylesheet" href="bootstrap/css/bootstrap.min.css"/>
|
||||
<link rel="stylesheet" href="css/index.css"/>
|
||||
<script src="bootstrap/js/bootstrap.min.js" type="text/javascript"></script>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<#setting classic_compatible=true>
|
||||
<link rel="icon" href="./favicon.ico" type="image/x-icon">
|
||||
<link rel="stylesheet" href="bootstrap/css/bootstrap.min.css"/>
|
||||
<script src="js/jquery-3.7.1.min.js" type="text/javascript"></script>
|
||||
<script src="js/jquery-3.6.1.min.js" type="text/javascript"></script>
|
||||
<script src="bootstrap/js/bootstrap.min.js" type="text/javascript"></script>
|
||||
<script src="js/bootbox.min.js" type="text/javascript"></script>
|
||||
<script>
|
||||
|
||||
@@ -1,131 +1,42 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>访问受限 - 未授信目录</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
<meta charset="utf-8" />
|
||||
<style type="text/css">
|
||||
body {
|
||||
font-family: 'Segoe UI', Roboto, 'Helvetica Neue', sans-serif;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 20px;
|
||||
margin: 0 auto;
|
||||
width: 900px;
|
||||
background-color: #CCB;
|
||||
}
|
||||
|
||||
.error-card {
|
||||
max-width: 600px;
|
||||
width: 100%;
|
||||
background: #ffffff;
|
||||
border-radius: 32px;
|
||||
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
|
||||
text-align: center;
|
||||
padding: 40px 32px 48px;
|
||||
transition: transform 0.2s ease;
|
||||
.container {
|
||||
width: 700px;
|
||||
height: 700px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.error-card:hover {
|
||||
transform: translateY(-4px);
|
||||
img {
|
||||
width: auto;
|
||||
height: auto;
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
padding-bottom: 36px;
|
||||
}
|
||||
|
||||
.icon-container {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.icon-container img {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 28px;
|
||||
font-weight: 700;
|
||||
color: #1e293b;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.warning-message {
|
||||
background: #fef2f2;
|
||||
border-left: 4px solid #dc2626;
|
||||
padding: 20px;
|
||||
border-radius: 16px;
|
||||
margin: 24px 0;
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
color: #1e293b;
|
||||
}
|
||||
|
||||
.warning-message::before {
|
||||
content: "🚫 ";
|
||||
p {
|
||||
display: block;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.community-link {
|
||||
background: #f8fafc;
|
||||
border-radius: 24px;
|
||||
padding: 16px 20px;
|
||||
margin-top: 20px;
|
||||
border: 1px solid #e2e8f0;
|
||||
}
|
||||
|
||||
.community-link p {
|
||||
font-size: 15px;
|
||||
color: #334155;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.community-link a {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
background: #3b82f6;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
padding: 10px 24px;
|
||||
border-radius: 40px;
|
||||
font-weight: 500;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
|
||||
.community-link a:hover {
|
||||
background: #2563eb;
|
||||
}
|
||||
|
||||
.footer-note {
|
||||
margin-top: 28px;
|
||||
font-size: 13px;
|
||||
color: #94a3b8;
|
||||
color: blue;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="error-card">
|
||||
<div class="icon-container">
|
||||
<!-- Base64 内嵌 SVG:文件夹加禁止符号 -->
|
||||
<img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iI2RjMjYyNiIgd2lkdGg9IjEyMCIgaGVpZ2h0PSIxMjAiPgogIDxwYXRoIGQ9Ik0yMCA2aC04bC0yLTJINGMyLTEuMSAwLTEgMCAwdjE0YzAgMS4xLjkgMiAyIDJoMTZjMS4xIDAgMi0uOSAyLTJWN2MwLTEuMS0uOS0yLTItMnptLTUgN2gtNHYtMmg0djJ6bTAtM2gtNFY4aDR2MnoiLz4KICA8Y2lyY2xlIGN4PSIxMiIgY3k9IjE2IiByPSI0IiBmaWxsPSIjZmZmIiBzdHJva2U9IiNkYzI2MjYiIHN0cm9rZS13aWR0aD0iMS41Ii8+CiAgPHBhdGggZD0iTTE2IDhsMi0yIDIgMi0yIDJ6IiBmaWxsPSIjZmZmIi8+Cjwvc3ZnPg==" alt="目录未授信">
|
||||
</div>
|
||||
<h1>访问被拒绝</h1>
|
||||
<div class="warning-message">
|
||||
预览源文件来自未授信的目录,请停止访问!
|
||||
</div>
|
||||
<div class="community-link">
|
||||
<p>有任何疑问,欢迎加入 kk 开源社区知识星球咨询</p>
|
||||
<a href="https://t.zsxq.com/09ZHSXbsQ" target="_blank" rel="noopener noreferrer">
|
||||
🔗 加入知识星球
|
||||
</a>
|
||||
</div>
|
||||
<div class="footer-note">
|
||||
如果您确信该目录安全,请联系管理员将其添加到信任目录列表中
|
||||
</div>
|
||||
<div class="container">
|
||||
<img src="images/sorry.jpg" />
|
||||
<p>
|
||||
预览源文件来自未授信的目录,请停止访问!<br>
|
||||
有任何疑问,请加入kk开源社区知识星球咨询:<a href="https://t.zsxq.com/09ZHSXbsQ">https://t.zsxq.com/09ZHSXbsQ</a><br>
|
||||
</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -1,148 +1,42 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>访问受限 - 不受信任的站点</title>
|
||||
<meta charset="utf-8" />
|
||||
<style type="text/css">
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Segoe UI', Roboto, 'Helvetica Neue', sans-serif;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 20px;
|
||||
margin: 0 auto;
|
||||
width: 900px;
|
||||
background-color: #CCB;
|
||||
}
|
||||
|
||||
.error-card {
|
||||
max-width: 600px;
|
||||
width: 100%;
|
||||
background: #ffffff;
|
||||
border-radius: 32px;
|
||||
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
|
||||
overflow: hidden;
|
||||
text-align: center;
|
||||
padding: 40px 32px 48px;
|
||||
transition: transform 0.2s ease;
|
||||
.container {
|
||||
width: 700px;
|
||||
height: 700px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.error-card:hover {
|
||||
transform: translateY(-4px);
|
||||
img {
|
||||
width: auto;
|
||||
height: auto;
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
padding-bottom: 36px;
|
||||
}
|
||||
|
||||
.icon-container {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.icon-container img {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 28px;
|
||||
font-weight: 700;
|
||||
color: #1e293b;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.host-warning {
|
||||
background: #fef2f2;
|
||||
border-left: 4px solid #dc2626;
|
||||
padding: 14px 20px;
|
||||
border-radius: 16px;
|
||||
margin: 24px 0;
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
color: #1e293b;
|
||||
}
|
||||
|
||||
.host-warning span {
|
||||
color: #dc2626;
|
||||
font-weight: 700;
|
||||
background: #fff0f0;
|
||||
padding: 4px 12px;
|
||||
border-radius: 40px;
|
||||
display: inline-block;
|
||||
margin: 0 4px;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.message {
|
||||
color: #475569;
|
||||
font-size: 16px;
|
||||
line-height: 1.5;
|
||||
margin-bottom: 28px;
|
||||
}
|
||||
|
||||
.community-link {
|
||||
background: #f8fafc;
|
||||
border-radius: 24px;
|
||||
padding: 16px 20px;
|
||||
margin-top: 8px;
|
||||
border: 1px solid #e2e8f0;
|
||||
}
|
||||
|
||||
.community-link p {
|
||||
font-size: 15px;
|
||||
color: #334155;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.community-link a {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
background: #3b82f6;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
padding: 10px 24px;
|
||||
border-radius: 40px;
|
||||
font-weight: 500;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
|
||||
.community-link a:hover {
|
||||
background: #2563eb;
|
||||
}
|
||||
|
||||
.footer-note {
|
||||
margin-top: 28px;
|
||||
font-size: 13px;
|
||||
color: #94a3b8;
|
||||
p {
|
||||
display: block;
|
||||
font-size: 20px;
|
||||
color: blue;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="error-card">
|
||||
<div class="icon-container">
|
||||
<!-- Base64 内嵌 SVG:安全盾牌 + 感叹号,风格简洁现代 -->
|
||||
<img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iI2RjMjYyNiIgd2lkdGg9IjEyMCIgaGVpZ2h0PSIxMjAiPgogIDxwYXRoIGQ9Ik0xMiAyTDMgN3Y3YzAgNC41MSAzLjgyIDguNDUgOSAxMC4yNSA1LjE4LTEuOCA5LTUuNzQgOS0xMC4yNVY3bC05LTV6bS0yIDEzaC00di0yaDR2MnptMC0zaC00VjloNHYzek0xNiAxM2gtNHYtMmg0djJ6bTAtM2gtNFY4aDR2MnoiLz4KPC9zdmc+" alt="安全警告">
|
||||
</div>
|
||||
<h1>访问被拒绝</h1>
|
||||
<div class="host-warning">
|
||||
⚠️ 预览源文件来自不受信任的站点:<span>${current_host}</span>
|
||||
</div>
|
||||
<div class="message">
|
||||
该站点不在系统信任列表中,为了您的数据安全,已阻止本次访问。<br>
|
||||
</div>
|
||||
<div class="community-link">
|
||||
<p>有任何疑问,欢迎加入 kk 开源社区知识星球咨询</p>
|
||||
<a href="https://t.zsxq.com/09ZHSXbsQ" target="_blank" rel="noopener noreferrer">
|
||||
🔗 加入知识星球
|
||||
</a>
|
||||
</div>
|
||||
<div class="footer-note">
|
||||
如有误判,请联系系统管理员更新信任主机配置
|
||||
</div>
|
||||
<div class="container">
|
||||
<img src="images/sorry.jpg" />
|
||||
<p>
|
||||
预览源文件来自不受信任的站点:<span style="color: red; display: inline;">${current_host}</span> 请联系管理员!<br>
|
||||
有任何疑问,请加入kk开源社区知识星球咨询:<a href="https://t.zsxq.com/09ZHSXbsQ">https://t.zsxq.com/09ZHSXbsQ</a><br>
|
||||
</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -4,178 +4,50 @@
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, user-scalable=yes, initial-scale=1.0">
|
||||
<title>${file.name} OFD预览</title>
|
||||
<title>${file.name}OFD预览</title>
|
||||
<#include "*/commonHeader.ftl">
|
||||
<script src="js/base64.min.js" type="text/javascript"></script>
|
||||
|
||||
<!-- OFD 阅读器所需样式和脚本(相对路径,请确保文件存在) -->
|
||||
<link rel="stylesheet" href="ofd/css/element-ui.css">
|
||||
<link rel="stylesheet" href="ofd/css/cnofd.css">
|
||||
<script src="ofd/js/jquery-3.6.0.min.js"></script>
|
||||
<script src="ofd/js/jszip-utils-0.1.0.min.js"></script>
|
||||
<script src="ofd/js/Typr.js"></script>
|
||||
<script src="ofd/js/Typr.U.js"></script>
|
||||
<script src="ofd/js/openjpeg.js"></script>
|
||||
<script src="ofd/js/cnofd.umd.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<#if currentUrl?contains("http://") || currentUrl?contains("https://")>
|
||||
<#assign finalUrl="${currentUrl}">
|
||||
<#else>
|
||||
<#assign finalUrl="${baseUrl}${currentUrl}">
|
||||
</#if>
|
||||
<body>
|
||||
<!-- OFD 阅读器 DOM 结构(直接嵌入,不再使用 iframe) -->
|
||||
<noscript>
|
||||
<strong>很抱歉,因为没有启用JavaScript,cnofd.js无法正常工作。请启用它以继续。</strong>
|
||||
</noscript>
|
||||
<div id="app">
|
||||
<section class="el-container is-vertical" style="width: 100vw; height: 100vh;">
|
||||
<header class="el-header"
|
||||
style="height: 32px; background: rgb(71, 71, 71); display: flex; border: 0px solid rgb(232, 232, 232); align-items: center;">
|
||||
<div id="openFile" title="打开" class="btn-icon">
|
||||
<svg viewbox="64 64 896 896" focusable="false" width="1em" height="1em" fill="currentColor"
|
||||
aria-hidden="true">
|
||||
<path
|
||||
d="M928 444H820V330.4c0-17.7-14.3-32-32-32H473L355.7 186.2a8.15 8.15 0 0 0-5.5-2.2H96c-17.7 0-32 14.3-32 32v592c0 17.7 14.3 32 32 32h698c13 0 24.8-7.9 29.7-20l134-332c1.5-3.8 2.3-7.9 2.3-12 0-17.7-14.3-32-32-32zM136 256h188.5l119.6 114.4H748V444H238c-13 0-24.8 7.9-29.7 20L136 643.2V256zm635.3 512H159l103.3-256h612.4L771.3 768z">
|
||||
</path>
|
||||
</svg>
|
||||
<input id="file" type="file" accept=".ofd" class="hidden" />
|
||||
</div>
|
||||
<div style="background: rgb(71, 71, 71); display: flex; align-items: center;">
|
||||
<div id="separator1" class="horizontalToolbarSeparator"></div>
|
||||
<div id="zoomIn" title="放大" class="btn-icon">
|
||||
<svg viewbox="64 64 896 896" focusable="false" width="1em" height="1em" fill="currentColor"
|
||||
aria-hidden="true">
|
||||
<path
|
||||
d="M637 443H519V309c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v134H325c-4.4 0-8 3.6-8 8v60c0 4.4 3.6 8 8 8h118v134c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V519h118c4.4 0 8-3.6 8-8v-60c0-4.4-3.6-8-8-8zm284 424L775 721c122.1-148.9 113.6-369.5-26-509-148-148.1-388.4-148.1-537 0-148.1 148.6-148.1 389 0 537 139.5 139.6 360.1 148.1 509 26l146 146c3.2 2.8 8.3 2.8 11 0l43-43c2.8-2.7 2.8-7.8 0-11zM696 696c-118.8 118.7-311.2 118.7-430 0-118.7-118.8-118.7-311.2 0-430 118.8-118.7 311.2-118.7 430 0 118.7 118.8 118.7 311.2 0 430z">
|
||||
</path>
|
||||
</svg>
|
||||
</div>
|
||||
<div id="zoomSelect" class="select-icon" title="缩放比例">
|
||||
<select id="zoomValue">
|
||||
<option value="width">适合页宽</option>
|
||||
<option value="4.0">400%</option>
|
||||
<option value="3.0">300%</option>
|
||||
<option value="2.0">200%</option>
|
||||
<option value="1.5">150%</option>
|
||||
<option value="1.2">120%</option>
|
||||
<option value="1.1">110%</option>
|
||||
<option value="1.0" selected="selected">100%</option>
|
||||
<option value="0.9">90%</option>
|
||||
<option value="0.8">80%</option>
|
||||
<option value="0.6">60%</option>
|
||||
<option value="0.5">50%</option>
|
||||
<option value="0.25">25%</option>
|
||||
</select>
|
||||
</div>
|
||||
<div id="zoomOut" title="缩小" class="btn-icon">
|
||||
<svg viewbox="64 64 896 896" focusable="false" width="1em" height="1em" fill="currentColor"
|
||||
aria-hidden="true">
|
||||
<path
|
||||
d="M637 443H325c-4.4 0-8 3.6-8 8v60c0 4.4 3.6 8 8 8h312c4.4 0 8-3.6 8-8v-60c0-4.4-3.6-8-8-8zm284 424L775 721c122.1-148.9 113.6-369.5-26-509-148-148.1-388.4-148.1-537 0-148.1 148.6-148.1 389 0 537 139.5 139.6 360.1 148.1 509 26l146 146c3.2 2.8 8.3 2.8 11 0l43-43c2.8-2.7 2.8-7.8 0-11zM696 696c-118.8 118.7-311.2 118.7-430 0-118.7-118.8-118.7-311.2 0-430 118.8-118.7 311.2-118.7 430 0 118.7 118.8 118.7 311.2 0 430z">
|
||||
</path>
|
||||
</svg>
|
||||
</div>
|
||||
<div id="firstPage" title="首页" class="btn-icon">
|
||||
<svg viewbox="64 64 896 896" focusable="false" width="1em" height="1em" fill="currentColor"
|
||||
aria-hidden="true">
|
||||
<path
|
||||
d="M347.6 528.95l383.2 301.02c14.25 11.2 35.2 1.1 35.2-16.95V210.97c0-18.05-20.95-28.14-35.2-16.94L347.6 495.05a21.53 21.53 0 0 0 0 33.9M330 864h-64a8 8 0 0 1-8-8V168a8 8 0 0 1 8-8h64a8 8 0 0 1 8 8v688a8 8 0 0 1-8 8">
|
||||
</path>
|
||||
</svg>
|
||||
</div>
|
||||
<div id="prePage" title="上一页" class="btn-icon">
|
||||
<svg viewbox="64 64 896 896" focusable="false" width="1em" height="1em" fill="currentColor"
|
||||
aria-hidden="true">
|
||||
<path
|
||||
d="M689 165.1L308.2 493.5c-10.9 9.4-10.9 27.5 0 37L689 858.9c14.2 12.2 35 1.2 35-18.5V183.6c0-19.7-20.8-30.7-35-18.5z">
|
||||
</path>
|
||||
</svg>
|
||||
</div>
|
||||
<div id="pageInfo" class="btn-icon">1/0</div>
|
||||
<div id="nextPage" title="下一页" class="btn-icon">
|
||||
<svg viewbox="64 64 896 896" focusable="false" width="1em" height="1em" fill="currentColor"
|
||||
aria-hidden="true">
|
||||
<path
|
||||
d="M715.8 493.5L335 165.1c-14.2-12.2-35-1.2-35 18.5v656.8c0 19.7 20.8 30.7 35 18.5l380.8-328.4c10.9-9.4 10.9-27.6 0-37z">
|
||||
</path>
|
||||
</svg>
|
||||
</div>
|
||||
<div id="lastPage" title="尾页" class="btn-icon">
|
||||
<svg viewbox="64 64 896 896" focusable="false" width="1em" height="1em" fill="currentColor"
|
||||
aria-hidden="true">
|
||||
<path
|
||||
d="M676.4 528.95L293.2 829.97c-14.25 11.2-35.2 1.1-35.2-16.95V210.97c0-18.05 20.95-28.14 35.2-16.94l383.2 301.02a21.53 21.53 0 0 1 0 33.9M694 864h64a8 8 0 0 0 8-8V168a8 8 0 0 0-8-8h-64a8 8 0 0 0-8 8v688a8 8 0 0 0 8 8">
|
||||
</path>
|
||||
</svg>
|
||||
</div>
|
||||
<div id="separator2" class="horizontalToolbarSeparator"></div>
|
||||
<div id="print" title="打印" class="btn-icon">
|
||||
<svg viewbox="64 64 896 896" focusable="false" data-icon="printer" width="1em" height="1em"
|
||||
fill="currentColor" aria-hidden="true">
|
||||
<path
|
||||
d="M820 436h-40c-4.4 0-8 3.6-8 8v40c0 4.4 3.6 8 8 8h40c4.4 0 8-3.6 8-8v-40c0-4.4-3.6-8-8-8zm32-104H732V120c0-4.4-3.6-8-8-8H300c-4.4 0-8 3.6-8 8v212H172c-44.2 0-80 35.8-80 80v328c0 17.7 14.3 32 32 32h168v132c0 4.4 3.6 8 8 8h424c4.4 0 8-3.6 8-8V772h168c17.7 0 32-14.3 32-32V412c0-44.2-35.8-80-80-80zM360 180h304v152H360V180zm304 664H360V568h304v276zm200-140H732V500H292v204H160V412c0-6.6 5.4-12 12-12h680c6.6 0 12 5.4 12 12v292z">
|
||||
</path>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<main class="el-main" id="main" style="height: auto; background: rgb(242, 242, 242); padding: 0px;">
|
||||
<div id="leftMenu" class="left-section"></div>
|
||||
<div id="content" class="main-section"></div>
|
||||
<div id="loading"
|
||||
style="position:absolute; z-index:999; display:none; top:50%; left:50%; transform:translate(-50%,-50%);">
|
||||
<img src="ofd/img/loading.gif" alt="" />
|
||||
</div>
|
||||
</main>
|
||||
</section>
|
||||
</div>
|
||||
<!-- cnofd 视图脚本(必须放在 DOM 之后) -->
|
||||
<script src="ofd/js/cnofd-view.js"></script>
|
||||
<script type="text/javascript">
|
||||
// ========== 整合后端变量,直接指定 OFD 文件地址 ==========
|
||||
// 后端传入的原始 URL(可能未经过代理)
|
||||
var rawUrl = '${finalUrl}';
|
||||
var kkagent = '${kkagent}';
|
||||
var baseUrl = '${baseUrl}'.endsWith('/') ? '${baseUrl}' : '${baseUrl}' + '/';
|
||||
var pageNum = '${page}'; // 可选,用于跳转到指定页
|
||||
|
||||
// 根据代理标志计算最终的文件地址(与原 iframe 逻辑完全一致)
|
||||
var finalOfdUrl = rawUrl;
|
||||
if (kkagent === 'true' || !finalOfdUrl.startsWith(baseUrl)) {
|
||||
<iframe src="" width="100%" frameborder="0"></iframe>
|
||||
</body>
|
||||
<script type="text/javascript">
|
||||
var url = '${finalUrl}';
|
||||
var kkagent = '${kkagent}';
|
||||
var baseUrl = '${baseUrl}'.endsWith('/') ? '${baseUrl}' : '${baseUrl}' + '/';
|
||||
|
||||
if (kkagent === 'true' || !url.startsWith(baseUrl)) {
|
||||
url = baseUrl + 'getCorsFile?urlPath=' + encodeURIComponent(Base64.encode(url))+ "&key=${kkkey}";
|
||||
}
|
||||
console.log("Hello, world!");
|
||||
console.log(finalOfdUrl);
|
||||
if(IsPhone()){
|
||||
document.getElementsByTagName('iframe')[0].src = "${baseUrl}ofd/index.html?file=" + encodeURIComponent(url)+"&scale=width"+"&page=${page}";
|
||||
}else{
|
||||
document.getElementsByTagName('iframe')[0].src = "${baseUrl}ofd/index.html?file="+ encodeURIComponent(url)+"&page=${page}";
|
||||
}
|
||||
document.getElementsByTagName('iframe')[0].height = document.documentElement.clientHeight - 10;
|
||||
/**
|
||||
* 页面变化调整高度
|
||||
*/
|
||||
window.onresize = function () {
|
||||
var fm = document.getElementsByTagName("iframe")[0];
|
||||
fm.height = window.document.documentElement.clientHeight - 10;
|
||||
}
|
||||
|
||||
// 页面加载完成后自动加载 OFD 文件
|
||||
$(document).ready(function() {
|
||||
// 延迟确保 cnofd 库完全初始化
|
||||
setTimeout(function() {
|
||||
if (typeof loadOfdFile === 'function') {
|
||||
loadOfdFile(finalOfdUrl);
|
||||
// 如果传入了页码参数,加载后跳转到指定页
|
||||
if (pageNum && !isNaN(pageNum) && pageNum > 1) {
|
||||
setTimeout(function() {
|
||||
// 等待渲染完成后再跳页
|
||||
if (typeof kkPage === 'function') {
|
||||
kkPage(); // 此函数需要提前定义,或使用类似逻辑
|
||||
} else {
|
||||
console.warn('未找到 kkPage 函数,无法跳转到指定页');
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
} else {
|
||||
console.error("cnofd 库未加载完成,请检查路径:ofd/js/cnofd-view.js");
|
||||
}
|
||||
}, 500);
|
||||
});
|
||||
// 保留水印初始化(原模板中的逻辑)
|
||||
window.onload = function () {
|
||||
if (typeof initWaterMark === 'function') {
|
||||
initWaterMark();
|
||||
}
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
function IsPhone() {
|
||||
var info = navigator.userAgent;
|
||||
//通过正则表达式的test方法判断是否包含“Mobile”字符串
|
||||
var isPhone = /mobile/i.test(info);
|
||||
//如果包含“Mobile”(是手机设备)则返回true
|
||||
return isPhone;
|
||||
}
|
||||
/*初始化水印*/
|
||||
window.onload = function () {
|
||||
initWaterMark();
|
||||
}
|
||||
</script>
|
||||
</html>
|
||||
|
||||
@@ -5,177 +5,47 @@
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, user-scalable=yes, initial-scale=1.0">
|
||||
<title>${file.name}3D预览</title>
|
||||
<script src="js/base64.min.js" type="text/javascript"></script>
|
||||
<script src="js/base64.min.js" type="text/javascript"></script>
|
||||
<#include "*/commonHeader.ftl">
|
||||
<!-- 引入 jQuery 和 3D Viewer 核心样式/脚本 -->
|
||||
<script src="js/jquery-3.7.1.min.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/website/build/website_dev/o3dv.website.min.css">
|
||||
<script type="text/javascript" src="/website/build/website_dev/o3dv.website.min.js"></script>
|
||||
<style>
|
||||
/* 提示样式 */
|
||||
.toast {
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
background: #323232;
|
||||
color: #fff;
|
||||
padding: 8px 16px;
|
||||
border-radius: 20px;
|
||||
font-size: 12px;
|
||||
z-index: 10001;
|
||||
font-family: monospace;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<#-- 根据变量计算最终模型 URL(与原有逻辑保持一致) -->
|
||||
<#if currentUrl?contains("http://") || currentUrl?contains("https://") || currentUrl?contains("file://")>
|
||||
<#assign finalUrl="${currentUrl}">
|
||||
<#elseif currentUrl?contains("ftp://") >
|
||||
<#if currentUrl?contains("http://") || currentUrl?contains("https://") || currentUrl?contains("file://")>
|
||||
<#assign finalUrl="${currentUrl}">
|
||||
<#elseif currentUrl?contains("ftp://") >
|
||||
<#assign finalUrl="${currentUrl}">
|
||||
<#else>
|
||||
<#assign finalUrl="${baseUrl}${currentUrl}">
|
||||
</#if>
|
||||
|
||||
<body>
|
||||
<!-- 3D Viewer 的 DOM 结构(从原示例中精简,保留核心容器) -->
|
||||
<input type="file" id="open_file" style="display:none;" multiple>
|
||||
<div class="header" id="header">
|
||||
<div class="title">
|
||||
<div class="title_left"></div>
|
||||
<div class="title_right" id="header_buttons"></div>
|
||||
<div class="main_file_name only_full_width" id="main_file_name"></div>
|
||||
</div>
|
||||
<div class="toolbar" id="toolbar"></div>
|
||||
</div>
|
||||
<div class="main" id="main">
|
||||
<div class="main_left_container only_full_width" id="main_left_container">
|
||||
<div class="main_navigator ov_panel_set_container" id="main_navigator"></div>
|
||||
<div class="main_splitter" id="main_navigator_splitter"></div>
|
||||
</div>
|
||||
<div class="main_viewer" id="main_viewer"></div>
|
||||
<div class="main_right_container only_full_width" id="main_right_container">
|
||||
<div class="main_splitter" id="main_sidebar_splitter"></div>
|
||||
<div class="main_sidebar ov_panel_set_right_container" id="main_sidebar"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="intro ov_thin_scrollbar" id="intro">
|
||||
<div class="intro_content" id="intro_content">
|
||||
<div class="intro_formats">
|
||||
<div class="intro_formats_title" id="intro_formats_title"></div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
// 保留原有事件处理
|
||||
OV.SetWebsiteEventHandler((eventName, eventLabel, eventParams) => {
|
||||
console.log({ eventName, eventLabel, eventParams });
|
||||
});
|
||||
|
||||
// 自定义加载逻辑(使用 fetch + Blob + ImportFiles)
|
||||
(function($) {
|
||||
// 从后端变量获取模型最终地址
|
||||
const MODEL_URL = '${finalUrl}';
|
||||
const kkagent = '${kkagent}';
|
||||
const baseUrl = '${baseUrl}'.endsWith('/') ? '${baseUrl}' : '${baseUrl}' + '/';
|
||||
if (kkagent === 'true' || !MODEL_URL.startsWith(baseUrl)) {
|
||||
MODEL_URL = baseUrl + 'getCorsFile?urlPath=' + encodeURIComponent(Base64.encode(MODEL_URL))+ "&key=${kkkey}";
|
||||
}
|
||||
|
||||
function showMessage(msg, isError = false) {
|
||||
let toast = $('<div class="toast">' + msg + '</div>');
|
||||
if (isError) toast.css('background', '#d32f2f');
|
||||
$('body').append(toast);
|
||||
setTimeout(() => toast.fadeOut(300, () => toast.remove()), 3000);
|
||||
}
|
||||
|
||||
async function loadModelFromUrl(modelUrl) {
|
||||
|
||||
try {
|
||||
const response = await fetch(modelUrl, { mode: 'cors', credentials: 'same-origin' });
|
||||
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
||||
const blob = await response.blob();
|
||||
const fileName = modelUrl.split('/').pop() || 'model.bin';
|
||||
const file = new File([blob], fileName, { type: blob.type || 'application/octet-stream' });
|
||||
|
||||
const dataTransfer = new DataTransfer();
|
||||
dataTransfer.items.add(file);
|
||||
const fileList = dataTransfer.files;
|
||||
|
||||
let imported = false;
|
||||
if (OV.Website && typeof OV.Website.ImportFiles === 'function') {
|
||||
OV.Website.ImportFiles(fileList);
|
||||
imported = true;
|
||||
} else if (OV.Website && typeof OV.Website.LoadFiles === 'function') {
|
||||
OV.Website.LoadFiles(fileList);
|
||||
imported = true;
|
||||
} else {
|
||||
let viewer = null;
|
||||
if (OV.ViewerManager && typeof OV.ViewerManager.getViewer === 'function') {
|
||||
viewer = OV.ViewerManager.getViewer();
|
||||
} else {
|
||||
const viewerElem = document.getElementById('main_viewer');
|
||||
if (viewerElem && viewerElem.__viewer) viewer = viewerElem.__viewer;
|
||||
}
|
||||
if (viewer && typeof viewer.ImportFiles === 'function') {
|
||||
viewer.ImportFiles(fileList);
|
||||
imported = true;
|
||||
} else if (viewer && typeof viewer.LoadFiles === 'function') {
|
||||
viewer.LoadFiles(fileList);
|
||||
imported = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!imported) {
|
||||
const fileInput = document.getElementById('open_file');
|
||||
if (fileInput) {
|
||||
const dt = new DataTransfer();
|
||||
dt.items.add(file);
|
||||
fileInput.files = dt.files;
|
||||
fileInput.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
imported = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (imported) {
|
||||
showMessage(`✅ 已加载: ${fileName}`);
|
||||
} else {
|
||||
throw new Error('无法将文件传递给查看器');
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
showMessage(`❌ 加载失败: ${err.message}`, true);
|
||||
}
|
||||
}
|
||||
|
||||
$(window).on('load', function() {
|
||||
// 等待查看器核心初始化完成后再加载模型
|
||||
setTimeout(() => {
|
||||
console.log('[自动加载] 固定模型:', MODEL_URL);
|
||||
if (MODEL_URL && MODEL_URL !== '') {
|
||||
loadModelFromUrl(MODEL_URL);
|
||||
} else {
|
||||
showMessage('❌ 模型地址为空', true);
|
||||
}
|
||||
}, 600);
|
||||
});
|
||||
})(jQuery);
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
// 启动 3D Viewer(注意:必须在 DOM 加载后执行,但脚本位置已在 body 底部)
|
||||
OV.StartWebsite();
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
/* 初始化水印(保留原逻辑) */
|
||||
if (!!window.ActiveXObject || "ActiveXObject" in window) {
|
||||
// IE 不支持水印
|
||||
} else {
|
||||
initWaterMark();
|
||||
}
|
||||
|
||||
</script>
|
||||
<iframe src="" width="100%" frameborder="0"></iframe>
|
||||
</body>
|
||||
<script type="text/javascript">
|
||||
var url = '${finalUrl}';
|
||||
var kkagent = '${kkagent}';
|
||||
var baseUrl = '${baseUrl}'.endsWith('/') ? '${baseUrl}' : '${baseUrl}' + '/';
|
||||
if (kkagent === 'true' || !url.startsWith(baseUrl)) {
|
||||
url = baseUrl + 'getCorsFile?urlPath=' + encodeURIComponent(Base64.encode(url))+ "&key=${kkkey}";
|
||||
document.getElementsByTagName('iframe')[0].src = "${baseUrl}website/index.html#model="+ url + "&fullfilename=/${file.name}";
|
||||
}else{
|
||||
document.getElementsByTagName('iframe')[0].src = "${baseUrl}website/index.html#model="+ url;
|
||||
}
|
||||
|
||||
document.getElementsByTagName('iframe')[0].height = document.documentElement.clientHeight - 10;
|
||||
/**
|
||||
* 页面变化调整高度
|
||||
*/
|
||||
window.onresize = function () {
|
||||
var fm = document.getElementsByTagName("iframe")[0];
|
||||
fm.height = window.document.documentElement.clientHeight - 10;
|
||||
}
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
/*初始化水印*/
|
||||
if (!!window.ActiveXObject || "ActiveXObject" in window)
|
||||
{
|
||||
}else{
|
||||
initWaterMark();
|
||||
}
|
||||
</script>
|
||||
</html>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user