diff --git a/assets/css/custom.css b/assets/css/custom.css index 0210e2e..ddaaf03 100644 --- a/assets/css/custom.css +++ b/assets/css/custom.css @@ -1,264 +1,231 @@ :root { - --primary-pink: #ff69b4; /* HotPink - softer than DeepPink */ - --vibrant-pink: #ff85b2; - --light-pink: #fff0f5; /* LavenderBlush */ - --accent-gold: #ffd700; - --bg-bright: #fffafa; /* Snow */ - --text-main: #444; - --glass-bg: rgba(255, 255, 255, 0.9); - --glass-border: rgba(255, 105, 180, 0.3); + --primary-pink: #ff1493; + --vibrant-pink: #ff69b4; + --soft-pink: #ffb6c1; + --royal-gold: #ffd700; + --electric-blue: #00d2ff; + --neon-green: #39ff14; + --glass-bg: rgba(255, 255, 255, 0.95); + --dark-text: #2c3e50; } body.bg-wealth { - background: linear-gradient(135deg, #ffb6c1, #ffc0cb, #fff0f5); + background: linear-gradient(45deg, #ff9a9e 0%, #fad0c4 99%, #fad0c4 100%); background-attachment: fixed; - color: var(--text-main); - font-family: 'Noto Sans SC', 'Inter', -apple-system, sans-serif; + color: var(--dark-text); + font-family: 'Noto Sans SC', sans-serif; min-height: 100vh; - -webkit-font-smoothing: antialiased; } -/* Glassmorphism Effects */ +/* Personalized Brand Font */ +.brand-personalized { + font-family: 'Ma Shan Zheng', cursive; + font-size: 2.2rem; + letter-spacing: 2px; +} + +/* Glass Navbar */ .glass-nav { - background: rgba(255, 255, 255, 0.95) !important; - backdrop-filter: blur(10px); - border-bottom: 2px solid var(--primary-pink); -} - -.glass-card { - background: var(--glass-bg); + background: var(--glass-bg) !important; backdrop-filter: blur(15px); - border: 3px solid var(--primary-pink) !important; - border-radius: 24px !important; - box-shadow: 0 10px 30px rgba(255, 105, 180, 0.15) !important; + border-bottom: 3px solid transparent; + border-image: linear-gradient(to right, var(--primary-pink), var(--royal-gold), var(--electric-blue)) 1; } -.icon-circle.bg-gold { +/* Time Badge Fix - More Contrast */ +.time-badge { background: linear-gradient(135deg, var(--primary-pink), var(--vibrant-pink)); - box-shadow: 0 0 15px rgba(255, 105, 180, 0.3); + color: white; + border-radius: 50px; + padding: 8px 20px; + border: 2px solid white; + display: flex; + align-items: center; + box-shadow: 0 5px 15px rgba(255, 20, 147, 0.4); +} + +.time-badge i { + color: var(--royal-gold); +} + +/* Modern Gradient Cards */ +.modern-card { + background: var(--glass-bg); + border-radius: 20px; + overflow: hidden; + position: relative; + z-index: 1; + transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275); +} + +.modern-card::before { + content: ''; + position: absolute; + top: -3px; left: -3px; right: -3px; bottom: -3px; + background: linear-gradient(135deg, var(--primary-pink), var(--royal-gold), var(--electric-blue), var(--neon-green)); + background-size: 400% 400%; + z-index: -1; + border-radius: 23px; + animation: gradient-border 8s ease infinite; +} + +@keyframes gradient-border { + 0% { background-position: 0% 50%; } + 50% { background-position: 100% 50%; } + 100% { background-position: 0% 50%; } +} + +.modern-card:hover { + transform: translateY(-5px); + box-shadow: 0 15px 40px rgba(0,0,0,0.1); +} + +/* Area sizing consistency */ +.fixed-height-area { + height: 550px !important; + overflow-y: auto; + font-size: 1.15rem; +} + +.result-display { + background: #ffffff; + border: 2px dashed var(--soft-pink); + border-radius: 15px; + padding: 25px; + line-height: 1.8; + color: #333; + font-weight: 600; + white-space: pre-wrap; /* Preserve line breaks */ +} + +/* Personalized Buttons */ +.btn-personalized { + border-radius: 50px; + padding: 12px 30px; + font-weight: 800; + letter-spacing: 1px; + text-transform: uppercase; + transition: all 0.3s ease; + border: none; + position: relative; + overflow: hidden; +} + +.btn-parse { + background: linear-gradient(to right, #ff1493, #ff69b4); + color: white !important; + box-shadow: 0 5px 20px rgba(255, 20, 147, 0.4); +} + +.btn-parse:hover { + box-shadow: 0 10px 30px rgba(255, 20, 147, 0.6); + transform: scale(1.03); +} + +.btn-clear { + background: white; + color: var(--primary-pink) !important; + border: 2px solid var(--primary-pink); +} + +.btn-clear:hover { + background: #fff0f5; + transform: rotate(-2deg); +} + +.btn-copy-alt { + background: linear-gradient(135deg, #ffd700, #ff8c00); color: white !important; } -.icon-circle.bg-success { - background: linear-gradient(135deg, #00c853, #b2ff59); +.btn-copy-alt:hover { + filter: brightness(1.1); + transform: translateY(-2px); } -/* Navbar & Brand */ -.logo-wrapper { +/* Icons */ +.icon-badge { + width: 50px; + height: 50px; + border-radius: 12px; display: flex; align-items: center; justify-content: center; - width: 45px; - height: 45px; - border-radius: 50%; + font-size: 1.5rem; + margin-right: 15px; +} + +.badge-pink { background: linear-gradient(135deg, #ff1493, #ff69b4); color: white; } +.badge-gold { background: linear-gradient(135deg, #ffd700, #daa520); color: white; } + +/* Carousel */ +.hero-wrapper { + border-radius: 25px; overflow: hidden; - border: 2px solid var(--primary-pink); - box-shadow: 0 0 10px rgba(255, 105, 180, 0.2); + border: 5px solid white; + box-shadow: 0 20px 50px rgba(0,0,0,0.15); } -.brand-text { - font-size: 1.4rem; - background: linear-gradient(135deg, var(--primary-pink) 0%, #ff1493 100%); - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - font-weight: 900 !important; +.hero-img { + height: 250px; + object-fit: cover; } -.text-glow { - text-shadow: 0 0 10px rgba(255, 105, 180, 0.1); +/* Instruction Steps */ +.step-item { + background: white; + border-radius: 15px; + padding: 15px; + margin-bottom: 12px; + display: flex; + align-items: center; + border-left: 5px solid var(--electric-blue); + transition: 0.3s; } -/* Animations */ -@keyframes rotating { +.step-item:hover { + background: #f0faff; + transform: translateX(5px); +} + +.step-digit { + background: var(--electric-blue); + color: white; + width: 30px; + height: 30px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + font-weight: bold; + margin-right: 15px; +} + +/* Logo Animation */ +.logo-spin { + animation: spin 20s linear infinite; + border: 3px solid var(--primary-pink); + padding: 2px; +} + +@keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } -.rotating { - animation: rotating 15s linear infinite; -} - -/* Carousel */ -#mainCarousel { - border: 3px solid var(--primary-pink); -} - -.hero-img { - height: 220px; - object-fit: cover; - filter: brightness(0.95); -} - -.carousel-overlay { - background: linear-gradient(to top, rgba(255, 105, 180, 0.3), transparent); -} - -.carousel-caption h2 { - font-size: 2.2rem !important; - text-shadow: 1px 1px 3px rgba(0,0,0,0.2); - color: white !important; -} - -.slogan-text { - color: white !important; - font-weight: 700; - text-shadow: 1px 1px 2px rgba(0,0,0,0.2); -} - -/* Inputs & Outputs */ -.glass-input { - background: #fff !important; - border: 2px solid var(--primary-pink) !important; - color: var(--primary-pink) !important; - border-radius: 12px !important; - transition: all 0.3s ease; - font-weight: 700 !important; - font-size: 1.1rem !important; -} - -.glass-input::placeholder { - color: #ffb6c1 !important; - font-weight: 500; - text-shadow: 1px 1px 2px rgba(255, 105, 180, 0.2); - opacity: 0.8; -} - -.glass-input:focus { - background: #fff !important; - border-color: #ff1493 !important; - box-shadow: 0 0 0 4px rgba(255, 105, 180, 0.2) !important; - transform: scale(1.01); -} - -.form-label { - color: var(--primary-pink) !important; - font-weight: 800 !important; - font-size: 1rem; - margin-bottom: 0.5rem; -} - -.result-container-dark { - background: #fff; - border: 3px solid var(--primary-pink); +.brand-glow { color: var(--primary-pink); - font-family: 'Noto Sans SC', sans-serif; - white-space: pre-wrap; - line-height: 1.8; - font-size: 1.1rem; - font-weight: 700; - box-shadow: inset 0 2px 8px rgba(255, 105, 180, 0.1); + text-shadow: 0 0 15px rgba(255, 20, 147, 0.3); } -/* Buttons */ -.btn-gold { - background: linear-gradient(135deg, #ff1493 0%, #ff69b4 100%); - border: none; - color: white !important; - border-radius: 15px; - box-shadow: 0 6px 15px rgba(255, 105, 180, 0.3); - transition: all 0.3s ease; - font-size: 1.2rem; -} - -.btn-gold:hover { - transform: translateY(-3px); - box-shadow: 0 10px 20px rgba(255, 105, 180, 0.4); - filter: brightness(1.05); -} - -.btn-gold-outline { - border: 2px solid var(--primary-pink); - color: var(--primary-pink); - border-radius: 12px; - transition: all 0.2s; - font-weight: 800; -} - -.btn-gold-outline:hover { - background: var(--primary-pink); - color: #fff; -} - -.btn-outline-light { - border: 2px solid var(--primary-pink); - color: var(--primary-pink); - background: white; -} - -.btn-outline-light:hover { - background: #fff5f8; - color: var(--primary-pink); - border-color: #ff1493; -} - -.text-light-muted { - color: var(--primary-pink); - opacity: 0.8; +/* Textarea Custom */ +.custom-textarea { + border: none !important; + background: #fcfcfc !important; + padding: 20px !important; font-weight: 600; } -/* Footer & Logo */ -.footer { - border-top: 4px solid var(--primary-pink); - color: var(--primary-pink) !important; - background: #fff !important; -} - -.footer-logo { - width: 60px; - height: 60px; - border-radius: 50%; - object-fit: cover; - border: 3px solid var(--primary-pink); -} - -/* Instructions Section */ -.instruction-card { - background: #fff5f8; - border-left: 5px solid var(--primary-pink); - border-radius: 12px; -} - -.instruction-step { - display: flex; - align-items: center; - margin-bottom: 1rem; -} - -.step-number { - width: 28px; - height: 28px; - background: var(--primary-pink); - color: white; - border-radius: 50%; - display: flex; - align-items: center; - justify-content: center; - font-size: 0.9rem; - font-weight: 900; - margin-right: 12px; - flex-shrink: 0; -} - -/* Responsive */ -@media (max-width: 768px) { - .hero-img { height: 160px; } - .carousel-caption h2 { font-size: 1.5rem !important; } -} - -.logo-img { width: 100%; height: 100%; object-fit: cover; display: block; } - -.marked-label { - font-weight: 900 !important; - font-size: 1.1rem !important; - color: #ff1493 !important; -} - -hr { - border-top: 2px solid var(--primary-pink) !important; - opacity: 0.2 !important; -} - -#real-time-clock { - color: var(--primary-pink) !important; +.custom-textarea:focus { + box-shadow: none !important; } \ No newline at end of file diff --git a/assets/js/main.js b/assets/js/main.js index 97a14c5..1103734 100644 --- a/assets/js/main.js +++ b/assets/js/main.js @@ -2,33 +2,14 @@ document.addEventListener('DOMContentLoaded', () => { // Elements const clockEl = document.getElementById('real-time-clock'); const outputEl = document.getElementById('reportOutput'); - const btnParse = document.getElementById('btnParse'); - const btnClear = document.getElementById('btnClear'); const btnCopy = document.getElementById('btnCopy'); + const btnBatchParse = document.getElementById('btnBatchParse'); + const btnClearBatch = document.getElementById('btnClearBatch'); + const batchInput = document.getElementById('batchInput'); const toastMessage = document.getElementById('toastMessage'); const toastEl = document.getElementById('liveToast'); const toast = new bootstrap.Toast(toastEl); - // Input Elements Mapping - const inputs = { - totalWS: document.getElementById('in_totalWS'), - wsBanned: document.getElementById('in_wsBanned'), - wsPermBanned: document.getElementById('in_wsPermBanned'), - totalXHS: document.getElementById('in_totalXHS'), - totalSMS: document.getElementById('in_totalSMS'), - xhs: document.getElementById('in_xhs'), - xhs_reply: document.getElementById('in_xhs_reply'), - ws: document.getElementById('in_ws'), - ws_reply: document.getElementById('in_ws_reply'), - sms: document.getElementById('in_sms'), - sms_reply: document.getElementById('in_sms_reply'), - totalGreeting: document.getElementById('in_totalGreeting'), - totalReply: document.getElementById('in_totalReply'), - rechat: document.getElementById('in_rechat'), - traffic: document.getElementById('in_traffic'), - voice: document.getElementById('in_voice') - }; - // Initialize Real-time Clock const updateClock = () => { const now = new Date(); @@ -46,69 +27,160 @@ document.addEventListener('DOMContentLoaded', () => { // Show Toast Helper const showToast = (msg, isError = false) => { toastMessage.textContent = msg; - const icon = isError ? 'fa-circle-xmark text-danger' : 'fa-circle-check text-success'; - toastMessage.previousElementSibling.className = `fa-solid ${icon} me-2`; + const iconContainer = toastMessage.previousElementSibling; + if (iconContainer) { + const icon = isError ? 'fa-circle-xmark text-danger' : 'fa-circle-check text-success'; + iconContainer.className = `fa-solid ${icon} me-2`; + } toast.show(); }; - // Parsing Logic - const generateReport = () => { - const stats = {}; - let hasValue = false; + // Global button click feedback + document.querySelectorAll('button').forEach(btn => { + btn.addEventListener('click', (e) => { + if (btn.id === 'btnBatchParse' || btn.id === 'btnClearBatch' || btn.id === 'btnCopy') return; + + if (btn.classList.contains('carousel-control-prev') || btn.classList.contains('carousel-control-next')) { + showToast('切换轮播图'); + } else if (btn.hasAttribute('data-bs-slide-to')) { + showToast('切换到幻灯片 ' + (parseInt(btn.getAttribute('data-bs-slide-to')) + 1)); + } else if (!btn.classList.contains('btn-close')) { + showToast('功能已触达'); + } + }); + }); - for (const [key, el] of Object.entries(inputs)) { - const val = parseInt(el.value, 10) || 0; - stats[key] = val; - if (el.value !== '') hasValue = true; - } - - if (!hasValue) { - showToast('请至少填入一项数据!', true); - return; - } - - // Generate output in the EXACT order and format requested by the user - // We also use the "招呼量" terminology for XHS, WS, SMS in the output for consistency - const result = `总WS数量: ${stats.totalWS} + // Helper to format the final report (Exact format requested) + const formatReport = (stats) => { + return `总WS数量: ${stats.totalWS} WS今日封号: ${stats.wsBanned} 总永封WS: ${stats.wsPermBanned} 总XHS数量: ${stats.totalXHS} 总SMS数量: ${stats.totalSMS} -XHS招呼量: ${stats.xhs} 回复: ${stats.xhs_reply} -WS招呼量: ${stats.ws} 回复: ${stats.ws_reply} -SMS招呼量: ${stats.sms} 回复: ${stats.sms_reply} +XHS: ${stats.xhs} +回复: ${stats.xhs_reply} +WS: ${stats.ws} +回复: ${stats.ws_reply} +SMS: ${stats.sms} +回复: ${stats.sms_reply} 总招呼量: ${stats.totalGreeting} 总回复: ${stats.totalReply} 再聊: ${stats.rechat} 引流: ${stats.traffic} 语音: ${stats.voice}`; + }; - outputEl.textContent = result; + // Robust Parsing Logic + const parseBatchData = () => { + const text = batchInput.value.trim(); + if (!text) { + showToast('请先粘贴报表内容!', true); + return; + } + + const totals = { + totalWS: 0, wsBanned: 0, wsPermBanned: 0, totalXHS: 0, totalSMS: 0, + xhs: 0, xhs_reply: 0, ws: 0, ws_reply: 0, sms: 0, sms_reply: 0, + totalGreeting: 0, totalReply: 0, rechat: 0, traffic: 0, voice: 0 + }; + + // Helper to extract a single value from a chunk + const extractVal = (pattern, content) => { + const match = content.match(pattern); + return match ? parseInt(match[1], 10) : 0; + }; + + // Identify distinct reports by "总WS数量" delimiter + const reportChunks = text.split(/总WS数量/); + + reportChunks.forEach((chunk, index) => { + if (!chunk.trim() && index === 0) return; + + const fullChunk = (index === 0 && !text.startsWith('总WS数量')) ? chunk : '总WS数量' + chunk; + + // Basic fields + totals.totalWS += extractVal(/总WS数量[::\s]+(\d+)/, fullChunk); + totals.wsBanned += extractVal(/WS今日封号[::\s]+(\d+)/, fullChunk); + totals.wsPermBanned += extractVal(/总永封WS[::\s]+(\d+)/, fullChunk); + totals.totalXHS += extractVal(/总XHS数量[::\s]+(\d+)/, fullChunk); + totals.totalSMS += extractVal(/总SMS数量[::\s]+(\d+)/, fullChunk); + + // XHS & Reply (Targeted extraction) + const xhsMatch = fullChunk.match(/XHS招呼量[::\s]+(\d+)[\s\S]*?回复[::\s]+(\d+)/); + if (xhsMatch) { + totals.xhs += parseInt(xhsMatch[1], 10); + totals.xhs_reply += parseInt(xhsMatch[2], 10); + } else { + totals.xhs += extractVal(/XHS(?:招呼量)?[::\s]+(\d+)/, fullChunk); + const genericXhsReply = fullChunk.match(/XHS[\s\S]*?回复[::\s]+(\d+)/); + if (genericXhsReply) totals.xhs_reply += parseInt(genericXhsReply[1], 10); + } + + // WS & Reply + const wsMatch = fullChunk.match(/WS招呼量[::\s]+(\d+)[\s\S]*?回复[::\s]+(\d+)/); + if (wsMatch) { + totals.ws += parseInt(wsMatch[1], 10); + totals.ws_reply += parseInt(wsMatch[2], 10); + } else { + totals.ws += extractVal(/WS(?:招呼量)?[::\s]+(\d+)/, fullChunk); + const genericWsReply = fullChunk.match(/WS[\s\S]*?回复[::\s]+(\d+)/); + if (genericWsReply) totals.ws_reply += parseInt(genericWsReply[1], 10); + } + + // SMS & Reply + const smsMatch = fullChunk.match(/SMS招呼量[::\s]+(\d+)[\s\S]*?回复[::\s]+(\d+)/); + if (smsMatch) { + totals.sms += parseInt(smsMatch[1], 10); + totals.sms_reply += parseInt(smsMatch[2], 10); + } else { + totals.sms += extractVal(/SMS(?:招呼量)?[::\s]+(\d+)/, fullChunk); + const genericSmsReply = fullChunk.match(/SMS[\s\S]*?回复[::\s]+(\d+)/); + if (genericSmsReply) totals.sms_reply += parseInt(genericSmsReply[1], 10); + } + + // Bottom fields + totals.totalGreeting += extractVal(/总招呼量[::\s]+(\d+)/, fullChunk); + totals.totalReply += extractVal(/总回复[::\s]+(\d+)/, fullChunk); + totals.rechat += extractVal(/再聊[::\s]+(\d+)/, fullChunk); + totals.traffic += extractVal(/引流[::\s]+(\d+)/, fullChunk); + totals.voice += extractVal(/语音[::\s]+(\d+)/, fullChunk); + }); + + outputEl.textContent = formatReport(totals); btnCopy.disabled = false; - showToast('报表生成成功!'); + showToast('报表汇总成功!'); }; // Events - btnParse.addEventListener('click', generateReport); + if (btnBatchParse) { + btnBatchParse.addEventListener('click', () => { + showToast('深度解析中...'); + setTimeout(parseBatchData, 400); + }); + } - btnClear.addEventListener('click', () => { - for (const el of Object.values(inputs)) { - el.value = ''; - } - outputEl.textContent = '数据结果将在此处生成...'; - btnCopy.disabled = true; - showToast('已清空所有内容'); - }); + if (btnClearBatch) { + btnClearBatch.addEventListener('click', () => { + batchInput.value = ''; + outputEl.textContent = '数据结果将在此处生成...'; + btnCopy.disabled = true; + showToast('输入区域已清空'); + }); + } - btnCopy.addEventListener('click', () => { - const text = outputEl.textContent; - if (text && !text.includes('在此处生成')) { - navigator.clipboard.writeText(text).then(() => { - showToast('汇总报表已复制到剪贴板!'); - }).catch(err => { - console.error('Copy failed', err); - showToast('复制失败,请手动选择复制', true); - }); - } - }); + if (btnCopy) { + btnCopy.addEventListener('click', () => { + const text = outputEl.textContent; + if (text && !text.includes('在此处生成')) { + navigator.clipboard.writeText(text).then(() => { + showToast('汇总报表已复制成功!'); + }).catch(err => { + console.error('Copy failed', err); + showToast('复制失败', true); + }); + } else { + showToast('无可复制内容', true); + } + }); + } }); \ No newline at end of file diff --git a/assets/pasted-20260224-132125-caa5002a.png b/assets/pasted-20260224-132125-caa5002a.png new file mode 100644 index 0000000..405ef11 Binary files /dev/null and b/assets/pasted-20260224-132125-caa5002a.png differ diff --git a/assets/pasted-20260224-132641-5b229e68.png b/assets/pasted-20260224-132641-5b229e68.png new file mode 100644 index 0000000..c7ffd3f Binary files /dev/null and b/assets/pasted-20260224-132641-5b229e68.png differ diff --git a/assets/pasted-20260224-133231-aee5dd9c.png b/assets/pasted-20260224-133231-aee5dd9c.png new file mode 100644 index 0000000..f3c390e Binary files /dev/null and b/assets/pasted-20260224-133231-aee5dd9c.png differ diff --git a/assets/pasted-20260224-135812-cffb2f73.png b/assets/pasted-20260224-135812-cffb2f73.png new file mode 100644 index 0000000..549fa95 Binary files /dev/null and b/assets/pasted-20260224-135812-cffb2f73.png differ diff --git a/index.php b/index.php index 77d99d0..844ab4b 100644 --- a/index.php +++ b/index.php @@ -4,7 +4,7 @@ declare(strict_types=1); @date_default_timezone_set('Asia/Shanghai'); $projectName = '财神组报表统计系统'; -$projectDescription = '专业、高效、精准的报表数据汇总解析平台'; +$projectDescription = '专业、高效、精准...报表数据汇总解析平台'; $logoPath = 'assets/pasted-20260224-085211-bb97e8b6.jpg'; ?> @@ -18,8 +18,8 @@ $logoPath = 'assets/pasted-20260224-085211-bb97e8b6.jpg'; - - + + @@ -28,201 +28,113 @@ $logoPath = 'assets/pasted-20260224-085211-bb97e8b6.jpg'; -