diff --git a/gost.sql b/gost.sql index 597c0cb..5d21599 100644 --- a/gost.sql +++ b/gost.sql @@ -94,7 +94,8 @@ CREATE TABLE `statistics_flow` ( `user_id` int(10) NOT NULL, `flow` bigint(20) NOT NULL, `total_flow` bigint(20) NOT NULL, - `time` varchar(100) NOT NULL + `time` varchar(100) NOT NULL, + `created_time` bigint(20) NOT NULL, ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- -------------------------------------------------------- diff --git a/panel_install.sh b/panel_install.sh index 6d23820..b7e2ed4 100755 --- a/panel_install.sh +++ b/panel_install.sh @@ -809,9 +809,33 @@ CREATE TABLE IF NOT EXISTS \`statistics_flow\` ( \`flow\` bigint(20) NOT NULL, \`total_flow\` bigint(20) NOT NULL, \`time\` varchar(100) NOT NULL, + \`created_time\` bigint(20) NOT NULL, PRIMARY KEY (\`id\`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +-- statistics_flow 表:添加 created_time 字段(如果不存在) +SET @sql = ( + SELECT IF( + NOT EXISTS ( + SELECT 1 + FROM information_schema.COLUMNS + WHERE table_schema = DATABASE() + AND table_name = 'statistics_flow' + AND column_name = 'created_time' + ), + 'ALTER TABLE \`statistics_flow\` ADD COLUMN \`created_time\` BIGINT(20) NOT NULL DEFAULT 0 COMMENT "创建时间毫秒时间戳";', + 'SELECT "Column \`created_time\` already exists in \`statistics_flow\`";' + ) +); +PREPARE stmt FROM @sql; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; + +-- 为现有记录设置当前毫秒时间戳(仅当 created_time 为 0 或 NULL 时) +UPDATE \`statistics_flow\` +SET \`created_time\` = UNIX_TIMESTAMP() * 1000 +WHERE \`created_time\` = 0 OR \`created_time\` IS NULL; + diff --git a/springboot-backend/src/main/java/com/admin/common/task/StatisticsFlowAsync.java b/springboot-backend/src/main/java/com/admin/common/task/StatisticsFlowAsync.java index 76037f8..0d74e83 100644 --- a/springboot-backend/src/main/java/com/admin/common/task/StatisticsFlowAsync.java +++ b/springboot-backend/src/main/java/com/admin/common/task/StatisticsFlowAsync.java @@ -16,6 +16,7 @@ import javax.annotation.Resource; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.ArrayList; +import java.util.Date; import java.util.List; @Slf4j @@ -33,6 +34,19 @@ public class StatisticsFlowAsync { public void statistics_flow() { LocalDateTime currentHour = LocalDateTime.now().withMinute(0).withSecond(0).withNano(0); String hourString = currentHour.format(DateTimeFormatter.ofPattern("HH:mm")); + long time = new Date().getTime(); + + // 删除48小时前的数据 + long nowMs = System.currentTimeMillis(); + long cutoffMs = nowMs - 48L * 60 * 60 * 1000; + statisticsFlowService.remove( + new LambdaQueryWrapper() + .lt(StatisticsFlow::getCreateTime, cutoffMs) + ); + + + + List list = userService.list(); List statisticsFlowList = new ArrayList<>(); @@ -65,6 +79,7 @@ public class StatisticsFlowAsync { statisticsFlow.setFlow(incrementFlow); statisticsFlow.setTotalFlow(currentTotalFlow); statisticsFlow.setTime(hourString); + statisticsFlow.setCreateTime(time); statisticsFlowList.add(statisticsFlow); } diff --git a/springboot-backend/src/main/java/com/admin/config/CaptchaResourceConfiguration.java b/springboot-backend/src/main/java/com/admin/config/CaptchaResourceConfiguration.java index 7dc9235..d06469a 100644 --- a/springboot-backend/src/main/java/com/admin/config/CaptchaResourceConfiguration.java +++ b/springboot-backend/src/main/java/com/admin/config/CaptchaResourceConfiguration.java @@ -4,11 +4,15 @@ import cloud.tianai.captcha.common.constant.CaptchaTypeConstant; import cloud.tianai.captcha.resource.FontCache; import cloud.tianai.captcha.resource.ResourceStore; import cloud.tianai.captcha.resource.common.model.dto.Resource; +import cloud.tianai.captcha.resource.common.model.dto.ResourceMap; +import cloud.tianai.captcha.resource.impl.provider.ClassPathResourceProvider; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; +import static cloud.tianai.captcha.common.constant.CommonConstant.DEFAULT_SLIDER_IMAGE_TEMPLATE_PATH; + @Component @RequiredArgsConstructor public class CaptchaResourceConfiguration { @@ -22,16 +26,24 @@ public class CaptchaResourceConfiguration { @PostConstruct public void init() { + // 添加自定义背景图片 + for (int i = 1; i <= 10; i++) { + ResourceMap template = new ResourceMap("default", 4); + template.put("active.png", new Resource(ClassPathResourceProvider.NAME, "slide/" + i + "/1.png")); + template.put("fixed.png", new Resource(ClassPathResourceProvider.NAME, "slide/" + i + "/2.png")); + resourceStore.addTemplate(CaptchaTypeConstant.SLIDER, template); + } + // 添加自定义背景图片 for (String option : OPTIONS) { for (int i = 1; i <= 26; i++) { - resourceStore.addResource(option, new Resource("classpath", "bgimages/"+i + ".jpg", "default")); + resourceStore.addResource(option, new Resource("classpath", "bgimages/" + i + ".jpg", "default")); } } //添加自定义字体 - resourceStore.addResource(FontCache.FONT_TYPE,new Resource("classpath", "fonts/SIMSUN.TTC", "default")); + resourceStore.addResource(FontCache.FONT_TYPE, new Resource("classpath", "fonts/SIMSUN.TTC", "default")); } } \ No newline at end of file diff --git a/springboot-backend/src/main/java/com/admin/entity/StatisticsFlow.java b/springboot-backend/src/main/java/com/admin/entity/StatisticsFlow.java index b5063c9..6e81c1a 100644 --- a/springboot-backend/src/main/java/com/admin/entity/StatisticsFlow.java +++ b/springboot-backend/src/main/java/com/admin/entity/StatisticsFlow.java @@ -28,5 +28,7 @@ public class StatisticsFlow { private String time; + private Long createTime; + } diff --git a/springboot-backend/src/main/resources/slide/1/1.png b/springboot-backend/src/main/resources/slide/1/1.png new file mode 100644 index 0000000..d684aa2 Binary files /dev/null and b/springboot-backend/src/main/resources/slide/1/1.png differ diff --git a/springboot-backend/src/main/resources/slide/1/2.png b/springboot-backend/src/main/resources/slide/1/2.png new file mode 100644 index 0000000..6a599bb Binary files /dev/null and b/springboot-backend/src/main/resources/slide/1/2.png differ diff --git a/springboot-backend/src/main/resources/slide/10/1.png b/springboot-backend/src/main/resources/slide/10/1.png new file mode 100644 index 0000000..cd720b4 Binary files /dev/null and b/springboot-backend/src/main/resources/slide/10/1.png differ diff --git a/springboot-backend/src/main/resources/slide/10/2.png b/springboot-backend/src/main/resources/slide/10/2.png new file mode 100644 index 0000000..1e67338 Binary files /dev/null and b/springboot-backend/src/main/resources/slide/10/2.png differ diff --git a/springboot-backend/src/main/resources/slide/2/1.png b/springboot-backend/src/main/resources/slide/2/1.png new file mode 100644 index 0000000..9e93069 Binary files /dev/null and b/springboot-backend/src/main/resources/slide/2/1.png differ diff --git a/springboot-backend/src/main/resources/slide/2/2.png b/springboot-backend/src/main/resources/slide/2/2.png new file mode 100644 index 0000000..c3eb8b7 Binary files /dev/null and b/springboot-backend/src/main/resources/slide/2/2.png differ diff --git a/springboot-backend/src/main/resources/slide/3/1.png b/springboot-backend/src/main/resources/slide/3/1.png new file mode 100644 index 0000000..2f8e777 Binary files /dev/null and b/springboot-backend/src/main/resources/slide/3/1.png differ diff --git a/springboot-backend/src/main/resources/slide/3/2.png b/springboot-backend/src/main/resources/slide/3/2.png new file mode 100644 index 0000000..39ee879 Binary files /dev/null and b/springboot-backend/src/main/resources/slide/3/2.png differ diff --git a/springboot-backend/src/main/resources/slide/4/1.png b/springboot-backend/src/main/resources/slide/4/1.png new file mode 100644 index 0000000..9577cc1 Binary files /dev/null and b/springboot-backend/src/main/resources/slide/4/1.png differ diff --git a/springboot-backend/src/main/resources/slide/4/2.png b/springboot-backend/src/main/resources/slide/4/2.png new file mode 100644 index 0000000..a9b91a7 Binary files /dev/null and b/springboot-backend/src/main/resources/slide/4/2.png differ diff --git a/springboot-backend/src/main/resources/slide/5/1.png b/springboot-backend/src/main/resources/slide/5/1.png new file mode 100644 index 0000000..e4cdfa1 Binary files /dev/null and b/springboot-backend/src/main/resources/slide/5/1.png differ diff --git a/springboot-backend/src/main/resources/slide/5/2.png b/springboot-backend/src/main/resources/slide/5/2.png new file mode 100644 index 0000000..14ac9af Binary files /dev/null and b/springboot-backend/src/main/resources/slide/5/2.png differ diff --git a/springboot-backend/src/main/resources/slide/6/1.png b/springboot-backend/src/main/resources/slide/6/1.png new file mode 100644 index 0000000..5e78f38 Binary files /dev/null and b/springboot-backend/src/main/resources/slide/6/1.png differ diff --git a/springboot-backend/src/main/resources/slide/6/2.png b/springboot-backend/src/main/resources/slide/6/2.png new file mode 100644 index 0000000..55abcbe Binary files /dev/null and b/springboot-backend/src/main/resources/slide/6/2.png differ diff --git a/springboot-backend/src/main/resources/slide/7/1.png b/springboot-backend/src/main/resources/slide/7/1.png new file mode 100644 index 0000000..909b9dd Binary files /dev/null and b/springboot-backend/src/main/resources/slide/7/1.png differ diff --git a/springboot-backend/src/main/resources/slide/7/2.png b/springboot-backend/src/main/resources/slide/7/2.png new file mode 100644 index 0000000..0013e76 Binary files /dev/null and b/springboot-backend/src/main/resources/slide/7/2.png differ diff --git a/springboot-backend/src/main/resources/slide/8/1.png b/springboot-backend/src/main/resources/slide/8/1.png new file mode 100644 index 0000000..91b279a Binary files /dev/null and b/springboot-backend/src/main/resources/slide/8/1.png differ diff --git a/springboot-backend/src/main/resources/slide/8/2.png b/springboot-backend/src/main/resources/slide/8/2.png new file mode 100644 index 0000000..f124e99 Binary files /dev/null and b/springboot-backend/src/main/resources/slide/8/2.png differ diff --git a/springboot-backend/src/main/resources/slide/9/1.png b/springboot-backend/src/main/resources/slide/9/1.png new file mode 100644 index 0000000..9ec99a1 Binary files /dev/null and b/springboot-backend/src/main/resources/slide/9/1.png differ diff --git a/springboot-backend/src/main/resources/slide/9/2.png b/springboot-backend/src/main/resources/slide/9/2.png new file mode 100644 index 0000000..72e2ae5 Binary files /dev/null and b/springboot-backend/src/main/resources/slide/9/2.png differ diff --git a/vite-frontend/src/config/site.ts b/vite-frontend/src/config/site.ts index f354012..36eeeed 100644 --- a/vite-frontend/src/config/site.ts +++ b/vite-frontend/src/config/site.ts @@ -4,7 +4,7 @@ export type SiteConfig = typeof siteConfig; // 缓存相关常量 const CACHE_PREFIX = 'vite_config_'; -const VERSION = "1.2.8"; +const VERSION = "1.2.9"; const getInitialConfig = () => { diff --git a/vite-frontend/src/images/bg.jpg b/vite-frontend/src/images/bg.jpg new file mode 100644 index 0000000..d875ec4 Binary files /dev/null and b/vite-frontend/src/images/bg.jpg differ diff --git a/vite-frontend/src/pages/dashboard.tsx b/vite-frontend/src/pages/dashboard.tsx index e31fac6..bb55a80 100644 --- a/vite-frontend/src/pages/dashboard.tsx +++ b/vite-frontend/src/pages/dashboard.tsx @@ -63,6 +63,7 @@ export default function DashboardPage() { const [userTunnels, setUserTunnels] = useState([]); const [forwardList, setForwardList] = useState([]); const [statisticsFlows, setStatisticsFlows] = useState([]); + const [isAdmin, setIsAdmin] = useState(false); const [addressModalOpen, setAddressModalOpen] = useState(false); const [addressModalTitle, setAddressModalTitle] = useState(''); @@ -166,6 +167,10 @@ export default function DashboardPage() { setForwardList([]); setStatisticsFlows([]); + // 检查用户是否是管理员 + const adminStatus = localStorage.getItem('admin'); + setIsAdmin(adminStatus === 'true'); + loadPackageData(); localStorage.setItem('e', '/dashboard'); }, []); @@ -751,8 +756,9 @@ export default function DashboardPage() { - {/* 隧道权限 */} - + {/* 隧道权限 - 管理员不显示 */} + {!isAdmin && ( +
@@ -828,6 +834,7 @@ export default function DashboardPage() { )} + )} {/* 转发配置 */} diff --git a/vite-frontend/src/pages/index.tsx b/vite-frontend/src/pages/index.tsx index ecebafa..bf0cfd1 100644 --- a/vite-frontend/src/pages/index.tsx +++ b/vite-frontend/src/pages/index.tsx @@ -10,6 +10,7 @@ import DefaultLayout from "@/layouts/default"; import { login, LoginData, checkCaptcha } from "@/api"; import "@/utils/tac.css"; import "@/utils/tac.min.js"; +import bgImage from "@/images/bg.jpg"; interface LoginForm { @@ -31,6 +32,8 @@ interface CaptchaConfig { } interface CaptchaStyle { + btnUrl?: string; + bgUrl?: string; logoUrl?: string | null; moveTrackMaskBgColor?: string; moveTrackMaskBorderColor?: string; @@ -117,7 +120,6 @@ export default function IndexPage() { performLogin(); }, validFail: (_: any, _captcha: any, tac: any) => { - toast.error("验证码验证失败,请重试"); tac.reloadCaptcha(); }, btnCloseFun: (_event: any, tac: any) => { @@ -130,10 +132,19 @@ export default function IndexPage() { } }; + // 检测暗黑模式 + const isDarkMode = document.documentElement.classList.contains('dark') || + document.documentElement.getAttribute('data-theme') === 'dark' || + window.matchMedia('(prefers-color-scheme: dark)').matches; + + // 根据主题调整颜色 + const trackColor = isDarkMode ? "#4a5568" : "#7db0be"; // 暗黑模式使用更深的灰蓝色 + const style: CaptchaStyle = { - logoUrl: null, // 去除默认logo - moveTrackMaskBgColor: "#0298f8", - moveTrackMaskBorderColor: "#0298f8" + bgUrl: bgImage, + logoUrl: null, + moveTrackMaskBgColor: trackColor, + moveTrackMaskBorderColor: trackColor }; tacInstanceRef.current = new window.TAC(config, style); @@ -289,14 +300,20 @@ export default function IndexPage() { {/* 验证码弹层 */} {showCaptcha && (
- {/* 背景遮罩层 - 模糊效果 */} -
+ {/* 背景遮罩层 - 模糊效果,暗黑模式下更深 */} +
{/* 验证码容器 */}
diff --git a/vite-frontend/src/pages/node.tsx b/vite-frontend/src/pages/node.tsx index c81fc48..a6ca2f4 100644 --- a/vite-frontend/src/pages/node.tsx +++ b/vite-frontend/src/pages/node.tsx @@ -879,21 +879,9 @@ export default function NodePage() { - -
diff --git a/vite-frontend/src/pages/tunnel.tsx b/vite-frontend/src/pages/tunnel.tsx index 0d5f5a5..5b88c28 100644 --- a/vite-frontend/src/pages/tunnel.tsx +++ b/vite-frontend/src/pages/tunnel.tsx @@ -100,8 +100,8 @@ export default function TunnelPage() { inNodeId: null, outNodeId: null, protocol: 'tls', - tcpListenAddr: '0.0.0.0', - udpListenAddr: '0.0.0.0', + tcpListenAddr: '[::]', + udpListenAddr: '[::]', interfaceName: '', flow: 1, trafficRatio: 1.0, @@ -195,8 +195,8 @@ export default function TunnelPage() { inNodeId: null, outNodeId: null, protocol: 'tls', - tcpListenAddr: '0.0.0.0', - udpListenAddr: '0.0.0.0', + tcpListenAddr: '[::]', + udpListenAddr: '[::]', interfaceName: '', flow: 1, trafficRatio: 1.0, @@ -216,8 +216,8 @@ export default function TunnelPage() { inNodeId: tunnel.inNodeId, outNodeId: tunnel.outNodeId || null, protocol: tunnel.protocol || 'tls', - tcpListenAddr: tunnel.tcpListenAddr || '0.0.0.0', - udpListenAddr: tunnel.udpListenAddr || '0.0.0.0', + tcpListenAddr: tunnel.tcpListenAddr || '[::]', + udpListenAddr: tunnel.udpListenAddr || '[::]', interfaceName: tunnel.interfaceName || '', flow: tunnel.flow, trafficRatio: tunnel.trafficRatio, diff --git a/vite-frontend/src/pages/user.tsx b/vite-frontend/src/pages/user.tsx index fec6022..4548c32 100644 --- a/vite-frontend/src/pages/user.tsx +++ b/vite-frontend/src/pages/user.tsx @@ -988,7 +988,7 @@ export default function UserPage() { aria-label="用户隧道权限列表" classNames={{ wrapper: "shadow-none", - th: "bg-gray-50 text-gray-700 font-medium" + th: "bg-gray-50 dark:bg-gray-800 text-gray-700 dark:text-gray-300 font-medium" }} >