From 3ea17db9717a52ea8264d09c5bbdf3f629d06285 Mon Sep 17 00:00:00 2001 From: yuyx <237899745@qq.com> Date: Wed, 18 Feb 2026 11:23:34 +0800 Subject: [PATCH] fix: correct local datetime display and remove false devtools detection --- frontend/app.html | 91 ++++++------------------------------------ frontend/app.js | 76 ++++++++++++++++++++++++----------- frontend/share.html | 96 ++++++++++++++++++--------------------------- 3 files changed, 104 insertions(+), 159 deletions(-) diff --git a/frontend/app.html b/frontend/app.html index a17fc28..6e8c273 100644 --- a/frontend/app.html +++ b/frontend/app.html @@ -13,101 +13,32 @@ } })(); - + + diff --git a/frontend/app.js b/frontend/app.js index ed54903..a6ef11f 100644 --- a/frontend/app.js +++ b/frontend/app.js @@ -623,8 +623,14 @@ createApp({ } list.sort((a, b) => { - const getTime = s => s.created_at ? new Date(s.created_at).getTime() : 0; - const getExpire = s => s.expires_at ? new Date(s.expires_at).getTime() : Number.MAX_SAFE_INTEGER; + const getTime = (s) => { + const date = this.parseDateValue(s?.created_at); + return date ? date.getTime() : 0; + }; + const getExpire = (s) => { + const date = this.parseDateValue(s?.expires_at); + return date ? date.getTime() : Number.MAX_SAFE_INTEGER; + }; switch (this.shareFilters.sort) { case 'created_asc': @@ -657,8 +663,10 @@ createApp({ } list.sort((a, b) => { - const ta = a.created_at ? new Date(a.created_at).getTime() : 0; - const tb = b.created_at ? new Date(b.created_at).getTime() : 0; + const da = this.parseDateValue(a?.created_at); + const db = this.parseDateValue(b?.created_at); + const ta = da ? da.getTime() : 0; + const tb = db ? db.getTime() : 0; return tb - ta; }); @@ -3006,7 +3014,8 @@ handleDragLeave(e) { formatExpireTime(expiresAt) { if (!expiresAt) return '永久有效'; - const expireDate = new Date(expiresAt); + const expireDate = this.parseDateValue(expiresAt); + if (!expireDate) return String(expiresAt); const now = new Date(); const diffMs = expireDate - now; const diffMinutes = Math.floor(diffMs / (1000 * 60)); @@ -3040,7 +3049,8 @@ handleDragLeave(e) { // 判断是否即将过期(3天内) isExpiringSoon(expiresAt) { if (!expiresAt) return false; - const expireDate = new Date(expiresAt); + const expireDate = this.parseDateValue(expiresAt); + if (!expireDate) return false; const now = new Date(); const diffMs = expireDate - now; const diffDays = diffMs / (1000 * 60 * 60 * 24); @@ -3050,7 +3060,8 @@ handleDragLeave(e) { // 判断是否已过期 isExpired(expiresAt) { if (!expiresAt) return false; - const expireDate = new Date(expiresAt); + const expireDate = this.parseDateValue(expiresAt); + if (!expireDate) return false; const now = new Date(); return expireDate <= now; }, @@ -3148,8 +3159,8 @@ handleDragLeave(e) { // 格式化时间 formatDateTime(value) { if (!value) return '--'; - const d = new Date(value); - if (Number.isNaN(d.getTime())) return value; + const d = this.parseDateValue(value); + if (!d) return value; return d.toLocaleString(); }, @@ -4141,14 +4152,41 @@ handleDragLeave(e) { return '不自动重置'; }, + parseDateValue(value) { + if (!value) return null; + if (value instanceof Date) { + return Number.isNaN(value.getTime()) ? null : value; + } + + const raw = String(value).trim(); + if (!raw) return null; + + const localMatch = raw.match(/^(\d{4})-(\d{2})-(\d{2})(?:[ T](\d{2}):(\d{2})(?::(\d{2}))?)?$/); + if (localMatch) { + const year = Number(localMatch[1]); + const month = Number(localMatch[2]); + const day = Number(localMatch[3]); + const hour = Number(localMatch[4] || 0); + const minute = Number(localMatch[5] || 0); + const second = Number(localMatch[6] || 0); + + const localDate = new Date(year, month - 1, day, hour, minute, second); + return Number.isNaN(localDate.getTime()) ? null : localDate; + } + + const normalized = raw.includes('T') ? raw : raw.replace(' ', 'T'); + const parsed = new Date(normalized); + return Number.isNaN(parsed.getTime()) ? null : parsed; + }, + toDateTimeLocalInput(dateString) { if (!dateString) return ''; const normalized = String(dateString).trim().replace(' ', 'T'); const match = normalized.match(/^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2})/); if (match) return match[1]; - const parsed = new Date(normalized); - if (Number.isNaN(parsed.getTime())) return ''; + const parsed = this.parseDateValue(dateString); + if (!parsed) return ''; const year = parsed.getFullYear(); const month = String(parsed.getMonth() + 1).padStart(2, '0'); const day = String(parsed.getDate()).padStart(2, '0'); @@ -4169,16 +4207,9 @@ handleDragLeave(e) { formatDate(dateString) { if (!dateString) return '-'; - - // SQLite 返回的是 UTC 时间字符串,需要显式处理 - // 如果字符串不包含时区信息,手动添加 'Z' 标记为 UTC - let dateStr = dateString; - if (!dateStr.includes('Z') && !dateStr.includes('+') && !dateStr.includes('T')) { - // SQLite 格式: "2025-11-13 16:37:19" -> ISO格式: "2025-11-13T16:37:19Z" - dateStr = dateStr.replace(' ', 'T') + 'Z'; - } - - const date = new Date(dateStr); + + const date = this.parseDateValue(dateString); + if (!date) return String(dateString); const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); @@ -4511,7 +4542,8 @@ handleDragLeave(e) { formatLogTime(timestamp) { if (!timestamp) return ''; - const date = new Date(timestamp); + const date = this.parseDateValue(timestamp); + if (!date) return String(timestamp); return date.toLocaleString('zh-CN', { year: 'numeric', month: '2-digit', diff --git a/frontend/share.html b/frontend/share.html index 839a2e2..ce44ebe 100644 --- a/frontend/share.html +++ b/frontend/share.html @@ -1369,17 +1369,36 @@ return 'color: #9E9E9E;'; }, - formatDate(dateString) { - if (!dateString) return ''; - - // SQLite 返回的是 UTC 时间字符串,需要显式处理 - let dateStr = dateString; - if (!dateStr.includes('Z') && !dateStr.includes('+') && !dateStr.includes('T')) { - // SQLite 格式: "2025-11-13 16:37:19" -> ISO格式: "2025-11-13T16:37:19Z" - dateStr = dateStr.replace(' ', 'T') + 'Z'; + parseDateValue(value) { + if (!value) return null; + if (value instanceof Date) { + return Number.isNaN(value.getTime()) ? null : value; } - const date = new Date(dateStr); + const raw = String(value).trim(); + if (!raw) return null; + + const localMatch = raw.match(/^(\d{4})-(\d{2})-(\d{2})(?:[ T](\d{2}):(\d{2})(?::(\d{2}))?)?$/); + if (localMatch) { + const year = Number(localMatch[1]); + const month = Number(localMatch[2]); + const day = Number(localMatch[3]); + const hour = Number(localMatch[4] || 0); + const minute = Number(localMatch[5] || 0); + const second = Number(localMatch[6] || 0); + const localDate = new Date(year, month - 1, day, hour, minute, second); + return Number.isNaN(localDate.getTime()) ? null : localDate; + } + + const normalized = raw.includes('T') ? raw : raw.replace(' ', 'T'); + const parsed = new Date(normalized); + return Number.isNaN(parsed.getTime()) ? null : parsed; + }, + + formatDate(dateString) { + if (!dateString) return ''; + const date = this.parseDateValue(dateString); + if (!date) return String(dateString); return date.toLocaleString('zh-CN', { year: 'numeric', month: '2-digit', @@ -1395,7 +1414,8 @@ formatExpireTime(expiresAt) { if (!expiresAt) return '永久有效'; - const expireDate = new Date(expiresAt); + const expireDate = this.parseDateValue(expiresAt); + if (!expireDate) return String(expiresAt); const now = new Date(); const diffMs = expireDate - now; const diffMinutes = Math.floor(diffMs / (1000 * 60)); @@ -1429,7 +1449,8 @@ // 判断是否即将过期(3天内) isExpiringSoon(expiresAt) { if (!expiresAt) return false; - const expireDate = new Date(expiresAt); + const expireDate = this.parseDateValue(expiresAt); + if (!expireDate) return false; const now = new Date(); const diffMs = expireDate - now; const diffDays = diffMs / (1000 * 60 * 60 * 24); @@ -1439,7 +1460,8 @@ // 判断是否已过期 isExpired(expiresAt) { if (!expiresAt) return false; - const expireDate = new Date(expiresAt); + const expireDate = this.parseDateValue(expiresAt); + if (!expireDate) return false; const now = new Date(); return expireDate <= now; } @@ -1494,57 +1516,17 @@ // 禁用F12和常见开发者工具快捷键(调试模式下不禁用) if (!isDebugMode) { document.addEventListener('keydown', function(e) { - // F12 - if (e.key === 'F12' || e.keyCode === 123) { - e.preventDefault(); - return false; - } - // Ctrl+Shift+I (开发者工具) - if (e.ctrlKey && e.shiftKey && (e.key === 'I' || e.keyCode === 73)) { - e.preventDefault(); - return false; - } - // Ctrl+Shift+J (控制台) - if (e.ctrlKey && e.shiftKey && (e.key === 'J' || e.keyCode === 74)) { - e.preventDefault(); - return false; - } - // Ctrl+U (查看源代码) - if (e.ctrlKey && (e.key === 'U' || e.keyCode === 85)) { - e.preventDefault(); - return false; - } - // Ctrl+Shift+C (元素选择器) - if (e.ctrlKey && e.shiftKey && (e.key === 'C' || e.keyCode === 67)) { + const key = String(e.key || '').toLowerCase(); + const blocked = e.keyCode === 123 + || (e.ctrlKey && e.shiftKey && ['i', 'j', 'c'].includes(key)) + || (e.ctrlKey && key === 'u'); + if (blocked) { e.preventDefault(); return false; } }); } - // 检测开发者工具是否打开(调试模式下不检测) - if (!isDebugMode) { - (function() { - const threshold = 160; - let isDevToolsOpen = false; - - setInterval(function() { - const widthThreshold = window.outerWidth - window.innerWidth > threshold; - const heightThreshold = window.outerHeight - window.innerHeight > threshold; - - if (!(heightThreshold && widthThreshold) && - ((window.Firebug && window.Firebug.chrome && window.Firebug.chrome.isInitialized) || widthThreshold || heightThreshold)) { - if (!isDevToolsOpen) { - isDevToolsOpen = true; - console.clear(); - } - } else { - isDevToolsOpen = false; - } - }, 500); - })(); - } - // 禁用console输出(调试模式下不禁用) if (!isDebugMode && window.location.hostname !== 'localhost' && window.location.hostname !== '127.0.0.1') { console.log = function() {};