mirror of
https://github.com/qaiu/netdisk-fast-download.git
synced 2026-04-13 12:26:55 +00:00
Compare commits
337 Commits
71a220f42b
...
v0.1.9b13
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
93835bd990 | ||
|
|
93ab3f3f3f | ||
|
|
de7703be83 | ||
|
|
ce1c4ee669 | ||
|
|
c60d9fdd61 | ||
|
|
2033542f49 | ||
|
|
3775cd0259 | ||
|
|
bec342d778 | ||
|
|
6305d805dd | ||
|
|
2ada2fddf7 | ||
|
|
66ba8b7ee8 | ||
|
|
2edf235941 | ||
|
|
57ef723368 | ||
|
|
366658b471 | ||
|
|
2a3244a8fa | ||
|
|
9912e6fef1 | ||
|
|
d475dcbcdc | ||
|
|
5ffe94e3a4 | ||
|
|
5809d3b664 | ||
|
|
2bed42a088 | ||
|
|
97e912c216 | ||
|
|
f657aa183c | ||
|
|
cf634c4464 | ||
|
|
a9b5d9ab57 | ||
|
|
f82267f8a7 | ||
|
|
46bd5819b3 | ||
|
|
d10a55d8cb | ||
|
|
e74d5ea97e | ||
|
|
1dfdff7024 | ||
|
|
f5c81e1b8e | ||
|
|
804b8853d9 | ||
|
|
f87a66bc79 | ||
|
|
74b9cc438c | ||
|
|
7829174cc0 | ||
|
|
2e558df96b | ||
|
|
474eea5f80 | ||
|
|
fc50d1f5ba | ||
|
|
3b63f48dfa | ||
|
|
95697de1d0 | ||
|
|
1aa9ecdc45 | ||
|
|
0a3dbc6342 | ||
|
|
72f215c301 | ||
|
|
add90984a5 | ||
|
|
857ac7a2c9 | ||
|
|
b807223614 | ||
|
|
c775dabd7e | ||
|
|
5ee0aae6e1 | ||
|
|
5c8e4d7754 | ||
|
|
79123448f6 | ||
|
|
8e4328f1eb | ||
|
|
63c810dcbb | ||
|
|
c71d4cfa87 | ||
|
|
2b17567a1d | ||
|
|
ba5f88af43 | ||
|
|
782f47c7c5 | ||
|
|
8f92ce9292 | ||
|
|
1c3b5082a2 | ||
|
|
8535f49786 | ||
|
|
92043cf415 | ||
|
|
c97a235e23 | ||
|
|
97c2fe6784 | ||
|
|
1baa6e36b8 | ||
|
|
9dbc8718a8 | ||
|
|
3107281cdc | ||
|
|
c5b2340fe6 | ||
|
|
2f6f977adb | ||
|
|
902443b511 | ||
|
|
322f173104 | ||
|
|
c61ba45d59 | ||
|
|
684e8d4c84 | ||
|
|
a96bde812d | ||
|
|
c0276f97d6 | ||
|
|
f60d2573e6 | ||
|
|
7e746ded60 | ||
|
|
11669c07ed | ||
|
|
0c0e4c9cc1 | ||
|
|
a3ab467c74 | ||
|
|
acb646ee2d | ||
|
|
5a02c38d57 | ||
|
|
bd9ac79ec9 | ||
|
|
d6c8b2f476 | ||
|
|
b616c59f1b | ||
|
|
c6603c0d83 | ||
|
|
ae0a5644b5 | ||
|
|
d87ab43a9b | ||
|
|
cfe084cb07 | ||
|
|
75521c87ba | ||
|
|
67042b39b3 | ||
|
|
c65b55d0c6 | ||
|
|
8e938acdb2 | ||
|
|
5db5b3c75a | ||
|
|
291df9d984 | ||
|
|
323c62f4e6 | ||
|
|
03e2bbbb91 | ||
|
|
4b8660932a | ||
|
|
35c7746e38 | ||
|
|
e2155aec45 | ||
|
|
aaf34a460e | ||
|
|
1bb30a9ed2 | ||
|
|
b1c68aa865 | ||
|
|
8b57d04a2e | ||
|
|
1a57bddef7 | ||
|
|
1d30716aa6 | ||
|
|
a2aabfc601 | ||
|
|
f7040a3c1c | ||
|
|
40d4a1fcb5 | ||
|
|
e01bb2d8d7 | ||
|
|
d8a4d2e39f | ||
|
|
dbbd5759ab | ||
|
|
0a59ff2357 | ||
|
|
4e1eb6654d | ||
|
|
b588ba740f | ||
|
|
af605a2be7 | ||
|
|
b2630a7e35 | ||
|
|
211fe92a35 | ||
|
|
be168a9f0d | ||
|
|
977f5dc6dd | ||
|
|
131cb7085d | ||
|
|
7fbd446a2a | ||
|
|
7b64699782 | ||
|
|
bad56037c4 | ||
|
|
180e54f278 | ||
|
|
ae89e0be26 | ||
|
|
f19b366b1b | ||
|
|
6b1bd573c8 | ||
|
|
43c82f2f16 | ||
|
|
e478486d73 | ||
|
|
32e5c69735 | ||
|
|
4ec5b491c5 | ||
|
|
6a0e4a695d | ||
|
|
e6d69331be | ||
|
|
f16e196040 | ||
|
|
2f67e3b04d | ||
|
|
4663751924 | ||
|
|
e6ae7e2545 | ||
|
|
74ec248b8c | ||
|
|
cd04eead07 | ||
|
|
2b4340a5d6 | ||
|
|
ff6913264f | ||
|
|
ffd88841d5 | ||
|
|
0ed0d2ed82 | ||
|
|
c2387c47ee | ||
|
|
65cc78de7d | ||
|
|
8bedfcf794 | ||
|
|
1cd059f842 | ||
|
|
42438f2bbd | ||
|
|
1fb6e5d660 | ||
|
|
3fa0588e03 | ||
|
|
5a008f4ddd | ||
|
|
1a0b3a75c3 | ||
|
|
c5ad19881c | ||
|
|
6188e5f2c6 | ||
|
|
6f19fbd300 | ||
|
|
5307da24ed | ||
|
|
e65da6fe4a | ||
|
|
7ed83e9437 | ||
|
|
f008f490d9 | ||
|
|
01109dedbd | ||
|
|
f2a78d8937 | ||
|
|
eef56b308c | ||
|
|
c9ca47b27d | ||
|
|
35e54f5ad5 | ||
|
|
310d516aac | ||
|
|
aee84e3cb3 | ||
|
|
f9fd68c0f4 | ||
|
|
9761a9e2d9 | ||
|
|
8bed7487de | ||
|
|
2b084a3cc8 | ||
|
|
1caabd1368 | ||
|
|
b5397ba303 | ||
|
|
36f9b53f9b | ||
|
|
26fcbaa9a6 | ||
|
|
a8a5b6e3ab | ||
|
|
588e087941 | ||
|
|
fe71db0967 | ||
|
|
9436575dcb | ||
|
|
4ea380d28e | ||
|
|
1f46b477e3 | ||
|
|
f7e17a10b5 | ||
|
|
6e19e29857 | ||
|
|
f6b5d72784 | ||
|
|
68f1334907 | ||
|
|
a83f4e9a2f | ||
|
|
fcd8709c7d | ||
|
|
854d0ea241 | ||
|
|
cff223ecd2 | ||
|
|
8f14762f43 | ||
|
|
c37ae638d2 | ||
|
|
bcfa46ec43 | ||
|
|
42cfe4aacf | ||
|
|
64dba88881 | ||
|
|
3f300ded96 | ||
|
|
1ceafc5c08 | ||
|
|
93adb06083 | ||
|
|
3ef1c81d13 | ||
|
|
84b4deffc6 | ||
|
|
2e7f1a7e52 | ||
|
|
59bea226e5 | ||
|
|
0bbef0c7a9 | ||
|
|
fc91192d0e | ||
|
|
8dbcaed813 | ||
|
|
577ec46f71 | ||
|
|
65bf4534c7 | ||
|
|
5b666e1fec | ||
|
|
e839f56a91 | ||
|
|
c5a327e2e0 | ||
|
|
5b5a11ac36 | ||
|
|
0c3efe326f | ||
|
|
b9100fb934 | ||
|
|
74a98713c1 | ||
|
|
339b80bbea | ||
|
|
ce0c3b3a1e | ||
|
|
1e611dd85b | ||
|
|
0791114e92 | ||
|
|
c85b9a01fd | ||
|
|
9c2a0e7f46 | ||
|
|
8699aef0da | ||
|
|
749bc67212 | ||
|
|
67e24e846b | ||
|
|
091def569a | ||
|
|
fb0cf9102b | ||
|
|
69ce48adb4 | ||
|
|
6c3ab975cc | ||
|
|
f501935365 | ||
|
|
c3593f335e | ||
|
|
351bdd9c58 | ||
|
|
812042b95e | ||
|
|
9957fcbce8 | ||
|
|
acb2c00cca | ||
|
|
9655b8715e | ||
|
|
13de30e8b5 | ||
|
|
1cfeae2ad2 | ||
|
|
31b4190eaf | ||
|
|
380e1c7482 | ||
|
|
f202800a0a | ||
|
|
96d246e64f | ||
|
|
75b460f4b0 | ||
|
|
1ba7af485d | ||
|
|
76c16c6312 | ||
|
|
66a09a8f1c | ||
|
|
235fed1b4e | ||
|
|
f75921ba03 | ||
|
|
202b261a53 | ||
|
|
95c39d258e | ||
|
|
71b35e4651 | ||
|
|
2465a4d6d3 | ||
|
|
30d4ce4781 | ||
|
|
27be70ea00 | ||
|
|
0c22267eaa | ||
|
|
d4f4ec67c3 | ||
|
|
df74d9a117 | ||
|
|
2fc7556f39 | ||
|
|
418dcde15f | ||
|
|
59db290cae | ||
|
|
2992d3586f | ||
|
|
7b8eea4865 | ||
|
|
6b2bba2854 | ||
|
|
4666e942b4 | ||
|
|
daa3c940ee | ||
|
|
e54c15dad1 | ||
|
|
054024e3e8 | ||
|
|
5be8c4548f | ||
|
|
60bd8ecf21 | ||
|
|
25edeaf709 | ||
|
|
1e7525f908 | ||
|
|
341e33a845 | ||
|
|
f5ef8c07a5 | ||
|
|
76da12da65 | ||
|
|
dacf93bd06 | ||
|
|
498bce5255 | ||
|
|
d67df58bc6 | ||
|
|
751c7163fe | ||
|
|
9bd5da8ac3 | ||
|
|
769e8545b6 | ||
|
|
a30c037138 | ||
|
|
3c7fc752fc | ||
|
|
54576e8cbc | ||
|
|
f2bac57ed3 | ||
|
|
a3220c36c1 | ||
|
|
821fc945cf | ||
|
|
784b3334f4 | ||
|
|
57c3355d3e | ||
|
|
9275e28e15 | ||
|
|
a82596dc70 | ||
|
|
add27186bc | ||
|
|
087ad0c120 | ||
|
|
5cd1db7e4b | ||
|
|
3cdbac1603 | ||
|
|
7402dd76cc | ||
|
|
de2e47628a | ||
|
|
aad0098169 | ||
|
|
922ce84000 | ||
|
|
aabfcd8c8b | ||
|
|
0e15d9f309 | ||
|
|
5ac89ac085 | ||
|
|
b3ec433d33 | ||
|
|
207b4cf6b3 | ||
|
|
03fbb3ef15 | ||
|
|
4ce62d6b98 | ||
|
|
1f504a8cd5 | ||
|
|
dd52f5a61f | ||
|
|
8369212bd3 | ||
|
|
c67911f1bb | ||
|
|
af95de8d15 | ||
|
|
ba2bfbd11a | ||
|
|
cc4b0ae90e | ||
|
|
399f55cae6 | ||
|
|
981513a557 | ||
|
|
326cfa838c | ||
|
|
b576e06099 | ||
|
|
1ad788c63f | ||
|
|
faf4d8e7ef | ||
|
|
d77095fe87 | ||
|
|
1bd1f611fe | ||
|
|
38f13524a1 | ||
|
|
d5588e3850 | ||
|
|
b7c2887d0c | ||
|
|
1cba9df571 | ||
|
|
32fc530a17 | ||
|
|
c9436f0a47 | ||
|
|
b8174a16f4 | ||
|
|
2a44a55764 | ||
|
|
0ad72c9108 | ||
|
|
b8340949d5 | ||
|
|
6c3433595f | ||
|
|
3e5e42fef9 | ||
|
|
c19f584b0d | ||
|
|
0bbf022c5d | ||
|
|
4516aa8300 | ||
|
|
30a53dd47c | ||
|
|
6e77c21021 | ||
|
|
f035cf4088 | ||
|
|
af5cba5ed6 | ||
|
|
8bb3d26b4c | ||
|
|
ef0829ab8f | ||
|
|
13f3546700 | ||
|
|
0cccba7b3b |
@@ -44,7 +44,7 @@ https://nfd-parser.github.io/nfd-preview/preview.html?src=https%3A%2F%2Flz.qaiu.
|
|||||||
|
|
||||||
## 预览地址
|
## 预览地址
|
||||||
[预览地址1](https://lz.qaiu.top)
|
[预览地址1](https://lz.qaiu.top)
|
||||||
[预览地址2](https://lz0.qaiu.top)
|
[预览地址2](https://lzzz.qaiu.top)
|
||||||
[移动/联通/天翼云盘大文件试用版](https://189.qaiu.top)
|
[移动/联通/天翼云盘大文件试用版](https://189.qaiu.top)
|
||||||
|
|
||||||
main分支依赖JDK17, 提供了JDK11分支[main-jdk11](https://github.com/qaiu/netdisk-fast-download/tree/main-jdk11)
|
main分支依赖JDK17, 提供了JDK11分支[main-jdk11](https://github.com/qaiu/netdisk-fast-download/tree/main-jdk11)
|
||||||
|
|||||||
@@ -23,8 +23,6 @@ import io.vertx.ext.web.RoutingContext;
|
|||||||
import io.vertx.ext.web.handler.*;
|
import io.vertx.ext.web.handler.*;
|
||||||
import io.vertx.ext.web.handler.sockjs.SockJSHandler;
|
import io.vertx.ext.web.handler.sockjs.SockJSHandler;
|
||||||
import io.vertx.ext.web.handler.sockjs.SockJSHandlerOptions;
|
import io.vertx.ext.web.handler.sockjs.SockJSHandlerOptions;
|
||||||
import io.vertx.ext.web.sstore.LocalSessionStore;
|
|
||||||
import io.vertx.ext.web.sstore.SessionStore;
|
|
||||||
import javassist.CtClass;
|
import javassist.CtClass;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
@@ -100,16 +98,6 @@ public class RouterHandlerFactory implements BaseHttpApi {
|
|||||||
// 配置文件上传路径
|
// 配置文件上传路径
|
||||||
mainRouter.route().handler(BodyHandler.create().setUploadsDirectory("uploads"));
|
mainRouter.route().handler(BodyHandler.create().setUploadsDirectory("uploads"));
|
||||||
|
|
||||||
// 配置Session管理 - 用于演练场登录状态持久化
|
|
||||||
// 30天过期时间(毫秒)
|
|
||||||
SessionStore sessionStore = LocalSessionStore.create(VertxHolder.getVertxInstance());
|
|
||||||
SessionHandler sessionHandler = SessionHandler.create(sessionStore)
|
|
||||||
.setSessionTimeout(30L * 24 * 60 * 60 * 1000) // 30天
|
|
||||||
.setSessionCookieName("SESSIONID") // Cookie名称
|
|
||||||
.setCookieHttpOnlyFlag(true) // 防止XSS攻击
|
|
||||||
.setCookieSecureFlag(false); // 非HTTPS环境设置为false
|
|
||||||
mainRouter.route().handler(sessionHandler);
|
|
||||||
|
|
||||||
// 拦截器
|
// 拦截器
|
||||||
Set<Handler<RoutingContext>> interceptorSet = getInterceptorSet();
|
Set<Handler<RoutingContext>> interceptorSet = getInterceptorSet();
|
||||||
Route route0 = mainRouter.route("/*");
|
Route route0 = mainRouter.route("/*");
|
||||||
|
|||||||
@@ -183,20 +183,20 @@ public class JsPlaygroundExecutor {
|
|||||||
// 取消超时任务
|
// 取消超时任务
|
||||||
timeoutTask.cancel(false);
|
timeoutTask.cancel(false);
|
||||||
|
|
||||||
if (error != null) {
|
if (error != null) {
|
||||||
if (error instanceof CancellationException) {
|
if (error instanceof CancellationException) {
|
||||||
String timeoutMsg = "JavaScript执行超时(超过" + EXECUTION_TIMEOUT_SECONDS + "秒),已强制中断";
|
String timeoutMsg = "JavaScript执行超时(超过" + EXECUTION_TIMEOUT_SECONDS + "秒),已强制中断";
|
||||||
playgroundLogger.errorJava(timeoutMsg);
|
playgroundLogger.errorJava(timeoutMsg);
|
||||||
log.error(timeoutMsg);
|
log.error(timeoutMsg);
|
||||||
promise.fail(new RuntimeException(timeoutMsg));
|
promise.fail(new RuntimeException(timeoutMsg));
|
||||||
} else {
|
|
||||||
Throwable cause = error.getCause();
|
|
||||||
promise.fail(cause != null ? cause : error);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
promise.complete(result);
|
Throwable cause = error.getCause();
|
||||||
|
promise.fail(cause != null ? cause : error);
|
||||||
}
|
}
|
||||||
});
|
} else {
|
||||||
|
promise.complete(result);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return promise.future();
|
return promise.future();
|
||||||
}
|
}
|
||||||
@@ -258,20 +258,20 @@ public class JsPlaygroundExecutor {
|
|||||||
// 取消超时任务
|
// 取消超时任务
|
||||||
timeoutTask.cancel(false);
|
timeoutTask.cancel(false);
|
||||||
|
|
||||||
if (error != null) {
|
if (error != null) {
|
||||||
if (error instanceof CancellationException) {
|
if (error instanceof CancellationException) {
|
||||||
String timeoutMsg = "JavaScript执行超时(超过" + EXECUTION_TIMEOUT_SECONDS + "秒),已强制中断";
|
String timeoutMsg = "JavaScript执行超时(超过" + EXECUTION_TIMEOUT_SECONDS + "秒),已强制中断";
|
||||||
playgroundLogger.errorJava(timeoutMsg);
|
playgroundLogger.errorJava(timeoutMsg);
|
||||||
log.error(timeoutMsg);
|
log.error(timeoutMsg);
|
||||||
promise.fail(new RuntimeException(timeoutMsg));
|
promise.fail(new RuntimeException(timeoutMsg));
|
||||||
} else {
|
|
||||||
Throwable cause = error.getCause();
|
|
||||||
promise.fail(cause != null ? cause : error);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
promise.complete(result);
|
Throwable cause = error.getCause();
|
||||||
|
promise.fail(cause != null ? cause : error);
|
||||||
}
|
}
|
||||||
});
|
} else {
|
||||||
|
promise.complete(result);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return promise.future();
|
return promise.future();
|
||||||
}
|
}
|
||||||
@@ -332,20 +332,20 @@ public class JsPlaygroundExecutor {
|
|||||||
// 取消超时任务
|
// 取消超时任务
|
||||||
timeoutTask.cancel(false);
|
timeoutTask.cancel(false);
|
||||||
|
|
||||||
if (error != null) {
|
if (error != null) {
|
||||||
if (error instanceof CancellationException) {
|
if (error instanceof CancellationException) {
|
||||||
String timeoutMsg = "JavaScript执行超时(超过" + EXECUTION_TIMEOUT_SECONDS + "秒),已强制中断";
|
String timeoutMsg = "JavaScript执行超时(超过" + EXECUTION_TIMEOUT_SECONDS + "秒),已强制中断";
|
||||||
playgroundLogger.errorJava(timeoutMsg);
|
playgroundLogger.errorJava(timeoutMsg);
|
||||||
log.error(timeoutMsg);
|
log.error(timeoutMsg);
|
||||||
promise.fail(new RuntimeException(timeoutMsg));
|
promise.fail(new RuntimeException(timeoutMsg));
|
||||||
} else {
|
|
||||||
Throwable cause = error.getCause();
|
|
||||||
promise.fail(cause != null ? cause : error);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
promise.complete(result);
|
Throwable cause = error.getCause();
|
||||||
|
promise.fail(cause != null ? cause : error);
|
||||||
}
|
}
|
||||||
});
|
} else {
|
||||||
|
promise.complete(result);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return promise.future();
|
return promise.future();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import java.util.regex.Pattern;
|
|||||||
*/
|
*/
|
||||||
public class LzTool extends PanBase {
|
public class LzTool extends PanBase {
|
||||||
|
|
||||||
public static final String SHARE_URL_PREFIX = "https://wwwwp.lanzoup.com";
|
public static final String SHARE_URL_PREFIX = "https://wwww.lanzoum.com";
|
||||||
MultiMap headers0 = HeaderUtils.parseHeaders("""
|
MultiMap headers0 = HeaderUtils.parseHeaders("""
|
||||||
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
|
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
|
||||||
Accept-Encoding: gzip, deflate
|
Accept-Encoding: gzip, deflate
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
### 1. NPM包安装
|
### 1. NPM包安装
|
||||||
已在 `package.json` 中安装:
|
已在 `package.json` 中安装:
|
||||||
- `monaco-editor`: ^0.55.1 - Monaco Editor核心包
|
- `monaco-editor`: ^0.45.0 - Monaco Editor核心包
|
||||||
- `@monaco-editor/loader`: ^1.4.0 - Monaco Editor加载器
|
- `@monaco-editor/loader`: ^1.4.0 - Monaco Editor加载器
|
||||||
- `monaco-editor-webpack-plugin`: ^7.1.1 - Webpack打包插件(devDependencies)
|
- `monaco-editor-webpack-plugin`: ^7.1.1 - Webpack打包插件(devDependencies)
|
||||||
|
|
||||||
@@ -172,5 +172,3 @@ Monaco Editor 打包后会增加构建产物大小(约2-3MB),但这是正
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
"clipboard": "^2.0.11",
|
"clipboard": "^2.0.11",
|
||||||
"core-js": "^3.8.3",
|
"core-js": "^3.8.3",
|
||||||
"element-plus": "2.11.3",
|
"element-plus": "2.11.3",
|
||||||
"monaco-editor": "^0.55.1",
|
"monaco-editor": "^0.45.0",
|
||||||
"qrcode": "^1.5.4",
|
"qrcode": "^1.5.4",
|
||||||
"splitpanes": "^4.0.4",
|
"splitpanes": "^4.0.4",
|
||||||
"vue": "^3.5.12",
|
"vue": "^3.5.12",
|
||||||
|
|||||||
@@ -9,8 +9,8 @@
|
|||||||
content="Netdisk fast download,网盘直链解析工具">
|
content="Netdisk fast download,网盘直链解析工具">
|
||||||
<meta name="description"
|
<meta name="description"
|
||||||
content="Netdisk fast download 网盘直链解析工具">
|
content="Netdisk fast download 网盘直链解析工具">
|
||||||
<!-- Font Awesome 图标库 - 使用国内CDN -->
|
<!-- Font Awesome 图标库 -->
|
||||||
<link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||||
<style>
|
<style>
|
||||||
.page-loading-wrap {
|
.page-loading-wrap {
|
||||||
padding: 120px;
|
padding: 120px;
|
||||||
@@ -154,26 +154,11 @@
|
|||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<script>
|
<script>
|
||||||
// 等待DOM加载完成后再操作
|
const saved = localStorage.getItem('isDarkMode') === 'true'
|
||||||
(function() {
|
const systemDark = window.matchMedia('(prefers-color-scheme: dark)').matches
|
||||||
function applyDarkTheme() {
|
if (saved || (!saved && systemDark)) {
|
||||||
const body = document.body;
|
document.body.classList.add('dark-theme')
|
||||||
if (body && body.classList) {
|
}
|
||||||
// 只在用户明确选择暗色模式时才应用,不自动检测系统偏好
|
|
||||||
if (localStorage.getItem('isDarkMode') === 'true') {
|
|
||||||
body.classList.add('dark-theme')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果DOM已加载,立即执行
|
|
||||||
if (document.readyState === 'loading') {
|
|
||||||
document.addEventListener('DOMContentLoaded', applyDarkTheme);
|
|
||||||
} else {
|
|
||||||
// DOM已加载,立即执行
|
|
||||||
applyDarkTheme();
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
@@ -43,16 +43,12 @@ watch(darkMode, (newValue) => {
|
|||||||
emit('theme-change', newValue)
|
emit('theme-change', newValue)
|
||||||
|
|
||||||
// 应用主题到body
|
// 应用主题到body
|
||||||
const html = document.documentElement;
|
if (newValue) {
|
||||||
const body = document.body;
|
document.body.classList.add('dark-theme')
|
||||||
if (html && body && html.classList && body.classList) {
|
document.documentElement.classList.add('dark-theme')
|
||||||
if (newValue) {
|
} else {
|
||||||
body.classList.add('dark-theme')
|
document.body.classList.remove('dark-theme')
|
||||||
html.classList.add('dark-theme')
|
document.documentElement.classList.remove('dark-theme')
|
||||||
} else {
|
|
||||||
body.classList.remove('dark-theme')
|
|
||||||
html.classList.remove('dark-theme')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -61,11 +57,9 @@ onMounted(() => {
|
|||||||
emit('theme-change', darkMode.value)
|
emit('theme-change', darkMode.value)
|
||||||
|
|
||||||
// 应用初始主题
|
// 应用初始主题
|
||||||
const html = document.documentElement;
|
if (darkMode.value) {
|
||||||
const body = document.body;
|
document.body.classList.add('dark-theme')
|
||||||
if (html && body && html.classList && body.classList && darkMode.value) {
|
document.documentElement.classList.add('dark-theme')
|
||||||
body.classList.add('dark-theme')
|
|
||||||
html.classList.add('dark-theme')
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -388,14 +388,8 @@ export default {
|
|||||||
return date.toLocaleString('zh-CN')
|
return date.toLocaleString('zh-CN')
|
||||||
},
|
},
|
||||||
checkTheme() {
|
checkTheme() {
|
||||||
const html = document.documentElement;
|
this.isDarkTheme = document.body.classList.contains('dark-theme') ||
|
||||||
const body = document.body;
|
document.documentElement.classList.contains('dark-theme')
|
||||||
if (html && body && html.classList && body.classList) {
|
|
||||||
this.isDarkTheme = body.classList.contains('dark-theme') ||
|
|
||||||
html.classList.contains('dark-theme')
|
|
||||||
} else {
|
|
||||||
this.isDarkTheme = false;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
renderContent(h, { node, data, store }) {
|
renderContent(h, { node, data, store }) {
|
||||||
const isFolder = data.fileType === 'folder'
|
const isFolder = data.fileType === 'folder'
|
||||||
|
|||||||
@@ -94,14 +94,6 @@ export default {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 配置Monaco Editor使用国内CDN (npmmirror)
|
|
||||||
// npmmirror的路径格式: https://registry.npmmirror.com/包名/版本号/files/文件路径
|
|
||||||
loader.config({
|
|
||||||
paths: {
|
|
||||||
vs: 'https://registry.npmmirror.com/monaco-editor/0.55.1/files/min/vs'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 初始化Monaco Editor
|
// 初始化Monaco Editor
|
||||||
monaco = await loader.init();
|
monaco = await loader.init();
|
||||||
|
|
||||||
|
|||||||
@@ -10,13 +10,7 @@ const routes = [
|
|||||||
{ path: '/showFile', component: ShowFile },
|
{ path: '/showFile', component: ShowFile },
|
||||||
{ path: '/showList', component: ShowList },
|
{ path: '/showList', component: ShowList },
|
||||||
{ path: '/clientLinks', component: ClientLinks },
|
{ path: '/clientLinks', component: ClientLinks },
|
||||||
{ path: '/playground', component: Playground },
|
{ path: '/playground', component: Playground }
|
||||||
// 404页面 - 必须放在最后
|
|
||||||
{
|
|
||||||
path: '/:pathMatch(.*)*',
|
|
||||||
name: 'NotFound',
|
|
||||||
component: () => import('@/views/NotFound.vue')
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
|
|||||||
@@ -1,10 +1,5 @@
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
|
||||||
// 创建axios实例,配置携带cookie
|
|
||||||
const axiosInstance = axios.create({
|
|
||||||
withCredentials: true // 重要:允许跨域请求携带cookie
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 演练场API服务
|
* 演练场API服务
|
||||||
*/
|
*/
|
||||||
@@ -15,7 +10,7 @@ export const playgroundApi = {
|
|||||||
*/
|
*/
|
||||||
async getStatus() {
|
async getStatus() {
|
||||||
try {
|
try {
|
||||||
const response = await axiosInstance.get('/v2/playground/status');
|
const response = await axios.get('/v2/playground/status');
|
||||||
return response.data;
|
return response.data;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new Error(error.response?.data?.error || error.message || '获取状态失败');
|
throw new Error(error.response?.data?.error || error.message || '获取状态失败');
|
||||||
@@ -29,7 +24,7 @@ export const playgroundApi = {
|
|||||||
*/
|
*/
|
||||||
async login(password) {
|
async login(password) {
|
||||||
try {
|
try {
|
||||||
const response = await axiosInstance.post('/v2/playground/login', { password });
|
const response = await axios.post('/v2/playground/login', { password });
|
||||||
return response.data;
|
return response.data;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new Error(error.response?.data?.error || error.message || '登录失败');
|
throw new Error(error.response?.data?.error || error.message || '登录失败');
|
||||||
@@ -46,7 +41,7 @@ export const playgroundApi = {
|
|||||||
*/
|
*/
|
||||||
async testScript(jsCode, shareUrl, pwd = '', method = 'parse') {
|
async testScript(jsCode, shareUrl, pwd = '', method = 'parse') {
|
||||||
try {
|
try {
|
||||||
const response = await axiosInstance.post('/v2/playground/test', {
|
const response = await axios.post('/v2/playground/test', {
|
||||||
jsCode,
|
jsCode,
|
||||||
shareUrl,
|
shareUrl,
|
||||||
pwd,
|
pwd,
|
||||||
@@ -74,7 +69,7 @@ export const playgroundApi = {
|
|||||||
*/
|
*/
|
||||||
async getTypesJs() {
|
async getTypesJs() {
|
||||||
try {
|
try {
|
||||||
const response = await axiosInstance.get('/v2/playground/types.js', {
|
const response = await axios.get('/v2/playground/types.js', {
|
||||||
responseType: 'text'
|
responseType: 'text'
|
||||||
});
|
});
|
||||||
return response.data;
|
return response.data;
|
||||||
@@ -88,7 +83,7 @@ export const playgroundApi = {
|
|||||||
*/
|
*/
|
||||||
async getParserList() {
|
async getParserList() {
|
||||||
try {
|
try {
|
||||||
const response = await axiosInstance.get('/v2/playground/parsers');
|
const response = await axios.get('/v2/playground/parsers');
|
||||||
// 框架会自动包装成JsonResult,需要从data字段获取
|
// 框架会自动包装成JsonResult,需要从data字段获取
|
||||||
if (response.data && response.data.data) {
|
if (response.data && response.data.data) {
|
||||||
return {
|
return {
|
||||||
@@ -109,7 +104,7 @@ export const playgroundApi = {
|
|||||||
*/
|
*/
|
||||||
async saveParser(jsCode) {
|
async saveParser(jsCode) {
|
||||||
try {
|
try {
|
||||||
const response = await axiosInstance.post('/v2/playground/parsers', { jsCode });
|
const response = await axios.post('/v2/playground/parsers', { jsCode });
|
||||||
// 框架会自动包装成JsonResult
|
// 框架会自动包装成JsonResult
|
||||||
if (response.data && response.data.data) {
|
if (response.data && response.data.data) {
|
||||||
return {
|
return {
|
||||||
@@ -135,7 +130,7 @@ export const playgroundApi = {
|
|||||||
*/
|
*/
|
||||||
async updateParser(id, jsCode, enabled = true) {
|
async updateParser(id, jsCode, enabled = true) {
|
||||||
try {
|
try {
|
||||||
const response = await axiosInstance.put(`/v2/playground/parsers/${id}`, { jsCode, enabled });
|
const response = await axios.put(`/v2/playground/parsers/${id}`, { jsCode, enabled });
|
||||||
return response.data;
|
return response.data;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new Error(error.response?.data?.error || error.message || '更新解析器失败');
|
throw new Error(error.response?.data?.error || error.message || '更新解析器失败');
|
||||||
@@ -147,7 +142,7 @@ export const playgroundApi = {
|
|||||||
*/
|
*/
|
||||||
async deleteParser(id) {
|
async deleteParser(id) {
|
||||||
try {
|
try {
|
||||||
const response = await axiosInstance.delete(`/v2/playground/parsers/${id}`);
|
const response = await axios.delete(`/v2/playground/parsers/${id}`);
|
||||||
return response.data;
|
return response.data;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new Error(error.response?.data?.error || error.message || '删除解析器失败');
|
throw new Error(error.response?.data?.error || error.message || '删除解析器失败');
|
||||||
@@ -159,7 +154,7 @@ export const playgroundApi = {
|
|||||||
*/
|
*/
|
||||||
async getParserById(id) {
|
async getParserById(id) {
|
||||||
try {
|
try {
|
||||||
const response = await axiosInstance.get(`/v2/playground/parsers/${id}`);
|
const response = await axios.get(`/v2/playground/parsers/${id}`);
|
||||||
// 框架会自动包装成JsonResult
|
// 框架会自动包装成JsonResult
|
||||||
if (response.data && response.data.data) {
|
if (response.data && response.data.data) {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -48,7 +48,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<!-- 项目简介移到卡片内 -->
|
<!-- 项目简介移到卡片内 -->
|
||||||
<div class="project-intro">
|
<div class="project-intro">
|
||||||
<div class="intro-title">NFD网盘直链解析0.1.9_b15</div>
|
<div class="intro-title">NFD网盘直链解析0.1.9_b12</div>
|
||||||
<div class="intro-desc">
|
<div class="intro-desc">
|
||||||
<div>支持网盘:蓝奏云、蓝奏云优享、小飞机盘、123云盘、奶牛快传、移动云空间、QQ邮箱云盘、QQ闪传等 <el-link style="color:#606cf5" href="https://github.com/qaiu/netdisk-fast-download?tab=readme-ov-file#%E7%BD%91%E7%9B%98%E6%94%AF%E6%8C%81%E6%83%85%E5%86%B5" target="_blank"> >> </el-link></div>
|
<div>支持网盘:蓝奏云、蓝奏云优享、小飞机盘、123云盘、奶牛快传、移动云空间、QQ邮箱云盘、QQ闪传等 <el-link style="color:#606cf5" href="https://github.com/qaiu/netdisk-fast-download?tab=readme-ov-file#%E7%BD%91%E7%9B%98%E6%94%AF%E6%8C%81%E6%83%85%E5%86%B5" target="_blank"> >> </el-link></div>
|
||||||
<div>文件夹解析支持:蓝奏云、蓝奏云优享、小飞机盘、123云盘</div>
|
<div>文件夹解析支持:蓝奏云、蓝奏云优享、小飞机盘、123云盘</div>
|
||||||
@@ -218,7 +218,7 @@
|
|||||||
<!-- 版本号显示 -->
|
<!-- 版本号显示 -->
|
||||||
<div class="version-info">
|
<div class="version-info">
|
||||||
<span class="version-text">内部版本: {{ buildVersion }}</span>
|
<span class="version-text">内部版本: {{ buildVersion }}</span>
|
||||||
<el-link v-if="playgroundEnabled" :href="'/playground'" class="playground-link">脚本演练场</el-link>
|
<!-- <el-link :href="'/playground'" class="playground-link">JS演练场</el-link>-->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 文件解析结果区下方加分享按钮 -->
|
<!-- 文件解析结果区下方加分享按钮 -->
|
||||||
@@ -248,7 +248,6 @@ import DirectoryTree from '@/components/DirectoryTree'
|
|||||||
import parserUrl from '../parserUrl1'
|
import parserUrl from '../parserUrl1'
|
||||||
import fileTypeUtils from '@/utils/fileTypeUtils'
|
import fileTypeUtils from '@/utils/fileTypeUtils'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
import { playgroundApi } from '@/utils/playgroundApi'
|
|
||||||
|
|
||||||
export const previewBaseUrl = 'https://nfd-parser.github.io/nfd-preview/preview.html?src=';
|
export const previewBaseUrl = 'https://nfd-parser.github.io/nfd-preview/preview.html?src=';
|
||||||
|
|
||||||
@@ -298,10 +297,7 @@ export default {
|
|||||||
errorButtonVisible: false,
|
errorButtonVisible: false,
|
||||||
|
|
||||||
// 版本信息
|
// 版本信息
|
||||||
buildVersion: '',
|
buildVersion: ''
|
||||||
|
|
||||||
// 演练场启用状态
|
|
||||||
playgroundEnabled: false
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@@ -320,9 +316,7 @@ export default {
|
|||||||
// 主题切换
|
// 主题切换
|
||||||
handleThemeChange(isDark) {
|
handleThemeChange(isDark) {
|
||||||
this.isDarkMode = isDark
|
this.isDarkMode = isDark
|
||||||
if (document.body && document.body.classList) {
|
document.body.classList.toggle('dark-theme', isDark)
|
||||||
document.body.classList.toggle('dark-theme', isDark)
|
|
||||||
}
|
|
||||||
window.localStorage.setItem('isDarkMode', isDark)
|
window.localStorage.setItem('isDarkMode', isDark)
|
||||||
|
|
||||||
},
|
},
|
||||||
@@ -558,19 +552,6 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// 检查演练场是否启用
|
|
||||||
async checkPlaygroundEnabled() {
|
|
||||||
try {
|
|
||||||
const result = await playgroundApi.getStatus()
|
|
||||||
if (result && result.data) {
|
|
||||||
this.playgroundEnabled = result.data.enabled === true
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('检查演练场状态失败:', error)
|
|
||||||
this.playgroundEnabled = false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// 新增切换目录树展示模式方法
|
// 新增切换目录树展示模式方法
|
||||||
setDirectoryViewMode(mode) {
|
setDirectoryViewMode(mode) {
|
||||||
this.directoryViewMode = mode
|
this.directoryViewMode = mode
|
||||||
@@ -675,9 +656,6 @@ export default {
|
|||||||
// 获取版本号
|
// 获取版本号
|
||||||
this.getBuildVersion()
|
this.getBuildVersion()
|
||||||
|
|
||||||
// 检查演练场是否启用
|
|
||||||
this.checkPlaygroundEnabled()
|
|
||||||
|
|
||||||
// 自动读取剪切板
|
// 自动读取剪切板
|
||||||
if (this.autoReadClipboard) {
|
if (this.autoReadClipboard) {
|
||||||
this.getPaste()
|
this.getPaste()
|
||||||
|
|||||||
@@ -1,135 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="not-found-container">
|
|
||||||
<div class="not-found-content">
|
|
||||||
<div class="not-found-icon">
|
|
||||||
<el-icon :size="120"><DocumentDelete /></el-icon>
|
|
||||||
</div>
|
|
||||||
<h1 class="not-found-title">404</h1>
|
|
||||||
<p class="not-found-message">抱歉,您访问的页面不存在</p>
|
|
||||||
<div class="not-found-actions">
|
|
||||||
<el-button type="primary" @click="goHome">返回首页</el-button>
|
|
||||||
<el-button @click="goBack">返回上一页</el-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { useRouter } from 'vue-router'
|
|
||||||
import { DocumentDelete } from '@element-plus/icons-vue'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'NotFound',
|
|
||||||
components: {
|
|
||||||
DocumentDelete
|
|
||||||
},
|
|
||||||
setup() {
|
|
||||||
const router = useRouter()
|
|
||||||
|
|
||||||
const goHome = () => {
|
|
||||||
router.push('/')
|
|
||||||
}
|
|
||||||
|
|
||||||
const goBack = () => {
|
|
||||||
if (window.history.length > 1) {
|
|
||||||
router.go(-1)
|
|
||||||
} else {
|
|
||||||
router.push('/')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
goHome,
|
|
||||||
goBack
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.not-found-container {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
min-height: 100vh;
|
|
||||||
/* background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); */
|
|
||||||
padding: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.not-found-content {
|
|
||||||
text-align: center;
|
|
||||||
background: white;
|
|
||||||
padding: 60px 40px;
|
|
||||||
border-radius: 20px;
|
|
||||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
|
||||||
max-width: 500px;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.not-found-icon {
|
|
||||||
color: #909399;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.not-found-title {
|
|
||||||
font-size: 72px;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #303133;
|
|
||||||
margin: 0 0 20px 0;
|
|
||||||
line-height: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.not-found-message {
|
|
||||||
font-size: 18px;
|
|
||||||
color: #606266;
|
|
||||||
margin: 0 0 40px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.not-found-actions {
|
|
||||||
display: flex;
|
|
||||||
gap: 15px;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 暗色主题支持 */
|
|
||||||
.dark-theme .not-found-content {
|
|
||||||
background: #1d1e1f;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dark-theme .not-found-title {
|
|
||||||
color: #e5eaf3;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dark-theme .not-found-message {
|
|
||||||
color: #a3a6ad;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dark-theme .not-found-icon {
|
|
||||||
color: #6c6e72;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 移动端适配 */
|
|
||||||
@media (max-width: 768px) {
|
|
||||||
.not-found-content {
|
|
||||||
padding: 40px 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.not-found-title {
|
|
||||||
font-size: 48px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.not-found-message {
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.not-found-actions {
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.not-found-actions .el-button {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
|
|
||||||
@@ -21,26 +21,12 @@
|
|||||||
<span style="margin-left: 10px;">正在检查访问权限...</span>
|
<span style="margin-left: 10px;">正在检查访问权限...</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 演练场禁用提示 -->
|
|
||||||
<div v-if="!loading && !authChecking && !playgroundEnabled" class="playground-auth-overlay">
|
|
||||||
<div class="playground-auth-card">
|
|
||||||
<div class="auth-icon" style="color: #f56c6c;">
|
|
||||||
<el-icon :size="50"><WarningFilled /></el-icon>
|
|
||||||
</div>
|
|
||||||
<div class="auth-title">演练场功能已禁用</div>
|
|
||||||
<div class="auth-subtitle">请联系管理员启用演练场功能</div>
|
|
||||||
<el-button type="primary" size="large" @click="goHome" class="auth-button">
|
|
||||||
<span>返回首页</span>
|
|
||||||
</el-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-if="shouldShowAuthUI" class="playground-auth-overlay">
|
<div v-if="shouldShowAuthUI" class="playground-auth-overlay">
|
||||||
<div class="playground-auth-card">
|
<div class="playground-auth-card">
|
||||||
<div class="auth-icon">
|
<div class="auth-icon">
|
||||||
<el-icon :size="50"><Lock /></el-icon>
|
<el-icon :size="50"><Lock /></el-icon>
|
||||||
</div>
|
</div>
|
||||||
<div class="auth-title">脚本解析器演练场</div>
|
<div class="auth-title">JS解析器演练场</div>
|
||||||
<div class="auth-subtitle">请输入访问密码</div>
|
<div class="auth-subtitle">请输入访问密码</div>
|
||||||
<el-input
|
<el-input
|
||||||
v-model="inputPassword"
|
v-model="inputPassword"
|
||||||
@@ -70,7 +56,7 @@
|
|||||||
<template #header>
|
<template #header>
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<div class="header-left">
|
<div class="header-left">
|
||||||
<span class="title">脚本解析器演练场</span>
|
<span class="title">JS解析器演练场</span>
|
||||||
<!-- 语言显示(仅支持JavaScript) -->
|
<!-- 语言显示(仅支持JavaScript) -->
|
||||||
<span style="margin-left: 15px; color: var(--el-text-color-secondary); font-size: 12px;">
|
<span style="margin-left: 15px; color: var(--el-text-color-secondary); font-size: 12px;">
|
||||||
JavaScript (ES5)
|
JavaScript (ES5)
|
||||||
@@ -132,133 +118,8 @@
|
|||||||
<el-tabs v-model="activeTab" @tab-change="handleTabChange">
|
<el-tabs v-model="activeTab" @tab-change="handleTabChange">
|
||||||
<!-- 代码编辑标签页 -->
|
<!-- 代码编辑标签页 -->
|
||||||
<el-tab-pane label="代码编辑" name="editor">
|
<el-tab-pane label="代码编辑" name="editor">
|
||||||
<!-- 移动端:不使用 splitpanes,内容自然向下流动 -->
|
<Splitpanes :class="['default-theme', isMobile ? 'mobile-vertical' : '']" :horizontal="isMobile" @resized="handleResize">
|
||||||
<div v-if="isMobile" class="mobile-layout">
|
<!-- 编辑器区域 (PC: 左侧, Mobile: 上方) -->
|
||||||
<!-- 编辑器区域 -->
|
|
||||||
<div class="editor-section">
|
|
||||||
<MonacoEditor
|
|
||||||
ref="editorRef"
|
|
||||||
v-model="jsCode"
|
|
||||||
:theme="editorTheme"
|
|
||||||
:height="'400px'"
|
|
||||||
:options="editorOptions"
|
|
||||||
@change="onCodeChange"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 测试参数和结果区域 -->
|
|
||||||
<div v-if="!collapsedPanels.rightPanel" class="test-section mobile-test-section">
|
|
||||||
<!-- 测试参数 -->
|
|
||||||
<el-card class="test-params-card collapsible-card" shadow="never" style="margin-top: 12px">
|
|
||||||
<template #header>
|
|
||||||
<div class="card-header-with-collapse">
|
|
||||||
<span>测试参数</span>
|
|
||||||
<el-button
|
|
||||||
text
|
|
||||||
size="small"
|
|
||||||
:icon="collapsedPanels.testParams ? 'ArrowDown' : 'ArrowUp'"
|
|
||||||
@click="togglePanel('testParams')"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<transition name="collapse">
|
|
||||||
<div v-show="!collapsedPanels.testParams">
|
|
||||||
<el-form :model="testParams" label-width="0px" size="small" class="test-params-form">
|
|
||||||
<el-form-item label="" class="share-url-item">
|
|
||||||
<el-input
|
|
||||||
v-model="testParams.shareUrl"
|
|
||||||
placeholder="请输入分享链接"
|
|
||||||
clearable
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="" class="password-item">
|
|
||||||
<el-input
|
|
||||||
v-model="testParams.pwd"
|
|
||||||
placeholder="密码(可选)"
|
|
||||||
clearable
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="" class="method-item-horizontal">
|
|
||||||
<el-radio-group v-model="testParams.method" size="small">
|
|
||||||
<el-radio label="parse">parse</el-radio>
|
|
||||||
<el-radio label="parseFileList">parseFileList</el-radio>
|
|
||||||
</el-radio-group>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item class="button-item">
|
|
||||||
<el-button
|
|
||||||
type="primary"
|
|
||||||
:loading="testing"
|
|
||||||
@click="executeTest"
|
|
||||||
style="width: 100%"
|
|
||||||
>
|
|
||||||
执行测试
|
|
||||||
</el-button>
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
|
||||||
</div>
|
|
||||||
</transition>
|
|
||||||
</el-card>
|
|
||||||
|
|
||||||
<!-- 执行结果 -->
|
|
||||||
<el-card class="result-card collapsible-card" shadow="never" style="margin-top: 10px">
|
|
||||||
<template #header>
|
|
||||||
<div class="card-header-with-collapse">
|
|
||||||
<span>执行结果</span>
|
|
||||||
<el-button
|
|
||||||
text
|
|
||||||
size="small"
|
|
||||||
:icon="collapsedPanels.testResult ? 'ArrowDown' : 'ArrowUp'"
|
|
||||||
@click="togglePanel('testResult')"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<transition name="collapse">
|
|
||||||
<div v-show="!collapsedPanels.testResult">
|
|
||||||
<div v-if="testResult" class="result-content">
|
|
||||||
<el-alert
|
|
||||||
:type="testResult.success ? 'success' : 'error'"
|
|
||||||
:title="testResult.success ? '执行成功' : '执行失败'"
|
|
||||||
:closable="false"
|
|
||||||
style="margin-bottom: 10px"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div v-if="testResult.success" class="result-section">
|
|
||||||
<div class="section-title">结果数据:</div>
|
|
||||||
<div v-if="testResult.result" class="result-debug-box">
|
|
||||||
<strong>结果内容:</strong>{{ testResult.result }}
|
|
||||||
</div>
|
|
||||||
<JsonViewer :value="testResult.result" :expand-depth="3" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-if="testResult.error" class="result-section">
|
|
||||||
<div class="section-title">错误信息:</div>
|
|
||||||
<el-alert type="error" :title="testResult.error" :closable="false" />
|
|
||||||
<div v-if="testResult.stackTrace" class="stack-trace">
|
|
||||||
<el-collapse>
|
|
||||||
<el-collapse-item title="查看堆栈信息" name="stack">
|
|
||||||
<pre>{{ testResult.stackTrace }}</pre>
|
|
||||||
</el-collapse-item>
|
|
||||||
</el-collapse>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-if="testResult.executionTime" class="result-section">
|
|
||||||
<div class="section-title">执行时间:</div>
|
|
||||||
<div>{{ testResult.executionTime }}ms</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div v-else class="empty-result">
|
|
||||||
<el-empty description="暂无执行结果" :image-size="80" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</transition>
|
|
||||||
</el-card>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 桌面端:使用 splitpanes -->
|
|
||||||
<Splitpanes v-else class="default-theme" @resized="handleResize">
|
|
||||||
<!-- 编辑器区域 (左侧) -->
|
|
||||||
<Pane :size="collapsedPanels.rightPanel ? 100 : splitSizes[0]" min-size="30" class="editor-pane">
|
<Pane :size="collapsedPanels.rightPanel ? 100 : splitSizes[0]" min-size="30" class="editor-pane">
|
||||||
<div class="editor-section">
|
<div class="editor-section">
|
||||||
<MonacoEditor
|
<MonacoEditor
|
||||||
@@ -272,9 +133,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</Pane>
|
</Pane>
|
||||||
|
|
||||||
<!-- 测试参数和结果区域 (右侧) -->
|
<!-- 测试参数和结果区域 (PC: 右侧, Mobile: 下方) -->
|
||||||
<Pane v-if="!collapsedPanels.rightPanel"
|
<Pane v-if="!collapsedPanels.rightPanel"
|
||||||
:size="splitSizes[1]" min-size="20" class="test-pane" style="margin-left: 10px;">
|
:size="splitSizes[1]" min-size="20" class="test-pane" :style="isMobile ? 'margin-top: 10px;' : 'margin-left: 10px;'">
|
||||||
<div class="test-section">
|
<div class="test-section">
|
||||||
<!-- 优化的折叠按钮 -->
|
<!-- 优化的折叠按钮 -->
|
||||||
<el-tooltip content="折叠测试面板" placement="left">
|
<el-tooltip content="折叠测试面板" placement="left">
|
||||||
@@ -470,7 +331,7 @@
|
|||||||
<transition name="collapse">
|
<transition name="collapse">
|
||||||
<div v-show="!collapsedPanels.help">
|
<div v-show="!collapsedPanels.help">
|
||||||
<div class="help-content">
|
<div class="help-content">
|
||||||
<h3>什么是脚本解析器演练场?</h3>
|
<h3>什么是JS解析器演练场?</h3>
|
||||||
<p>演练场允许您快速编写、测试和发布JavaScript解析脚本,无需重启服务器即可调试和验证解析逻辑。</p>
|
<p>演练场允许您快速编写、测试和发布JavaScript解析脚本,无需重启服务器即可调试和验证解析逻辑。</p>
|
||||||
|
|
||||||
<h3>快速开始</h3>
|
<h3>快速开始</h3>
|
||||||
@@ -598,7 +459,7 @@
|
|||||||
</el-tag>
|
</el-tag>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="操作" width="120" fixed="right">
|
<el-table-column label="操作" width="200" fixed="right">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-button size="small" @click="loadParserToEditor(scope.row)">编辑</el-button>
|
<el-button size="small" @click="loadParserToEditor(scope.row)">编辑</el-button>
|
||||||
<el-button size="small" type="danger" @click="deleteParser(scope.row.id)">删除</el-button>
|
<el-button size="small" type="danger" @click="deleteParser(scope.row.id)">删除</el-button>
|
||||||
@@ -611,33 +472,26 @@
|
|||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<!-- 发布对话框 -->
|
<!-- 发布对话框 -->
|
||||||
<el-dialog
|
<!-- 发布对话框 -->
|
||||||
v-model="publishDialogVisible"
|
<el-dialog v-model="publishDialogVisible" title="发布解析器" width="600px">
|
||||||
title="发布解析器"
|
<el-form :model="publishForm" label-width="100px">
|
||||||
:width="isMobile ? '90%' : '600px'"
|
|
||||||
:close-on-click-modal="false"
|
|
||||||
class="publish-dialog"
|
|
||||||
>
|
|
||||||
<el-form :model="publishForm" :label-width="isMobile ? '80px' : '100px'">
|
|
||||||
<el-form-item label="脚本代码">
|
<el-form-item label="脚本代码">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="publishForm.jsCode"
|
v-model="publishForm.jsCode"
|
||||||
type="textarea"
|
type="textarea"
|
||||||
:rows="isMobile ? 8 : 10"
|
:rows="10"
|
||||||
readonly
|
readonly
|
||||||
class="publish-code-textarea"
|
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-alert
|
<el-alert
|
||||||
type="warning"
|
type="warning"
|
||||||
:closable="false"
|
:closable="false"
|
||||||
style="margin-bottom: 20px"
|
style="margin-bottom: 20px"
|
||||||
class="publish-alert"
|
|
||||||
>
|
>
|
||||||
<template #title>
|
<template #title>
|
||||||
<div class="publish-checklist">
|
<div>
|
||||||
<p style="margin-bottom: 8px; font-weight: 500;">发布前请确保:</p>
|
<p>发布前请确保:</p>
|
||||||
<ul style="margin: 0; padding-left: 20px;">
|
<ul>
|
||||||
<li>脚本已通过测试</li>
|
<li>脚本已通过测试</li>
|
||||||
<li>元数据信息完整(@name, @type, @displayName, @match)</li>
|
<li>元数据信息完整(@name, @type, @displayName, @match)</li>
|
||||||
<li>类型标识(@type)唯一,不与现有解析器冲突</li>
|
<li>类型标识(@type)唯一,不与现有解析器冲突</li>
|
||||||
@@ -648,32 +502,25 @@
|
|||||||
</el-alert>
|
</el-alert>
|
||||||
</el-form>
|
</el-form>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<div class="dialog-footer-mobile">
|
<el-button @click="publishDialogVisible = false">取消</el-button>
|
||||||
<el-button @click="publishDialogVisible = false" :size="isMobile ? 'default' : 'default'">取消</el-button>
|
<el-button type="primary" :loading="publishing" @click="confirmPublish">确认发布</el-button>
|
||||||
<el-button type="primary" :loading="publishing" @click="confirmPublish" :size="isMobile ? 'default' : 'default'">确认发布</el-button>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
<!-- 快捷键帮助对话框 -->
|
<!-- 快捷键帮助对话框 -->
|
||||||
<el-dialog
|
<el-dialog v-model="shortcutsDialogVisible" title="⌨️ 快捷键" width="500px">
|
||||||
v-model="shortcutsDialogVisible"
|
<el-table :data="shortcutsData" style="width: 100%" :show-header="false">
|
||||||
title="⌨️ 快捷键"
|
<el-table-column prop="name" label="功能" width="200" />
|
||||||
:width="isMobile ? '90%' : '500px'"
|
|
||||||
class="shortcuts-dialog"
|
|
||||||
>
|
|
||||||
<el-table :data="shortcutsData" style="width: 100%" :show-header="false" class="shortcuts-table">
|
|
||||||
<el-table-column prop="name" label="功能" :width="isMobile ? 120 : 200" />
|
|
||||||
<el-table-column prop="keys" label="快捷键">
|
<el-table-column prop="keys" label="快捷键">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-tag v-for="key in row.keys" :key="key" size="small" style="margin-right: 5px; margin-bottom: 4px;">
|
<el-tag v-for="key in row.keys" :key="key" size="small" style="margin-right: 5px;">
|
||||||
{{ key }}
|
{{ key }}
|
||||||
</el-tag>
|
</el-tag>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<el-button type="primary" @click="shortcutsDialogVisible = false" :size="isMobile ? 'default' : 'default'">知道了</el-button>
|
<el-button type="primary" @click="shortcutsDialogVisible = false">知道了</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
@@ -683,7 +530,6 @@
|
|||||||
import { ref, computed, onMounted, onUnmounted, nextTick, watch } from 'vue';
|
import { ref, computed, onMounted, onUnmounted, nextTick, watch } from 'vue';
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||||
import { useMagicKeys, useFullscreen, useEventListener } from '@vueuse/core';
|
import { useMagicKeys, useFullscreen, useEventListener } from '@vueuse/core';
|
||||||
import { useRouter } from 'vue-router';
|
|
||||||
import { Splitpanes, Pane } from 'splitpanes';
|
import { Splitpanes, Pane } from 'splitpanes';
|
||||||
import 'splitpanes/dist/splitpanes.css';
|
import 'splitpanes/dist/splitpanes.css';
|
||||||
import MonacoEditor from '@/components/MonacoEditor.vue';
|
import MonacoEditor from '@/components/MonacoEditor.vue';
|
||||||
@@ -700,8 +546,6 @@ export default {
|
|||||||
Pane
|
Pane
|
||||||
},
|
},
|
||||||
setup() {
|
setup() {
|
||||||
const router = useRouter();
|
|
||||||
|
|
||||||
// 语言常量
|
// 语言常量
|
||||||
const LANGUAGE = {
|
const LANGUAGE = {
|
||||||
JAVASCRIPT: 'JavaScript'
|
JAVASCRIPT: 'JavaScript'
|
||||||
@@ -719,13 +563,12 @@ export default {
|
|||||||
const inputPassword = ref('');
|
const inputPassword = ref('');
|
||||||
const authError = ref('');
|
const authError = ref('');
|
||||||
const authLoading = ref(false);
|
const authLoading = ref(false);
|
||||||
const playgroundEnabled = ref(true); // 演练场是否启用
|
|
||||||
|
|
||||||
// ===== 移动端检测 =====
|
// ===== 移动端检测 =====
|
||||||
const isMobile = ref(false);
|
const isMobile = ref(false);
|
||||||
|
|
||||||
const testParams = ref({
|
const testParams = ref({
|
||||||
shareUrl: 'https://example.com/s/abc',
|
shareUrl: 'https://lanzoui.com/i7Aq12ab3cd',
|
||||||
pwd: '',
|
pwd: '',
|
||||||
method: 'parse'
|
method: 'parse'
|
||||||
});
|
});
|
||||||
@@ -788,7 +631,7 @@ export default {
|
|||||||
// @type example_parser
|
// @type example_parser
|
||||||
// @displayName 示例网盘
|
// @displayName 示例网盘
|
||||||
// @description 使用JavaScript实现的示例解析器
|
// @description 使用JavaScript实现的示例解析器
|
||||||
// @match https?://example\.com/s/(?<KEY>\\w+)
|
// @match https?://example\.com/s/(?<KEY>\w+)
|
||||||
// @author yourname
|
// @author yourname
|
||||||
// @version 1.0.0
|
// @version 1.0.0
|
||||||
// ==/UserScript==
|
// ==/UserScript==
|
||||||
@@ -804,7 +647,7 @@ function parse(shareLinkInfo, http, logger) {
|
|||||||
var url = shareLinkInfo.getShareUrl();
|
var url = shareLinkInfo.getShareUrl();
|
||||||
logger.info("开始解析: " + url);
|
logger.info("开始解析: " + url);
|
||||||
|
|
||||||
var response = http.get('https://example.com');
|
var response = http.get(url);
|
||||||
if (!response.isSuccess()) {
|
if (!response.isSuccess()) {
|
||||||
throw new Error("请求失败: " + response.statusCode());
|
throw new Error("请求失败: " + response.statusCode());
|
||||||
}
|
}
|
||||||
@@ -857,7 +700,7 @@ function parseById(shareLinkInfo, http, logger) {
|
|||||||
|
|
||||||
// 计算属性:是否需要显示密码输入界面
|
// 计算属性:是否需要显示密码输入界面
|
||||||
const shouldShowAuthUI = computed(() => {
|
const shouldShowAuthUI = computed(() => {
|
||||||
return !loading.value && !authChecking.value && !authed.value && playgroundEnabled.value;
|
return !loading.value && !authChecking.value && !authed.value;
|
||||||
});
|
});
|
||||||
|
|
||||||
// 编辑器配置
|
// 编辑器配置
|
||||||
@@ -873,14 +716,7 @@ function parseById(shareLinkInfo, http, logger) {
|
|||||||
|
|
||||||
// ===== 移动端检测 =====
|
// ===== 移动端检测 =====
|
||||||
const updateIsMobile = () => {
|
const updateIsMobile = () => {
|
||||||
const wasMobile = isMobile.value;
|
|
||||||
isMobile.value = window.innerWidth <= 768;
|
isMobile.value = window.innerWidth <= 768;
|
||||||
// 如果是移动端,调整分栏大小,让测试面板有更多空间
|
|
||||||
if (isMobile.value && !wasMobile) {
|
|
||||||
splitSizes.value = [50, 50]; // 移动端:编辑器50%,测试面板50%
|
|
||||||
} else if (!isMobile.value && wasMobile) {
|
|
||||||
splitSizes.value = [70, 30]; // 桌面端:编辑器70%,测试面板30%
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// ===== 进度设置函数 =====
|
// ===== 进度设置函数 =====
|
||||||
@@ -898,59 +734,19 @@ function parseById(shareLinkInfo, http, logger) {
|
|||||||
try {
|
try {
|
||||||
const res = await playgroundApi.getStatus();
|
const res = await playgroundApi.getStatus();
|
||||||
if (res.code === 200 && res.data) {
|
if (res.code === 200 && res.data) {
|
||||||
// 检查是否启用
|
authed.value = res.data.authed || res.data.public;
|
||||||
playgroundEnabled.value = res.data.enabled === true;
|
return res.data.authed || res.data.public;
|
||||||
|
|
||||||
if (!playgroundEnabled.value) {
|
|
||||||
authChecking.value = false;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 先检查localStorage中是否有保存的登录信息
|
|
||||||
const savedAuth = localStorage.getItem('playground_authed');
|
|
||||||
const authTime = localStorage.getItem('playground_auth_time');
|
|
||||||
|
|
||||||
// 如果30天内登录过,直接认为已认证(实际认证状态由后端session决定)
|
|
||||||
if (savedAuth === 'true' && authTime) {
|
|
||||||
const daysSinceAuth = (Date.now() - parseInt(authTime)) / (1000 * 60 * 60 * 24);
|
|
||||||
if (daysSinceAuth < 30) {
|
|
||||||
// 先设置为已认证,然后验证后端session
|
|
||||||
authed.value = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const isAuthed = res.data.authed || res.data.public;
|
|
||||||
authed.value = isAuthed;
|
|
||||||
|
|
||||||
// 如果后端session已失效,清除localStorage
|
|
||||||
if (!isAuthed && savedAuth === 'true') {
|
|
||||||
localStorage.removeItem('playground_authed');
|
|
||||||
localStorage.removeItem('playground_auth_time');
|
|
||||||
}
|
|
||||||
|
|
||||||
return isAuthed;
|
|
||||||
}
|
}
|
||||||
playgroundEnabled.value = false;
|
|
||||||
return false;
|
return false;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('检查认证状态失败:', error);
|
console.error('检查认证状态失败:', error);
|
||||||
// 如果错误信息包含"已禁用",则设置启用状态为false
|
ElMessage.error('检查访问权限失败: ' + error.message);
|
||||||
if (error.message && error.message.includes('已禁用')) {
|
|
||||||
playgroundEnabled.value = false;
|
|
||||||
} else {
|
|
||||||
ElMessage.error('检查访问权限失败: ' + error.message);
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
} finally {
|
} finally {
|
||||||
authChecking.value = false;
|
authChecking.value = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 返回首页
|
|
||||||
const goHome = () => {
|
|
||||||
router.push('/');
|
|
||||||
};
|
|
||||||
|
|
||||||
const submitPassword = async () => {
|
const submitPassword = async () => {
|
||||||
if (!inputPassword.value.trim()) {
|
if (!inputPassword.value.trim()) {
|
||||||
authError.value = '请输入密码';
|
authError.value = '请输入密码';
|
||||||
@@ -964,9 +760,6 @@ function parseById(shareLinkInfo, http, logger) {
|
|||||||
const res = await playgroundApi.login(inputPassword.value);
|
const res = await playgroundApi.login(inputPassword.value);
|
||||||
if (res.code === 200 || res.success) {
|
if (res.code === 200 || res.success) {
|
||||||
authed.value = true;
|
authed.value = true;
|
||||||
// 保存登录信息到localStorage,避免每次都需要登录
|
|
||||||
localStorage.setItem('playground_authed', 'true');
|
|
||||||
localStorage.setItem('playground_auth_time', Date.now().toString());
|
|
||||||
ElMessage.success('登录成功');
|
ElMessage.success('登录成功');
|
||||||
await initPlayground();
|
await initPlayground();
|
||||||
} else {
|
} else {
|
||||||
@@ -994,11 +787,7 @@ function parseById(shareLinkInfo, http, logger) {
|
|||||||
if (saved) {
|
if (saved) {
|
||||||
jsCode.value = saved;
|
jsCode.value = saved;
|
||||||
} else {
|
} else {
|
||||||
// 默认加载示例代码和示例参数
|
|
||||||
jsCode.value = exampleCode;
|
jsCode.value = exampleCode;
|
||||||
testParams.value.shareUrl = 'https://example.com/s/abc';
|
|
||||||
testParams.value.pwd = '';
|
|
||||||
testParams.value.method = 'parse';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setProgress(50, '初始化Monaco Editor类型定义...');
|
setProgress(50, '初始化Monaco Editor类型定义...');
|
||||||
@@ -1011,20 +800,16 @@ function parseById(shareLinkInfo, http, logger) {
|
|||||||
if (savedTheme) {
|
if (savedTheme) {
|
||||||
currentTheme.value = savedTheme;
|
currentTheme.value = savedTheme;
|
||||||
const theme = themes.find(t => t.name === savedTheme);
|
const theme = themes.find(t => t.name === savedTheme);
|
||||||
if (theme) {
|
if (theme && document.documentElement && document.body) {
|
||||||
await nextTick();
|
await nextTick();
|
||||||
const html = document.documentElement;
|
if (theme.page === 'dark') {
|
||||||
const body = document.body;
|
document.documentElement.classList.add('dark');
|
||||||
if (html && body && html.classList && body.classList) {
|
document.body.classList.add('dark-theme');
|
||||||
if (theme.page === 'dark') {
|
document.body.style.backgroundColor = '#0a0a0a';
|
||||||
html.classList.add('dark');
|
} else {
|
||||||
body.classList.add('dark-theme');
|
document.documentElement.classList.remove('dark');
|
||||||
body.style.backgroundColor = '#0a0a0a';
|
document.body.classList.remove('dark-theme');
|
||||||
} else {
|
document.body.style.backgroundColor = '#f0f2f5';
|
||||||
html.classList.remove('dark');
|
|
||||||
body.classList.remove('dark-theme');
|
|
||||||
body.style.backgroundColor = '#f0f2f5';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1062,13 +847,6 @@ function parseById(shareLinkInfo, http, logger) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 配置Monaco Editor使用国内CDN (npmmirror)
|
|
||||||
loader.config({
|
|
||||||
paths: {
|
|
||||||
vs: 'https://registry.npmmirror.com/monaco-editor/0.55.1/files/min/vs'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const monaco = await loader.init();
|
const monaco = await loader.init();
|
||||||
if (monaco) {
|
if (monaco) {
|
||||||
await configureMonacoTypes(monaco);
|
await configureMonacoTypes(monaco);
|
||||||
@@ -1089,13 +867,6 @@ function parseById(shareLinkInfo, http, logger) {
|
|||||||
// 加载示例代码
|
// 加载示例代码
|
||||||
const loadTemplate = () => {
|
const loadTemplate = () => {
|
||||||
jsCode.value = exampleCode;
|
jsCode.value = exampleCode;
|
||||||
// 重置测试参数为示例链接
|
|
||||||
testParams.value.shareUrl = 'https://example.com/s/abc';
|
|
||||||
testParams.value.pwd = '';
|
|
||||||
testParams.value.method = 'parse';
|
|
||||||
// 清空测试结果
|
|
||||||
testResult.value = null;
|
|
||||||
consoleLogs.value = [];
|
|
||||||
ElMessage.success('已加载JavaScript示例代码');
|
ElMessage.success('已加载JavaScript示例代码');
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1412,7 +1183,7 @@ curl "${baseUrl}/json/parser?url=${encodeURIComponent(exampleUrl)}"</pre>
|
|||||||
const html = document.documentElement;
|
const html = document.documentElement;
|
||||||
const body = document.body;
|
const body = document.body;
|
||||||
|
|
||||||
if (html && body && html.classList && body.classList) {
|
if (html && body) {
|
||||||
if (theme.page === 'dark') {
|
if (theme.page === 'dark') {
|
||||||
html.classList.add('dark');
|
html.classList.add('dark');
|
||||||
body.classList.add('dark-theme');
|
body.classList.add('dark-theme');
|
||||||
@@ -1557,13 +1328,8 @@ curl "${baseUrl}/json/parser?url=${encodeURIComponent(exampleUrl)}"</pre>
|
|||||||
const checkDarkMode = () => {
|
const checkDarkMode = () => {
|
||||||
try {
|
try {
|
||||||
const html = document.documentElement;
|
const html = document.documentElement;
|
||||||
const body = document.body;
|
if (html) {
|
||||||
if (!html || !body) {
|
isDarkMode.value = html.classList?.contains('dark') ||
|
||||||
return; // DOM未准备好,直接返回
|
|
||||||
}
|
|
||||||
|
|
||||||
if (html.classList) {
|
|
||||||
isDarkMode.value = html.classList.contains('dark') ||
|
|
||||||
html.getAttribute('data-theme') === 'dark';
|
html.getAttribute('data-theme') === 'dark';
|
||||||
// 强制更新splitpanes分隔线样式
|
// 强制更新splitpanes分隔线样式
|
||||||
updateSplitpanesStyle();
|
updateSplitpanesStyle();
|
||||||
@@ -1576,31 +1342,19 @@ curl "${baseUrl}/json/parser?url=${encodeURIComponent(exampleUrl)}"</pre>
|
|||||||
// 强制更新splitpanes分隔线样式
|
// 强制更新splitpanes分隔线样式
|
||||||
const updateSplitpanesStyle = () => {
|
const updateSplitpanesStyle = () => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
try {
|
const splitters = document.querySelectorAll('.splitpanes__splitter');
|
||||||
const html = document.documentElement;
|
const isDark = document.documentElement?.classList?.contains('dark') ||
|
||||||
const body = document.body;
|
document.body?.classList?.contains('dark-theme');
|
||||||
if (!html || !body) {
|
|
||||||
return; // DOM未准备好,直接返回
|
splitters.forEach(splitter => {
|
||||||
|
if (isDark) {
|
||||||
|
splitter.style.setProperty('background-color', 'rgba(255, 255, 255, 0.08)', 'important');
|
||||||
|
splitter.style.setProperty('background', 'rgba(255, 255, 255, 0.08)', 'important');
|
||||||
|
} else {
|
||||||
|
splitter.style.removeProperty('background-color');
|
||||||
|
splitter.style.removeProperty('background');
|
||||||
}
|
}
|
||||||
|
});
|
||||||
const splitters = document.querySelectorAll('.splitpanes__splitter');
|
|
||||||
const isDark = html.classList?.contains('dark') ||
|
|
||||||
body.classList?.contains('dark-theme');
|
|
||||||
|
|
||||||
splitters.forEach(splitter => {
|
|
||||||
if (splitter) {
|
|
||||||
if (isDark) {
|
|
||||||
splitter.style.setProperty('background-color', 'rgba(255, 255, 255, 0.08)', 'important');
|
|
||||||
splitter.style.setProperty('background', 'rgba(255, 255, 255, 0.08)', 'important');
|
|
||||||
} else {
|
|
||||||
splitter.style.removeProperty('background-color');
|
|
||||||
splitter.style.removeProperty('background');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
console.warn('更新splitpanes样式失败:', error);
|
|
||||||
}
|
|
||||||
}, 100);
|
}, 100);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1624,19 +1378,14 @@ curl "${baseUrl}/json/parser?url=${encodeURIComponent(exampleUrl)}"</pre>
|
|||||||
checkDarkMode();
|
checkDarkMode();
|
||||||
|
|
||||||
// 监听主题变化
|
// 监听主题变化
|
||||||
const html = document.documentElement;
|
if (document.documentElement) {
|
||||||
if (html && html.classList) {
|
const observer = new MutationObserver(() => {
|
||||||
try {
|
checkDarkMode();
|
||||||
const observer = new MutationObserver(() => {
|
});
|
||||||
checkDarkMode();
|
observer.observe(document.documentElement, {
|
||||||
});
|
attributes: true,
|
||||||
observer.observe(html, {
|
attributeFilter: ['class', 'data-theme']
|
||||||
attributes: true,
|
});
|
||||||
attributeFilter: ['class', 'data-theme']
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
console.warn('创建主题监听器失败:', error);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 初始化splitpanes样式
|
// 初始化splitpanes样式
|
||||||
@@ -1667,10 +1416,8 @@ curl "${baseUrl}/json/parser?url=${encodeURIComponent(exampleUrl)}"</pre>
|
|||||||
inputPassword,
|
inputPassword,
|
||||||
authError,
|
authError,
|
||||||
authLoading,
|
authLoading,
|
||||||
playgroundEnabled,
|
|
||||||
checkAuthStatus,
|
checkAuthStatus,
|
||||||
submitPassword,
|
submitPassword,
|
||||||
goHome,
|
|
||||||
// 移动端
|
// 移动端
|
||||||
isMobile,
|
isMobile,
|
||||||
updateIsMobile,
|
updateIsMobile,
|
||||||
@@ -2694,6 +2441,7 @@ html.dark .playground-container .splitpanes__splitter:hover {
|
|||||||
background-color: #fafafa;
|
background-color: #fafafa;
|
||||||
font-family: 'Monaco', 'Menlo', 'Courier New', monospace;
|
font-family: 'Monaco', 'Menlo', 'Courier New', monospace;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
|
min-height: 250px;
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2888,28 +2636,26 @@ html.dark .playground-container .splitpanes__splitter:hover {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ===== 响应式布局 ===== */
|
/* ===== 响应式布局 ===== */
|
||||||
/* 移动端布局:内容自然向下流动 */
|
/* 移动端纵向布局 */
|
||||||
.mobile-layout {
|
.playground-container.is-mobile .splitpanes.mobile-vertical {
|
||||||
display: flex;
|
flex-direction: column !important;
|
||||||
flex-direction: column;
|
|
||||||
width: 100%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.mobile-layout .editor-section {
|
.playground-container.is-mobile .splitpanes--horizontal > .splitpanes__splitter {
|
||||||
|
height: 6px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-bottom: 12px;
|
cursor: row-resize;
|
||||||
|
margin: 5px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mobile-test-section {
|
.playground-container.is-mobile .editor-pane,
|
||||||
width: 100%;
|
.playground-container.is-mobile .test-pane {
|
||||||
height: auto !important;
|
width: 100% !important;
|
||||||
overflow-y: visible !important;
|
|
||||||
padding: 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.mobile-test-section .test-params-card,
|
.playground-container.is-mobile .test-pane {
|
||||||
.mobile-test-section .result-card {
|
margin-left: 0 !important;
|
||||||
margin-bottom: 12px;
|
margin-top: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.playground-container.is-mobile .playground-loading-card {
|
.playground-container.is-mobile .playground-loading-card {
|
||||||
@@ -2934,11 +2680,7 @@ html.dark .playground-container .splitpanes__splitter:hover {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.console-container {
|
.console-container {
|
||||||
max-height: 250px;
|
max-height: 200px;
|
||||||
}
|
|
||||||
|
|
||||||
.empty-console {
|
|
||||||
padding: 20px 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2953,26 +2695,15 @@ html.dark .playground-container .splitpanes__splitter:hover {
|
|||||||
gap: 10px;
|
gap: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.console-container {
|
|
||||||
max-height: 300px;
|
|
||||||
padding: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.empty-console {
|
|
||||||
padding: 12px 0;
|
|
||||||
font-size: 13px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.console-entry {
|
|
||||||
font-size: 12px;
|
|
||||||
padding: 6px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header-actions {
|
.header-actions {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.test-section {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
.panel-expand-btn {
|
.panel-expand-btn {
|
||||||
right: 10px;
|
right: 10px;
|
||||||
}
|
}
|
||||||
@@ -2982,70 +2713,9 @@ html.dark .playground-container .splitpanes__splitter:hover {
|
|||||||
gap: 8px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 移动端结果区域自适应高度 */
|
.splitpanes {
|
||||||
.result-content {
|
|
||||||
max-height: none !important;
|
|
||||||
overflow-y: visible !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 移动端测试区域不使用固定高度 */
|
|
||||||
.test-section {
|
|
||||||
height: auto !important;
|
|
||||||
overflow-y: visible !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 移动端对话框样式 */
|
|
||||||
.publish-dialog :deep(.el-dialog) {
|
|
||||||
margin: 5vh auto !important;
|
|
||||||
max-height: 90vh;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
.publish-dialog :deep(.el-dialog__body) {
|
|
||||||
flex: 1;
|
|
||||||
overflow-y: auto;
|
|
||||||
padding: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.publish-code-textarea :deep(.el-textarea__inner) {
|
|
||||||
font-size: 12px;
|
|
||||||
font-family: 'Monaco', 'Menlo', 'Courier New', monospace;
|
|
||||||
}
|
|
||||||
|
|
||||||
.publish-checklist {
|
|
||||||
font-size: 13px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.publish-checklist ul {
|
|
||||||
line-height: 1.8;
|
|
||||||
}
|
|
||||||
|
|
||||||
.publish-checklist li {
|
|
||||||
margin-bottom: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dialog-footer-mobile {
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-end;
|
|
||||||
gap: 10px;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.shortcuts-dialog :deep(.el-dialog) {
|
|
||||||
margin: 5vh auto !important;
|
|
||||||
max-height: 90vh;
|
|
||||||
}
|
|
||||||
|
|
||||||
.shortcuts-dialog :deep(.el-dialog__body) {
|
|
||||||
padding: 15px;
|
|
||||||
max-height: calc(90vh - 120px);
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.shortcuts-table :deep(.el-table__body) {
|
|
||||||
font-size: 13px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ===== 改进的滚动条样式 ===== */
|
/* ===== 改进的滚动条样式 ===== */
|
||||||
|
|||||||
@@ -61,16 +61,12 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
toggleTheme(isDark) {
|
toggleTheme(isDark) {
|
||||||
const html = document.documentElement;
|
if (isDark) {
|
||||||
const body = document.body;
|
document.body.classList.add('dark-theme')
|
||||||
if (html && body && html.classList && body.classList) {
|
document.documentElement.classList.add('dark-theme')
|
||||||
if (isDark) {
|
} else {
|
||||||
body.classList.add('dark-theme')
|
document.body.classList.remove('dark-theme')
|
||||||
html.classList.add('dark-theme')
|
document.documentElement.classList.remove('dark-theme')
|
||||||
} else {
|
|
||||||
body.classList.remove('dark-theme')
|
|
||||||
html.classList.remove('dark-theme')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ module.exports = {
|
|||||||
'@': resolve('src')
|
'@': resolve('src')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// Monaco Editor配置 - 使用国内CDN
|
// Monaco Editor配置
|
||||||
module: {
|
module: {
|
||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -122,23 +122,13 @@ public class AppMain {
|
|||||||
if (parser.getBoolean("enabled", false)) {
|
if (parser.getBoolean("enabled", false)) {
|
||||||
try {
|
try {
|
||||||
String jsCode = parser.getString("jsCode");
|
String jsCode = parser.getString("jsCode");
|
||||||
if (jsCode == null || jsCode.trim().isEmpty()) {
|
|
||||||
log.error("加载演练场解析器失败: {} - JavaScript代码为空", parser.getString("name"));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
CustomParserConfig config = JsScriptMetadataParser.parseScript(jsCode);
|
CustomParserConfig config = JsScriptMetadataParser.parseScript(jsCode);
|
||||||
CustomParserRegistry.register(config);
|
CustomParserRegistry.register(config);
|
||||||
loadedCount++;
|
loadedCount++;
|
||||||
log.info("已加载演练场解析器: {} ({})",
|
log.info("已加载演练场解析器: {} ({})",
|
||||||
config.getDisplayName(), config.getType());
|
config.getDisplayName(), config.getType());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
String parserName = parser.getString("name");
|
log.error("加载演练场解析器失败: {}", parser.getString("name"), e);
|
||||||
String errorMsg = e.getMessage();
|
|
||||||
log.error("加载演练场解析器失败: {} - {}", parserName, errorMsg, e);
|
|
||||||
// 如果是require相关错误,提供更详细的提示
|
|
||||||
if (errorMsg != null && errorMsg.contains("require")) {
|
|
||||||
log.error("提示:演练场解析器不支持CommonJS模块系统(require),请确保代码使用ES5.1语法");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,12 +18,6 @@ public class PlaygroundConfig {
|
|||||||
*/
|
*/
|
||||||
private static PlaygroundConfig instance;
|
private static PlaygroundConfig instance;
|
||||||
|
|
||||||
/**
|
|
||||||
* 是否启用演练场
|
|
||||||
* 默认false,不启用
|
|
||||||
*/
|
|
||||||
private boolean enabled = false;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否公开模式(不需要密码)
|
* 是否公开模式(不需要密码)
|
||||||
* 默认false,需要密码访问
|
* 默认false,需要密码访问
|
||||||
@@ -63,20 +57,17 @@ public class PlaygroundConfig {
|
|||||||
PlaygroundConfig cfg = getInstance();
|
PlaygroundConfig cfg = getInstance();
|
||||||
if (config != null && config.containsKey("playground")) {
|
if (config != null && config.containsKey("playground")) {
|
||||||
JsonObject playgroundConfig = config.getJsonObject("playground");
|
JsonObject playgroundConfig = config.getJsonObject("playground");
|
||||||
cfg.enabled = playgroundConfig.getBoolean("enabled", false);
|
|
||||||
cfg.isPublic = playgroundConfig.getBoolean("public", false);
|
cfg.isPublic = playgroundConfig.getBoolean("public", false);
|
||||||
cfg.password = playgroundConfig.getString("password", "nfd_playground_2024");
|
cfg.password = playgroundConfig.getString("password", "nfd_playground_2024");
|
||||||
|
|
||||||
log.info("Playground配置已加载: enabled={}, public={}, password={}",
|
log.info("Playground配置已加载: public={}, password={}",
|
||||||
cfg.enabled, cfg.isPublic, cfg.isPublic ? "N/A" : "已设置");
|
cfg.isPublic, cfg.isPublic ? "N/A" : "已设置");
|
||||||
|
|
||||||
if (!cfg.enabled) {
|
if (!cfg.isPublic && "nfd_playground_2024".equals(cfg.password)) {
|
||||||
log.info("演练场功能已禁用");
|
|
||||||
} else if (!cfg.isPublic && "nfd_playground_2024".equals(cfg.password)) {
|
|
||||||
log.warn("⚠️ 警告:您正在使用默认密码,建议修改配置文件中的 playground.password 以确保安全!");
|
log.warn("⚠️ 警告:您正在使用默认密码,建议修改配置文件中的 playground.password 以确保安全!");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.info("未找到playground配置,使用默认值: enabled=false, public=false");
|
log.info("未找到playground配置,使用默认值: public=false");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,23 +50,10 @@ public class PlaygroundApi {
|
|||||||
private static final String SESSION_AUTH_KEY = "playgroundAuthed";
|
private static final String SESSION_AUTH_KEY = "playgroundAuthed";
|
||||||
private final DbService dbService = AsyncServiceUtil.getAsyncServiceInstance(DbService.class);
|
private final DbService dbService = AsyncServiceUtil.getAsyncServiceInstance(DbService.class);
|
||||||
|
|
||||||
/**
|
|
||||||
* 检查Playground是否启用
|
|
||||||
*/
|
|
||||||
private boolean checkEnabled() {
|
|
||||||
PlaygroundConfig config = PlaygroundConfig.getInstance();
|
|
||||||
return config.isEnabled();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查Playground访问权限
|
* 检查Playground访问权限
|
||||||
*/
|
*/
|
||||||
private boolean checkAuth(RoutingContext ctx) {
|
private boolean checkAuth(RoutingContext ctx) {
|
||||||
// 首先检查是否启用
|
|
||||||
if (!checkEnabled()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
PlaygroundConfig config = PlaygroundConfig.getInstance();
|
PlaygroundConfig config = PlaygroundConfig.getInstance();
|
||||||
|
|
||||||
// 如果是公开模式,直接允许访问
|
// 如果是公开模式,直接允许访问
|
||||||
@@ -90,11 +77,9 @@ public class PlaygroundApi {
|
|||||||
@RouteMapping(value = "/status", method = RouteMethod.GET)
|
@RouteMapping(value = "/status", method = RouteMethod.GET)
|
||||||
public Future<JsonObject> getStatus(RoutingContext ctx) {
|
public Future<JsonObject> getStatus(RoutingContext ctx) {
|
||||||
PlaygroundConfig config = PlaygroundConfig.getInstance();
|
PlaygroundConfig config = PlaygroundConfig.getInstance();
|
||||||
boolean enabled = config.isEnabled();
|
boolean authed = checkAuth(ctx);
|
||||||
boolean authed = enabled && checkAuth(ctx);
|
|
||||||
|
|
||||||
JsonObject result = new JsonObject()
|
JsonObject result = new JsonObject()
|
||||||
.put("enabled", enabled)
|
|
||||||
.put("public", config.isPublic())
|
.put("public", config.isPublic())
|
||||||
.put("authed", authed);
|
.put("authed", authed);
|
||||||
|
|
||||||
@@ -106,11 +91,6 @@ public class PlaygroundApi {
|
|||||||
*/
|
*/
|
||||||
@RouteMapping(value = "/login", method = RouteMethod.POST)
|
@RouteMapping(value = "/login", method = RouteMethod.POST)
|
||||||
public Future<JsonObject> login(RoutingContext ctx) {
|
public Future<JsonObject> login(RoutingContext ctx) {
|
||||||
// 检查是否启用
|
|
||||||
if (!checkEnabled()) {
|
|
||||||
return Future.succeededFuture(JsonResult.error("演练场功能已禁用").toJsonObject());
|
|
||||||
}
|
|
||||||
|
|
||||||
Promise<JsonObject> promise = Promise.promise();
|
Promise<JsonObject> promise = Promise.promise();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -162,11 +142,6 @@ public class PlaygroundApi {
|
|||||||
*/
|
*/
|
||||||
@RouteMapping(value = "/test", method = RouteMethod.POST)
|
@RouteMapping(value = "/test", method = RouteMethod.POST)
|
||||||
public Future<JsonObject> test(RoutingContext ctx) {
|
public Future<JsonObject> test(RoutingContext ctx) {
|
||||||
// 检查是否启用
|
|
||||||
if (!checkEnabled()) {
|
|
||||||
return Future.succeededFuture(JsonResult.error("演练场功能已禁用").toJsonObject());
|
|
||||||
}
|
|
||||||
|
|
||||||
// 权限检查
|
// 权限检查
|
||||||
if (!checkAuth(ctx)) {
|
if (!checkAuth(ctx)) {
|
||||||
return Future.succeededFuture(JsonResult.error("未授权访问").toJsonObject());
|
return Future.succeededFuture(JsonResult.error("未授权访问").toJsonObject());
|
||||||
@@ -370,12 +345,6 @@ public class PlaygroundApi {
|
|||||||
*/
|
*/
|
||||||
@RouteMapping(value = "/types.js", method = RouteMethod.GET)
|
@RouteMapping(value = "/types.js", method = RouteMethod.GET)
|
||||||
public void getTypesJs(RoutingContext ctx, HttpServerResponse response) {
|
public void getTypesJs(RoutingContext ctx, HttpServerResponse response) {
|
||||||
// 检查是否启用
|
|
||||||
if (!checkEnabled()) {
|
|
||||||
ResponseUtil.fireJsonResultResponse(response, JsonResult.error("演练场功能已禁用"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 权限检查
|
// 权限检查
|
||||||
if (!checkAuth(ctx)) {
|
if (!checkAuth(ctx)) {
|
||||||
ResponseUtil.fireJsonResultResponse(response, JsonResult.error("未授权访问"));
|
ResponseUtil.fireJsonResultResponse(response, JsonResult.error("未授权访问"));
|
||||||
@@ -408,11 +377,6 @@ public class PlaygroundApi {
|
|||||||
*/
|
*/
|
||||||
@RouteMapping(value = "/parsers", method = RouteMethod.GET)
|
@RouteMapping(value = "/parsers", method = RouteMethod.GET)
|
||||||
public Future<JsonObject> getParserList(RoutingContext ctx) {
|
public Future<JsonObject> getParserList(RoutingContext ctx) {
|
||||||
// 检查是否启用
|
|
||||||
if (!checkEnabled()) {
|
|
||||||
return Future.succeededFuture(JsonResult.error("演练场功能已禁用").toJsonObject());
|
|
||||||
}
|
|
||||||
|
|
||||||
// 权限检查
|
// 权限检查
|
||||||
if (!checkAuth(ctx)) {
|
if (!checkAuth(ctx)) {
|
||||||
return Future.succeededFuture(JsonResult.error("未授权访问").toJsonObject());
|
return Future.succeededFuture(JsonResult.error("未授权访问").toJsonObject());
|
||||||
@@ -425,11 +389,6 @@ public class PlaygroundApi {
|
|||||||
*/
|
*/
|
||||||
@RouteMapping(value = "/parsers", method = RouteMethod.POST)
|
@RouteMapping(value = "/parsers", method = RouteMethod.POST)
|
||||||
public Future<JsonObject> saveParser(RoutingContext ctx) {
|
public Future<JsonObject> saveParser(RoutingContext ctx) {
|
||||||
// 检查是否启用
|
|
||||||
if (!checkEnabled()) {
|
|
||||||
return Future.succeededFuture(JsonResult.error("演练场功能已禁用").toJsonObject());
|
|
||||||
}
|
|
||||||
|
|
||||||
// 权限检查
|
// 权限检查
|
||||||
if (!checkAuth(ctx)) {
|
if (!checkAuth(ctx)) {
|
||||||
return Future.succeededFuture(JsonResult.error("未授权访问").toJsonObject());
|
return Future.succeededFuture(JsonResult.error("未授权访问").toJsonObject());
|
||||||
@@ -545,11 +504,6 @@ public class PlaygroundApi {
|
|||||||
*/
|
*/
|
||||||
@RouteMapping(value = "/parsers/:id", method = RouteMethod.PUT)
|
@RouteMapping(value = "/parsers/:id", method = RouteMethod.PUT)
|
||||||
public Future<JsonObject> updateParser(RoutingContext ctx, Long id) {
|
public Future<JsonObject> updateParser(RoutingContext ctx, Long id) {
|
||||||
// 检查是否启用
|
|
||||||
if (!checkEnabled()) {
|
|
||||||
return Future.succeededFuture(JsonResult.error("演练场功能已禁用").toJsonObject());
|
|
||||||
}
|
|
||||||
|
|
||||||
// 权限检查
|
// 权限检查
|
||||||
if (!checkAuth(ctx)) {
|
if (!checkAuth(ctx)) {
|
||||||
return Future.succeededFuture(JsonResult.error("未授权访问").toJsonObject());
|
return Future.succeededFuture(JsonResult.error("未授权访问").toJsonObject());
|
||||||
@@ -631,11 +585,6 @@ public class PlaygroundApi {
|
|||||||
*/
|
*/
|
||||||
@RouteMapping(value = "/parsers/:id", method = RouteMethod.DELETE)
|
@RouteMapping(value = "/parsers/:id", method = RouteMethod.DELETE)
|
||||||
public Future<JsonObject> deleteParser(RoutingContext ctx, Long id) {
|
public Future<JsonObject> deleteParser(RoutingContext ctx, Long id) {
|
||||||
// 检查是否启用
|
|
||||||
if (!checkEnabled()) {
|
|
||||||
return Future.succeededFuture(JsonResult.error("演练场功能已禁用").toJsonObject());
|
|
||||||
}
|
|
||||||
|
|
||||||
// 权限检查
|
// 权限检查
|
||||||
if (!checkAuth(ctx)) {
|
if (!checkAuth(ctx)) {
|
||||||
return Future.succeededFuture(JsonResult.error("未授权访问").toJsonObject());
|
return Future.succeededFuture(JsonResult.error("未授权访问").toJsonObject());
|
||||||
@@ -679,11 +628,6 @@ public class PlaygroundApi {
|
|||||||
*/
|
*/
|
||||||
@RouteMapping(value = "/parsers/:id", method = RouteMethod.GET)
|
@RouteMapping(value = "/parsers/:id", method = RouteMethod.GET)
|
||||||
public Future<JsonObject> getParserById(RoutingContext ctx, Long id) {
|
public Future<JsonObject> getParserById(RoutingContext ctx, Long id) {
|
||||||
// 检查是否启用
|
|
||||||
if (!checkEnabled()) {
|
|
||||||
return Future.succeededFuture(JsonResult.error("演练场功能已禁用").toJsonObject());
|
|
||||||
}
|
|
||||||
|
|
||||||
// 权限检查
|
// 权限检查
|
||||||
if (!checkAuth(ctx)) {
|
if (!checkAuth(ctx)) {
|
||||||
return Future.succeededFuture(JsonResult.error("未授权访问").toJsonObject());
|
return Future.succeededFuture(JsonResult.error("未授权访问").toJsonObject());
|
||||||
|
|||||||
@@ -15,8 +15,6 @@ proxyConf: server-proxy
|
|||||||
|
|
||||||
# JS演练场配置
|
# JS演练场配置
|
||||||
playground:
|
playground:
|
||||||
# 是否启用演练场,默认false不启用
|
|
||||||
enabled: false
|
|
||||||
# 公开模式,默认false需要密码访问,设为true则无需密码
|
# 公开模式,默认false需要密码访问,设为true则无需密码
|
||||||
public: false
|
public: false
|
||||||
# 访问密码,建议修改默认密码!
|
# 访问密码,建议修改默认密码!
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ server-name: Vert.x-proxy-server(v4.1.2)
|
|||||||
proxy:
|
proxy:
|
||||||
- listen: 6401
|
- listen: 6401
|
||||||
# 404的路径
|
# 404的路径
|
||||||
page404: webroot/nfd-front/index.html
|
page404: webroot/err/404.html
|
||||||
static:
|
static:
|
||||||
path: /
|
path: /
|
||||||
add-headers:
|
add-headers:
|
||||||
|
|||||||
Reference in New Issue
Block a user