From 82210681c0c9a61959968f9add13ea74b0f5fdc8 Mon Sep 17 00:00:00 2001 From: biss Date: Tue, 5 May 2026 07:13:54 +0800 Subject: [PATCH] 2000s --- 2000s/certs/certificate.html | 91 ++ 2000s/certs/index.html | 96 ++ 2000s/css/notice-banner.css | 136 +++ 2000s/css/notice-page.css | 536 +++++++++++ 2000s/css/style.css | 186 ++++ 2000s/css/tech-query.css | 1710 +++++++++++++++++++++++++++++++++ 2000s/css/ticket-print.css | 95 ++ 2000s/js/certs-certificate.js | 119 +++ 2000s/js/certs-index.js | 246 +++++ 2000s/js/notice-banner.js | 175 ++++ 2000s/js/notice-index.js | 70 ++ 2000s/js/ticket-detail.js | 100 ++ 2000s/js/ticket-index.js | 132 +++ 2000s/js/ticket-print.js | 47 + 2000s/js/xinhan-index.js | 73 ++ 2000s/notice/index.html | 70 ++ 2000s/ticket/detail.html | 37 + 2000s/ticket/index.html | 96 ++ 2000s/ticket/print.html | 46 + 2000s/xinhan/index.html | 84 ++ 20 files changed, 4145 insertions(+) create mode 100644 2000s/certs/certificate.html create mode 100644 2000s/certs/index.html create mode 100644 2000s/css/notice-banner.css create mode 100644 2000s/css/notice-page.css create mode 100644 2000s/css/style.css create mode 100644 2000s/css/tech-query.css create mode 100644 2000s/css/ticket-print.css create mode 100644 2000s/js/certs-certificate.js create mode 100644 2000s/js/certs-index.js create mode 100644 2000s/js/notice-banner.js create mode 100644 2000s/js/notice-index.js create mode 100644 2000s/js/ticket-detail.js create mode 100644 2000s/js/ticket-index.js create mode 100644 2000s/js/ticket-print.js create mode 100644 2000s/js/xinhan-index.js create mode 100644 2000s/notice/index.html create mode 100644 2000s/ticket/detail.html create mode 100644 2000s/ticket/index.html create mode 100644 2000s/ticket/print.html create mode 100644 2000s/xinhan/index.html diff --git a/2000s/certs/certificate.html b/2000s/certs/certificate.html new file mode 100644 index 0000000..29c1da7 --- /dev/null +++ b/2000s/certs/certificate.html @@ -0,0 +1,91 @@ + + + + + + 证书核验详情 + + + + + + + + +
+
+ 返回查询 +
+ + +
+
+ +
+
+
Certificate Preview
+

证书原件预览

+

点击下方预览区域或使用顶部按钮,即可加载对应证书原件图片。

+
+ 证书原件 +
+ + 点击加载证书图片 + 原件图片将从当前证书编号对应的 `img/*.svg` 文件中读取。 +
+
+
+ + +
+ + +
+ + + + + + + + diff --git a/2000s/certs/index.html b/2000s/certs/index.html new file mode 100644 index 0000000..df10193 --- /dev/null +++ b/2000s/certs/index.html @@ -0,0 +1,96 @@ + + + + + + 证书查询系统 + + + + + + + + + +
+ + +
+
+
+

检索条件

+
输入编号、姓名或奖项名后即可开始查询
+
+
+ +
+
+ +
+ + +
+
+
+ + +
+
+ + +
+ +
+
+ +
+
+
+

查询结果

+
点击“查看详情”进入证书详情页
+
+
+
+
请输入查询条件,或使用扫码功能快速检索证书。
+
+
+
+ +
+
+
+
+
+
请将条形码置于识别框内
+ +
+ + + + + + + + diff --git a/2000s/css/notice-banner.css b/2000s/css/notice-banner.css new file mode 100644 index 0000000..ee8003c --- /dev/null +++ b/2000s/css/notice-banner.css @@ -0,0 +1,136 @@ +.notice-banner { + position: fixed; + top: 0; + left: 0; + right: 0; + z-index: 9999; + display: none; + justify-content: center; + padding: 10px 14px; + color: #102033; + font-family: "Noto Sans SC", "Microsoft YaHei", Arial, sans-serif; + background: linear-gradient(90deg, #fff7d6, #dff7ff); + border-bottom: 1px solid rgba(16, 32, 51, 0.14); + box-shadow: 0 10px 28px rgba(0, 0, 0, 0.18); +} + +.notice-banner.is-visible { + display: flex; +} + +.notice-banner__inner { + width: min(100%, 1120px); + display: grid; + grid-template-columns: auto 1fr auto auto; + align-items: center; + gap: 10px; +} + +.notice-banner__badge { + min-width: 40px; + padding: 4px 9px; + border-radius: 999px; + color: #ffffff; + background: #2563eb; + font-size: 12px; + font-weight: 700; + text-align: center; + line-height: 1.2; +} + +.notice-banner[data-level="warning"] .notice-banner__badge { + background: #b45309; +} + +.notice-banner[data-level="error"] .notice-banner__badge { + background: #be123c; +} + +.notice-banner[data-level="success"] .notice-banner__badge { + background: #047857; +} + +.notice-banner__content { + min-width: 0; + font-size: 14px; + line-height: 1.45; +} + +.notice-banner__title { + margin-right: 6px; + font-weight: 700; +} + +.notice-banner__message { + color: rgba(16, 32, 51, 0.84); +} + +.notice-banner__link { + display: inline-flex; + align-items: center; + justify-content: center; + min-height: 30px; + padding: 0 12px; + border-radius: 999px; + color: #ffffff; + background: #075985; + font-size: 14px; + font-weight: 700; + text-decoration: none; + white-space: nowrap; +} + +.notice-banner__link:hover { + background: #0369a1; + text-decoration: none; +} + +.notice-banner__close { + width: 30px; + height: 30px; + border: 0; + border-radius: 50%; + color: #102033; + background: rgba(16, 32, 51, 0.08); + font-size: 20px; + line-height: 1; + cursor: pointer; +} + +.notice-banner__close:hover { + background: rgba(16, 32, 51, 0.14); +} + +body.has-notice-banner { + padding-top: calc(var(--notice-body-pad-top, 0px) + var(--notice-banner-height, 0px) + 12px) !important; +} + +@media (max-width: 640px) { + .notice-banner { + padding: 9px 10px; + } + + .notice-banner__inner { + grid-template-columns: auto 1fr auto; + gap: 8px; + } + + .notice-banner__link { + grid-column: 2 / 3; + justify-self: start; + } + + .notice-banner__content { + font-size: 13px; + } +} + +@media print { + .notice-banner { + display: none !important; + } + + body.has-notice-banner { + padding-top: var(--notice-body-pad-top, 0px) !important; + } +} diff --git a/2000s/css/notice-page.css b/2000s/css/notice-page.css new file mode 100644 index 0000000..2d5a173 --- /dev/null +++ b/2000s/css/notice-page.css @@ -0,0 +1,536 @@ +:root { + --bg: #07111f; + --panel: rgba(9, 20, 40, 0.78); + --panel-strong: rgba(10, 24, 46, 0.94); + --line: rgba(103, 213, 255, 0.22); + --line-strong: rgba(103, 213, 255, 0.48); + --text: #edf7ff; + --muted: #96b2d1; + --accent: #67d5ff; + --accent-strong: #2de2a6; + --warning: #ffcc66; + --font-display: "Orbitron", "Segoe UI", sans-serif; + --font-body: "Noto Sans SC", "Microsoft YaHei", sans-serif; +} + +* { + box-sizing: border-box; +} + +html { + color-scheme: dark; +} + +body { + margin: 0; + min-height: 100vh; + color: var(--text); + font-family: var(--font-body); + background: + linear-gradient(135deg, rgba(7, 17, 31, 0.96), rgba(10, 28, 54, 0.96)), + repeating-linear-gradient(90deg, rgba(103, 213, 255, 0.055) 0 1px, transparent 1px 72px), + repeating-linear-gradient(0deg, rgba(103, 213, 255, 0.045) 0 1px, transparent 1px 72px); +} + +a { + color: inherit; +} + +.notice-page { + width: min(calc(100% - 32px), 1120px); + margin: 0 auto; + padding: 28px 0 56px; +} + +.topbar { + display: flex; + align-items: center; + justify-content: space-between; + gap: 16px; + margin-bottom: 34px; +} + +.brand, +.back-link, +.primary-action { + display: inline-flex; + align-items: center; + min-height: 40px; + border-radius: 999px; + text-decoration: none; +} + +.brand { + gap: 10px; + color: var(--text); + font-weight: 700; +} + +.brand-mark { + display: inline-grid; + place-items: center; + width: 40px; + height: 40px; + border: 1px solid var(--line-strong); + border-radius: 12px; + color: var(--accent); + font-family: var(--font-display); + background: rgba(103, 213, 255, 0.08); +} + +.back-link { + padding: 0 16px; + border: 1px solid var(--line); + color: var(--muted); + background: rgba(255, 255, 255, 0.04); +} + +.back-link:hover, +.primary-action:hover { + border-color: var(--line-strong); + color: var(--text); +} + +.notice-hero { + display: grid; + grid-template-columns: minmax(0, 1fr) 280px; + gap: 22px; + align-items: stretch; + margin-bottom: 22px; +} + +.hero-copy, +.status-panel, +.notice-card, +.side-card { + border: 1px solid var(--line); + background: var(--panel); + box-shadow: 0 28px 60px rgba(0, 0, 0, 0.32); + backdrop-filter: blur(18px); +} + +.hero-copy { + padding: clamp(28px, 5vw, 54px); + border-radius: 24px; +} + +.eyebrow { + display: inline-block; + margin-bottom: 14px; + color: var(--accent); + font-family: var(--font-display); + font-size: 12px; + font-weight: 700; + letter-spacing: 0.08em; + text-transform: uppercase; +} + +h1, +h2, +p { + margin-top: 0; +} + +h1 { + margin-bottom: 16px; + font-size: clamp(34px, 6vw, 64px); + line-height: 1.05; +} + +.hero-copy p { + max-width: 760px; + margin-bottom: 0; + color: var(--muted); + font-size: 17px; + line-height: 1.8; +} + +.status-panel { + display: flex; + min-height: 240px; + flex-direction: column; + justify-content: space-between; + padding: 24px; + border-radius: 24px; +} + +.status-badge { + width: max-content; + padding: 7px 12px; + border-radius: 999px; + color: #06111f; + background: var(--warning); + font-size: 13px; + font-weight: 800; +} + +.status-code { + color: var(--accent); + font-family: var(--font-display); + font-size: 44px; + font-weight: 700; +} + +.status-panel p { + margin-bottom: 0; + color: var(--muted); +} + +.notice-layout { + display: grid; + grid-template-columns: minmax(0, 1fr) 320px; + gap: 22px; + align-items: start; +} + +.notice-card, +.side-card { + border-radius: 20px; +} + +.notice-card { + padding: clamp(24px, 4vw, 40px); +} + +.notice-meta { + display: flex; + flex-wrap: wrap; + gap: 10px; + margin-bottom: 22px; +} + +.notice-meta span, +.info-label { + color: var(--muted); + font-size: 13px; +} + +.notice-meta span { + padding: 6px 10px; + border: 1px solid var(--line); + border-radius: 999px; + background: rgba(255, 255, 255, 0.04); +} + +.notice-card h2, +.side-card h2 { + margin-bottom: 12px; + font-size: 24px; +} + +.notice-card p, +.side-card p { + color: var(--muted); + line-height: 1.8; +} + +.info-grid { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 12px; + margin-top: 30px; +} + +.info-grid div { + min-height: 92px; + padding: 16px; + border: 1px solid var(--line); + border-radius: 16px; + background: rgba(255, 255, 255, 0.04); +} + +.info-grid strong { + display: block; + margin-top: 8px; + font-size: 16px; +} + +.side-card { + padding: 24px; +} + +code { + color: var(--accent); + font-family: Consolas, "Courier New", monospace; +} + +.primary-action { + justify-content: center; + width: 100%; + margin-top: 14px; + padding: 0 18px; + border: 1px solid rgba(45, 226, 166, 0.5); + color: #06111f; + background: linear-gradient(135deg, var(--accent), var(--accent-strong)); + font-weight: 800; +} + +@media (max-width: 840px) { + .notice-hero, + .notice-layout { + grid-template-columns: 1fr; + } + + .status-panel { + min-height: 180px; + } + + .info-grid { + grid-template-columns: 1fr; + } +} + +/* Light visual refresh for notice detail */ +html { + color-scheme: light; +} + +body { + color: #172033; + background: + linear-gradient(135deg, rgba(236, 248, 255, 0.92), rgba(255, 255, 255, 0.96) 48%, rgba(245, 250, 255, 0.94)), + linear-gradient(90deg, rgba(37, 99, 235, 0.045) 1px, transparent 1px), + linear-gradient(0deg, rgba(20, 184, 166, 0.035) 1px, transparent 1px); + background-size: auto, 52px 52px, 52px 52px; +} + +.brand { + color: #172033; +} + +.brand-mark { + color: #2563eb; + background: rgba(37, 99, 235, 0.07); + border-color: rgba(37, 99, 235, 0.2); +} + +.back-link { + color: #66758a; + background: #ffffff; + border-color: rgba(120, 144, 176, 0.24); +} + +.back-link:hover, +.primary-action:hover { + color: #172033; + border-color: rgba(37, 99, 235, 0.36); +} + +.hero-copy, +.status-panel, +.notice-card, +.side-card { + background: rgba(255, 255, 255, 0.84); + border-color: rgba(120, 144, 176, 0.24); + box-shadow: 0 18px 44px rgba(47, 74, 112, 0.12); + backdrop-filter: blur(16px); +} + +.eyebrow, +.status-code, +code { + color: #2563eb; +} + +h1, +h2, +.info-grid strong { + color: #172033; +} + +.hero-copy p, +.status-panel p, +.notice-card p, +.side-card p, +.notice-meta span, +.info-label { + color: #66758a; +} + +.status-badge { + color: #854d0e; + background: #fef3c7; +} + +.notice-meta span, +.info-grid div { + background: rgba(248, 251, 255, 0.86); + border-color: rgba(120, 144, 176, 0.2); +} + +.primary-action { + color: #ffffff; + background: linear-gradient(135deg, #2563eb, #0891b2); + border-color: rgba(37, 99, 235, 0.16); + box-shadow: 0 12px 24px rgba(37, 99, 235, 0.16); +} + +/* Youthful unified layout refresh */ +:root { + --joy-blue: #2563eb; + --joy-cyan: #06b6d4; + --joy-mint: #10b981; + --joy-coral: #fb7185; + --joy-yellow: #facc15; + --joy-ink: #172033; + --joy-muted: #627187; + --joy-line: rgba(96, 116, 148, 0.18); + --joy-card: rgba(255, 255, 255, 0.9); +} + +body { + background: + linear-gradient(128deg, rgba(255, 255, 255, 0.96) 0 34%, rgba(232, 249, 255, 0.9) 34% 58%, rgba(255, 246, 249, 0.92) 58% 100%), + linear-gradient(90deg, rgba(37, 99, 235, 0.04) 1px, transparent 1px), + linear-gradient(0deg, rgba(16, 185, 129, 0.035) 1px, transparent 1px); + background-size: auto, 44px 44px, 44px 44px; +} + +.notice-page { + padding-top: 24px; +} + +.topbar { + margin-bottom: 22px; +} + +.brand-mark { + border-radius: 10px; + color: #ffffff; + background: linear-gradient(135deg, var(--joy-blue), var(--joy-coral)); + border-color: transparent; +} + +.back-link { + min-height: 38px; + border-radius: 12px; +} + +.notice-hero { + grid-template-columns: minmax(0, 1fr) minmax(220px, 0.28fr); + gap: 16px; + margin-bottom: 16px; +} + +.notice-layout { + grid-template-columns: minmax(0, 1fr) minmax(260px, 0.34fr); + gap: 16px; +} + +.hero-copy, +.status-panel, +.notice-card, +.side-card { + border-radius: 18px; + border-color: var(--joy-line); + background: var(--joy-card); + box-shadow: 0 16px 34px rgba(37, 63, 101, 0.1); +} + +.hero-copy { + min-height: 250px; + display: grid; + align-content: center; + padding: clamp(26px, 5vw, 48px); +} + +.hero-copy, +.notice-card, +.side-card, +.status-panel { + position: relative; + overflow: hidden; +} + +.hero-copy::after, +.notice-card::after, +.side-card::after, +.status-panel::after { + content: ""; + position: absolute; + left: 0; + right: 0; + bottom: 0; + height: 4px; + background: linear-gradient(90deg, var(--joy-blue), var(--joy-cyan), var(--joy-mint), var(--joy-coral)); + pointer-events: none; +} + +.eyebrow { + width: max-content; + padding: 8px 14px; + border-radius: 999px; + background: linear-gradient(135deg, rgba(37, 99, 235, 0.11), rgba(6, 182, 212, 0.11)); + color: var(--joy-blue); + letter-spacing: 0.12em; +} + +h1 { + letter-spacing: 0; +} + +.status-panel { + position: relative; + min-height: 250px; + justify-content: center; + gap: 22px; + border-top: 5px solid var(--joy-coral); +} + +.status-code { + color: var(--joy-coral); + font-size: clamp(34px, 4vw, 44px); +} + +.status-badge, +.notice-meta span { + border: 0; +} + +.status-badge { + color: #8a4b05; + background: #fff2bf; +} + +.notice-meta span, +.info-grid div { + border-radius: 14px; + background: #f8fbff; + border-color: rgba(96, 116, 148, 0.12); +} + +.notice-card, +.side-card { + padding: clamp(22px, 4vw, 34px); +} + +.info-grid { + gap: 10px; + margin-top: 24px; +} + +.primary-action { + min-height: 46px; + border-radius: 12px; + background: linear-gradient(135deg, var(--joy-blue), var(--joy-cyan)); +} + +@media (max-width: 520px) { + .notice-page { + width: min(calc(100% - 20px), 1120px); + padding-top: 16px; + } + + .topbar { + align-items: flex-start; + flex-direction: column; + margin-bottom: 22px; + } + + .hero-copy, + .status-panel, + .notice-card, + .side-card { + border-radius: 16px; + } +} diff --git a/2000s/css/style.css b/2000s/css/style.css new file mode 100644 index 0000000..2742f43 --- /dev/null +++ b/2000s/css/style.css @@ -0,0 +1,186 @@ +/* =========================================== + 1. 通用响应式底座 (所有样式均需依赖) + =========================================== */ +:root { + --text-color: #333; + --paper-bg: #fff; + --wish-color: #333; + --border-color: #ddd; + --font-family-base: "Noto Serif SC", serif; + --font-family-sig: "Noto Serif SC", serif; /* 默认署名字体 */ +} + +body { + margin: 0; + padding: 20px; + background-color: #f6f6f6; /* 默认外背景 */ + font-family: var(--font-family-base); + color: var(--text-color); + display: flex; + justify-content: center; + transition: background 0.3s; +} + +/* 自适应容器 */ +.letter-container { + width: 100%; + max-width: 800px; + min-height: 85vh; + padding: 5% 7%; + box-sizing: border-box; + position: relative; + box-shadow: 0 4px 15px rgba(0,0,0,0.05); + background-color: var(--paper-bg); + border: 1px solid var(--border-color); + transition: all 0.3s ease; +} + +/* 手机端适配 */ +@media (max-width: 600px) { + body { padding: 10px; } + .letter-container { padding: 35px 20px; } +} + +/* 传统书信格式公共逻辑 */ +.salutation { + font-size: 1.2rem; + margin-top: 0; + margin-bottom: 1.5rem; + font-weight: bold; +} + +.content p { + text-indent: 2em; /* 首行缩进 */ + line-height: 1.8; + text-align: justify; + margin-bottom: 1rem; +} + +.closing { margin-top: 2.5rem; } +.wish-prefix { text-indent: 2em; margin: 0; color: var(--wish-color); } +.wish-suffix { font-weight: bold; margin-top: 5px; color: var(--wish-color); } + +.footer { + text-align: right; + margin-top: 4rem; + line-height: 1.6; +} + +.signature { + font-size: 1.1em; + font-family: var(--font-family-sig); +} + +.text-right { + text-align: right; +} + +/* =========================================== + 2. 原始场景皮肤 (Modern, Traditional, Vintage) + =========================================== */ +/* ... (保留你之前的定义,此处略以节省空间,直接写新的) ... */ +.theme-modern { --paper-bg: #fff; border-top: 4px solid #333; } +.theme-traditional { --paper-bg: #fdfaf2; writing-mode: vertical-rl; height: 650px; } +@media (max-width: 600px) { .theme-traditional { writing-mode: horizontal-tb; height: auto; } } +.theme-vintage { --paper-bg: #fff; border: 2px solid #b71c1c; background-image: repeating-linear-gradient(transparent, transparent 31px, rgba(183, 28, 28, 0.1) 31px, rgba(183, 28, 28, 0.1) 32px); line-height: 32px; --text-color: #b71c1c; --wish-color: #b71c1c; } + + +/* =========================================== + 3. [新增] 青春与多样场景皮肤 + =========================================== */ + +/* --- A. 青春派对 (Youthful) --- */ +/* 特点:明亮多彩、活力、柔和 */ +.theme-youth { + --paper-bg: #fff; + --text-color: #4a4a4a; + --wish-color: #ff6b6b; /* 鲜艳的颜色 */ + --border-color: #ffe0e0; + font-family: "PingFang SC", "Microsoft YaHei", sans-serif; /* 使用现代无衬线字体 */ + + border-radius: 15px; /* 圆角增加亲和力 */ + border: 3px solid #ffe0e0; +} + +/* 装饰:顶部和底部加点彩色条纹 */ +.theme-youth::before { + content: ""; + position: absolute; + top: 0; left: 0; right: 0; height: 8px; + background: linear-gradient(90deg, #ff6b6b, #feca57, #48dbfb, #ff9f43); + border-radius: 15px 15px 0 0; +} + +.theme-youth .salutation { color: #222; } +.theme-youth .content p { text-indent: 0; text-align: left; background-color: #fcfcfc; padding: 10px; border-radius: 8px; margin-bottom: 1.2rem; } /* 类似气泡感 */ +.theme-youth .wish-prefix { text-indent: 0; padding-left: 1rem; } /* 青春风不一定强制缩进 */ +.theme-youth .wish-suffix { font-weight: 800; font-size: 1.1rem; } +.theme-youth .footer { color: #888; } +.theme-youth .signature { color: #333; font-weight: bold; } + + +/* --- B. 青葱校园 (Campus) --- */ +/* 特点:数学格子纸、怀旧、清爽蓝调 */ +.theme-campus { + --paper-bg: #fdfdfd; + --text-color: #3e3e3e; + --wish-color: #2980b9; /* 校园蓝 */ + --border-color: #87ceeb; + font-family: "SimSun", serif; /* 怀旧宋体 */ + + /* 模拟蓝格子纸 */ + background-image: + linear-gradient(rgba(135, 206, 235, 0.3) 1px, transparent 1px), + linear-gradient(90deg, rgba(135, 206, 235, 0.3) 1px, transparent 1px); + background-size: 25px 25px; /* 格子大小 */ +} + +/* 顶部加一个类似书签或校徽的圆 */ +.theme-campus::after { + content: "CAMPUS"; + position: absolute; + top: -15px; right: 30px; + background-color: #2980b9; + color: white; + padding: 5px 15px; + border-radius: 20px; + font-size: 0.8rem; + font-family: sans-serif; +} + +.theme-campus .content p { line-height: 1.6; text-indent: 2em; } +.theme-campus .closing { border-top: 1px dashed rgba(135, 206, 235, 0.5); padding-top: 1rem; } +.theme-campus .footer .date { color: #888; } + + +/* --- C. 极简和风 (Wabi-Sabi / Minimalist) --- */ +/* 特点:淡雅、素净、极低对比度、高端商务或长辈 */ +.theme-wabi { + --paper-bg: #fafafa; + --text-color: #555; + --wish-color: #777; + --border-color: transparent; /* 无边框 */ + font-family: "Source Han Serif SC", serif; /* 高质量宋体 */ + + background-color: #fff; + padding: 8% 10%; /* 更宽松的内边距 */ + border-radius: 0; + box-shadow: none; /* 去掉阴影,极度扁平 */ +} + +/* 手机端去掉过于宽松的内边距 */ +@media (max-width: 600px) { + .theme-wabi { padding: 40px 20px; } +} + +/* 装饰:只在底部加一条极淡的灰线 */ +.theme-wabi .footer { + text-align: right; + border-top: 1px solid #f0f0f0; + padding-top: 1.5rem; +} + +.theme-wabi .salutation { font-weight: normal; font-size: 1.2rem; color: #333; } +.theme-wabi .content p { text-indent: 2em; line-height: 2; color: #666; font-size: 0.95rem; } +.theme-wabi .wish-suffix { font-weight: normal; color: #777; } +.theme-wabi .signature { font-family: "Zhi Mang Xing", cursive; font-size: 1.8rem; color: #333; } /* 使用Google Font书法字体 */ diff --git a/2000s/css/tech-query.css b/2000s/css/tech-query.css new file mode 100644 index 0000000..4a608e5 --- /dev/null +++ b/2000s/css/tech-query.css @@ -0,0 +1,1710 @@ +:root { + --bg-primary: #07111f; + --bg-secondary: #0d1b31; + --panel: rgba(9, 20, 40, 0.78); + --panel-strong: rgba(10, 24, 46, 0.92); + --line: rgba(98, 180, 255, 0.22); + --line-strong: rgba(98, 180, 255, 0.45); + --text-primary: #ecf6ff; + --text-secondary: #93afd1; + --accent: #67d5ff; + --accent-strong: #3ea2ff; + --accent-soft: rgba(103, 213, 255, 0.14); + --success: #2de2a6; + --warning: #ffcc66; + --danger: #ff6b8a; + --shadow: 0 28px 60px rgba(0, 0, 0, 0.35); + --radius-xl: 28px; + --radius-lg: 20px; + --radius-md: 14px; + --radius-sm: 10px; + --content-width: 1180px; + --grid-gap: 18px; + --font-display: "Orbitron", "Segoe UI", sans-serif; + --font-body: "Noto Sans SC", "Segoe UI", sans-serif; +} + +* { + box-sizing: border-box; +} + +html { + color-scheme: dark; +} + +body { + margin: 0; + min-height: 100vh; + color: var(--text-primary); + font-family: var(--font-body); + background: + radial-gradient(circle at top left, rgba(62, 162, 255, 0.18), transparent 28%), + radial-gradient(circle at top right, rgba(45, 226, 166, 0.08), transparent 22%), + linear-gradient(135deg, #040914 0%, #07111f 45%, #0a1730 100%); + position: relative; + overflow-x: hidden; +} + +body::before, +body::after { + content: ""; + position: fixed; + inset: 0; + pointer-events: none; + z-index: -1; +} + +body::before { + background-image: + linear-gradient(rgba(103, 213, 255, 0.06) 1px, transparent 1px), + linear-gradient(90deg, rgba(103, 213, 255, 0.06) 1px, transparent 1px); + background-size: 42px 42px; + mask-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.65), transparent 92%); +} + +body::after { + background: + radial-gradient(circle at 20% 20%, rgba(103, 213, 255, 0.08), transparent 16%), + radial-gradient(circle at 80% 35%, rgba(103, 213, 255, 0.05), transparent 18%); +} + +a { + color: inherit; +} + +.is-hidden { + display: none; +} + +.mt-18 { + margin-top: 18px; +} + +.page-shell { + width: min(calc(100% - 32px), var(--content-width)); + margin: 0 auto; + padding: 36px 0 48px; +} + +.page-header { + display: grid; + gap: 18px; + grid-template-columns: 1.35fr 0.85fr; + align-items: stretch; + margin-bottom: 24px; +} + +.hero-card, +.stat-card, +.panel-card { + position: relative; + overflow: hidden; + background: linear-gradient(180deg, rgba(10, 24, 46, 0.9), rgba(7, 18, 35, 0.82)); + border: 1px solid var(--line); + border-radius: var(--radius-xl); + box-shadow: var(--shadow); + backdrop-filter: blur(18px); +} + +.hero-card { + padding: 32px; +} + +.hero-card::before, +.stat-card::before, +.panel-card::before, +.entry-card::before { + content: ""; + position: absolute; + inset: 0; + background: linear-gradient(135deg, rgba(103, 213, 255, 0.12), transparent 42%, rgba(103, 213, 255, 0.06)); + pointer-events: none; +} + +.eyebrow { + display: inline-flex; + align-items: center; + gap: 10px; + padding: 8px 14px; + border-radius: 999px; + border: 1px solid rgba(103, 213, 255, 0.28); + background: rgba(103, 213, 255, 0.08); + color: var(--accent); + font-size: 12px; + letter-spacing: 0.24em; + text-transform: uppercase; +} + +.hero-card h1, +.landing-hero h1 { + margin: 18px 0 12px; + font-family: var(--font-display); + font-size: clamp(28px, 4.4vw, 48px); + line-height: 1.08; + letter-spacing: 0.06em; +} + +.hero-card p, +.landing-hero p, +.stat-card p, +.panel-subtitle, +.empty-state, +.loading-state, +.error-state { + color: var(--text-secondary); +} + +.hero-meta { + display: flex; + flex-wrap: wrap; + gap: 12px; + margin-top: 22px; +} + +.meta-chip { + padding: 10px 14px; + border-radius: 999px; + background: rgba(255, 255, 255, 0.04); + border: 1px solid rgba(147, 175, 209, 0.14); + font-size: 13px; + color: var(--text-primary); +} + +.stat-card { + padding: 28px; + display: flex; + flex-direction: column; + justify-content: space-between; + gap: 18px; +} + +.stat-label { + color: var(--text-secondary); + font-size: 13px; + letter-spacing: 0.18em; + text-transform: uppercase; +} + +.stat-value { + font-family: var(--font-display); + font-size: clamp(28px, 4vw, 44px); + color: var(--accent); + text-shadow: 0 0 18px rgba(103, 213, 255, 0.28); +} + +.panel-card { + padding: 24px; +} + +.panel-title-row { + display: flex; + justify-content: space-between; + gap: 16px; + align-items: center; + margin-bottom: 18px; +} + +.panel-title { + margin: 0; + font-size: 20px; + font-weight: 700; + letter-spacing: 0.04em; +} + +.search-grid { + display: grid; + grid-template-columns: repeat(4, minmax(0, 1fr)); + gap: var(--grid-gap); + align-items: end; +} + +.search-grid.compact { + grid-template-columns: repeat(5, minmax(0, 1fr)); +} + +.form-group { + display: flex; + flex-direction: column; + gap: 8px; +} + +.form-label { + color: var(--text-secondary); + font-size: 13px; + letter-spacing: 0.06em; +} + +.tech-input, +.tech-button, +.tech-link-button { + border-radius: var(--radius-md); + border: 1px solid var(--line); + min-height: 48px; + font: inherit; +} + +.tech-input { + width: 100%; + padding: 0 16px; + background: rgba(6, 14, 28, 0.8); + color: var(--text-primary); + outline: none; + box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.02); +} + +.tech-input::placeholder { + color: rgba(147, 175, 209, 0.68); +} + +.tech-input:focus { + border-color: var(--line-strong); + box-shadow: 0 0 0 4px rgba(62, 162, 255, 0.14); +} + +.input-with-action { + position: relative; +} + +.input-with-action .tech-input { + padding-right: 56px; +} + +.icon-action { + position: absolute; + right: 8px; + top: 50%; + transform: translateY(-50%); + width: 40px; + height: 40px; + display: inline-flex; + align-items: center; + justify-content: center; + border-radius: 12px; + border: 1px solid transparent; + background: transparent; + color: var(--accent); + cursor: pointer; + transition: transform 0.18s ease, background 0.18s ease, border-color 0.18s ease; +} + +.icon-action:hover { + transform: translateY(-50%) scale(1.04); + background: rgba(103, 213, 255, 0.1); + border-color: rgba(103, 213, 255, 0.18); +} + +.tech-button, +.tech-link-button { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 10px; + padding: 0 20px; + background: linear-gradient(135deg, rgba(103, 213, 255, 0.24), rgba(62, 162, 255, 0.44)); + color: #f7fbff; + font-weight: 700; + letter-spacing: 0.03em; + text-decoration: none; + cursor: pointer; + transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease; +} + +.tech-button:hover, +.tech-link-button:hover { + transform: translateY(-1px); + border-color: rgba(103, 213, 255, 0.4); + box-shadow: 0 12px 30px rgba(62, 162, 255, 0.2); +} + +.tech-button.secondary, +.tech-link-button.secondary { + background: rgba(255, 255, 255, 0.04); + color: var(--text-primary); +} + +.results-card { + min-height: 260px; +} + +.results-shell { + border-radius: var(--radius-lg); + border: 1px solid rgba(103, 213, 255, 0.16); + overflow: hidden; + background: rgba(3, 8, 18, 0.46); +} + +.table-wrapper { + overflow-x: auto; +} + +.results-summary { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 12px; + padding: 16px; + border-bottom: 1px solid rgba(103, 213, 255, 0.12); +} + +.summary-stat-tile { + min-height: 86px; + display: flex; + flex-direction: column; + justify-content: center; + gap: 8px; + padding: 14px 16px; + border-radius: var(--radius-md); + border: 1px solid rgba(103, 213, 255, 0.14); + background: rgba(255, 255, 255, 0.035); +} + +.summary-stat-tile span, +.stats-panel-title, +.muted-note { + color: var(--text-secondary); +} + +.summary-stat-tile span { + font-size: 13px; + letter-spacing: 0.08em; +} + +.summary-stat-tile strong { + font-family: var(--font-display); + font-size: 30px; + color: var(--accent); + line-height: 1; +} + +.stats-grid { + display: grid; + grid-template-columns: minmax(0, 1.1fr) minmax(0, 0.9fr); + gap: 16px; + padding: 0 16px 16px; +} + +.stats-panel { + min-width: 0; + padding: 16px; + border-radius: var(--radius-md); + border: 1px solid rgba(103, 213, 255, 0.14); + background: rgba(255, 255, 255, 0.025); +} + +.stats-panel-title { + margin-bottom: 14px; + font-size: 13px; + font-weight: 700; + letter-spacing: 0.08em; +} + +.bar-chart { + display: grid; + gap: 12px; +} + +.chart-row { + display: grid; + grid-template-columns: minmax(88px, 0.35fr) minmax(120px, 1fr) 56px; + gap: 12px; + align-items: center; +} + +.chart-row-label, +.award-count-title { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.chart-row-label { + color: var(--text-primary); + font-weight: 600; +} + +.chart-bar-track { + height: 12px; + overflow: hidden; + border-radius: 999px; + background: rgba(103, 213, 255, 0.1); +} + +.chart-bar-fill { + height: 100%; + border-radius: inherit; + background: linear-gradient(90deg, var(--accent), var(--success)); + box-shadow: 0 0 18px rgba(103, 213, 255, 0.25); +} + +.chart-row-value { + color: var(--accent); + font-weight: 700; + text-align: right; +} + +.award-count-grid { + display: grid; + gap: 10px; +} + +.award-count-chip { + display: grid; + grid-template-columns: minmax(0, 1fr) auto auto; + gap: 8px; + align-items: center; + padding: 12px 14px; + border-radius: var(--radius-sm); + border: 1px solid rgba(147, 175, 209, 0.14); + background: rgba(3, 8, 18, 0.36); +} + +.award-count-chip strong { + color: var(--success); + font-family: var(--font-display); +} + +.award-count-chip span:last-child { + color: var(--text-secondary); + font-size: 13px; +} + +.muted-note { + padding: 12px 0; + text-align: center; +} + +.result-table { + width: 100%; + min-width: 720px; + border-collapse: collapse; +} + +.result-table th, +.result-table td { + padding: 16px 18px; + border-bottom: 1px solid rgba(103, 213, 255, 0.08); + text-align: left; +} + +.result-table th { + background: rgba(103, 213, 255, 0.08); + color: var(--text-secondary); + font-size: 13px; + font-weight: 600; + letter-spacing: 0.08em; + text-transform: uppercase; +} + +.result-table td { + color: var(--text-primary); + background: rgba(255, 255, 255, 0.01); +} + +.result-table tbody tr:hover td { + background: rgba(103, 213, 255, 0.04); +} + +.table-highlight { + color: var(--accent); + font-weight: 700; +} + +.text-truncate { + display: inline-block; + max-width: 220px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + vertical-align: bottom; +} + +.status-pill { + display: inline-flex; + align-items: center; + gap: 8px; + padding: 8px 12px; + border-radius: 999px; + font-size: 13px; + font-weight: 700; + line-height: 1; + border: 1px solid transparent; +} + +.status-pill.done { + color: #081a14; + background: rgba(45, 226, 166, 0.9); +} + +.status-pill.pending { + color: #251400; + background: rgba(255, 204, 102, 0.92); +} + +.loading-state, +.empty-state, +.error-state { + min-height: 220px; + display: flex; + align-items: center; + justify-content: center; + text-align: center; + padding: 36px 24px; + font-size: 15px; +} + +.error-state { + color: #ffd7df; +} + +.page-footer { + width: min(calc(100% - 32px), var(--content-width)); + margin: 0 auto 24px; + color: rgba(147, 175, 209, 0.74); + font-size: 13px; + text-align: center; +} + +.scanner-overlay { + display: none; + position: fixed; + inset: 0; + z-index: 9999; + background: rgba(2, 7, 16, 0.92); + backdrop-filter: blur(14px); + align-items: center; + justify-content: center; + flex-direction: column; + gap: 18px; + padding: 24px; +} + +.scanner-frame { + position: relative; + width: min(92vw, 520px); + height: min(54vw, 240px); + min-height: 180px; + border-radius: 28px; + overflow: hidden; + border: 1px solid rgba(103, 213, 255, 0.28); + box-shadow: 0 20px 50px rgba(0, 0, 0, 0.35); + background: #000; +} + +.scanner-frame::before, +.scanner-frame::after { + content: ""; + position: absolute; + inset: 16px; + border: 1px solid rgba(103, 213, 255, 0.25); + border-radius: 18px; + pointer-events: none; +} + +.scanner-line { + position: absolute; + left: 8%; + width: 84%; + height: 2px; + background: linear-gradient(90deg, transparent, var(--accent), transparent); + box-shadow: 0 0 18px rgba(103, 213, 255, 0.7); + animation: scanner-sweep 2.2s linear infinite; + z-index: 2; +} + +@keyframes scanner-sweep { + 0% { + top: 16%; + } + + 100% { + top: 84%; + } +} + +#reader { + width: 100% !important; + height: 100% !important; +} + +.scanner-text { + color: var(--text-secondary); + font-size: 14px; + letter-spacing: 0.04em; +} + +.landing-shell { + width: min(calc(100% - 32px), 1240px); + margin: 0 auto; + padding: 36px 0 48px; +} + +.landing-hero { + position: relative; + padding: 38px; + border-radius: 34px; + overflow: hidden; + background: + linear-gradient(135deg, rgba(10, 24, 46, 0.95), rgba(7, 18, 35, 0.86)), + linear-gradient(90deg, rgba(103, 213, 255, 0.18), transparent); + border: 1px solid var(--line); + box-shadow: var(--shadow); +} + +.landing-grid { + margin-top: 24px; + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 18px; +} + +.entry-card { + position: relative; + overflow: hidden; + display: grid; + gap: 18px; + padding: 24px; + border-radius: 24px; + text-decoration: none; + background: linear-gradient(180deg, rgba(9, 20, 40, 0.88), rgba(7, 18, 35, 0.86)); + border: 1px solid var(--line); + box-shadow: var(--shadow); + transition: transform 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease; +} + +.entry-card:hover { + transform: translateY(-4px); + border-color: rgba(103, 213, 255, 0.4); + box-shadow: 0 24px 48px rgba(0, 0, 0, 0.38); +} + +.entry-kicker { + color: var(--accent); + font-size: 12px; + letter-spacing: 0.22em; + text-transform: uppercase; +} + +.entry-card h2 { + margin: 0; + font-size: 24px; +} + +.entry-card p { + margin: 0; + color: var(--text-secondary); + line-height: 1.7; +} + +.entry-meta { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; + color: var(--text-primary); + font-size: 14px; +} + +.entry-arrow { + width: 42px; + height: 42px; + border-radius: 999px; + display: inline-flex; + align-items: center; + justify-content: center; + background: rgba(103, 213, 255, 0.12); + color: var(--accent); +} + +.detail-shell { + width: min(calc(100% - 32px), 1120px); + margin: 0 auto; + padding: 28px 0 48px; +} + +.top-actions { + display: flex; + justify-content: space-between; + align-items: center; + gap: 14px; + margin-bottom: 18px; +} + +.top-actions-group { + display: flex; + flex-wrap: wrap; + gap: 12px; +} + +.detail-grid { + display: grid; + grid-template-columns: 1.1fr 0.9fr; + gap: 18px; +} + +.preview-panel, +.summary-panel, +.detail-panel { + position: relative; + overflow: hidden; + border-radius: var(--radius-xl); + border: 1px solid var(--line); + background: linear-gradient(180deg, rgba(10, 24, 46, 0.92), rgba(7, 18, 35, 0.84)); + box-shadow: var(--shadow); +} + +.preview-panel, +.summary-panel, +.detail-panel { + padding: 24px; +} + +.preview-panel::before, +.summary-panel::before, +.detail-panel::before { + content: ""; + position: absolute; + inset: 0; + background: linear-gradient(135deg, rgba(103, 213, 255, 0.08), transparent 45%, rgba(103, 213, 255, 0.05)); + pointer-events: none; +} + +.section-kicker { + color: var(--accent); + font-size: 12px; + letter-spacing: 0.22em; + text-transform: uppercase; +} + +.section-heading { + margin: 12px 0 10px; + font-size: 26px; + line-height: 1.2; +} + +.section-copy { + margin: 0; + color: var(--text-secondary); + line-height: 1.75; +} + +.summary-stack { + display: grid; + gap: 14px; + margin-top: 20px; +} + +.summary-tile { + padding: 16px 18px; + border-radius: 18px; + background: rgba(255, 255, 255, 0.03); + border: 1px solid rgba(103, 213, 255, 0.12); +} + +.summary-label { + display: block; + margin-bottom: 8px; + color: var(--text-secondary); + font-size: 12px; + letter-spacing: 0.08em; + text-transform: uppercase; +} + +.summary-value { + font-size: 18px; + font-weight: 700; + color: var(--text-primary); + word-break: break-word; +} + +.summary-value.emphasis { + color: var(--accent); +} + +.certificate-stage { + position: relative; + min-height: 520px; + display: flex; + align-items: center; + justify-content: center; + border-radius: 24px; + border: 1px solid rgba(103, 213, 255, 0.14); + background: #ffffff; + overflow: hidden; + cursor: pointer; +} + +.certificate-stage img { + width: 100%; + height: auto; + display: none; + position: relative; + z-index: 1; +} + +.certificate-hint { + position: absolute; + inset: 0; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 12px; + text-align: center; + color: #64748b; + padding: 24px; +} + +.certificate-hint strong { + color: #0f172a; + font-size: 18px; +} + +.hint-orb { + width: 72px; + height: 72px; + border-radius: 999px; + display: inline-flex; + align-items: center; + justify-content: center; + background: rgba(103, 213, 255, 0.1); + border: 1px solid rgba(103, 213, 255, 0.18); + color: var(--accent); + font-size: 30px; + box-shadow: 0 0 24px rgba(103, 213, 255, 0.12); +} + +.info-table-shell { + overflow: hidden; + border-radius: 20px; + border: 1px solid rgba(103, 213, 255, 0.14); + background: rgba(3, 8, 18, 0.4); +} + +.info-table { + width: 100%; + border-collapse: collapse; +} + +.info-table th, +.info-table td { + padding: 16px 18px; + border-bottom: 1px solid rgba(103, 213, 255, 0.08); + text-align: left; + vertical-align: top; +} + +.info-table th { + width: 28%; + color: var(--text-secondary); + font-size: 13px; + font-weight: 600; + letter-spacing: 0.06em; + text-transform: uppercase; + background: rgba(103, 213, 255, 0.06); +} + +.info-table td { + color: var(--text-primary); + line-height: 1.7; +} + +.ticket-header { + display: flex; + justify-content: space-between; + gap: 16px; + align-items: flex-start; + margin-bottom: 20px; +} + +.ticket-title { + margin: 10px 0 6px; + font-size: clamp(26px, 4vw, 36px); + line-height: 1.16; +} + +.ticket-subtitle { + margin: 0; + color: var(--text-secondary); +} + +.ticket-detail-grid { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 14px; +} + +.detail-item { + padding: 16px 18px; + border-radius: 18px; + background: rgba(255, 255, 255, 0.03); + border: 1px solid rgba(103, 213, 255, 0.12); +} + +.detail-item.wide { + grid-column: 1 / -1; +} + +.detail-label { + display: block; + margin-bottom: 8px; + color: var(--text-secondary); + font-size: 12px; + letter-spacing: 0.08em; + text-transform: uppercase; +} + +.detail-value { + color: var(--text-primary); + font-size: 16px; + line-height: 1.65; + word-break: break-word; +} + +.detail-value.money { + color: var(--accent); + font-weight: 700; +} + +.feedback-card { + min-height: 220px; + display: flex; + align-items: center; + justify-content: center; + text-align: center; + color: var(--text-secondary); + font-size: 15px; +} + +@media (max-width: 1040px) { + .page-header, + .landing-grid, + .detail-grid { + grid-template-columns: 1fr; + } + + .search-grid, + .search-grid.compact { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } +} + +@media (max-width: 720px) { + .page-shell, + .landing-shell, + .detail-shell { + width: min(calc(100% - 20px), var(--content-width)); + padding-top: 20px; + } + + .hero-card, + .stat-card, + .panel-card, + .landing-hero, + .entry-card, + .preview-panel, + .summary-panel, + .detail-panel { + border-radius: 22px; + } + + .hero-card, + .landing-hero, + .panel-card, + .entry-card, + .preview-panel, + .summary-panel, + .detail-panel { + padding: 20px; + } + + .search-grid, + .search-grid.compact { + grid-template-columns: 1fr; + } + + .results-summary, + .stats-grid { + grid-template-columns: 1fr; + } + + .chart-row { + grid-template-columns: minmax(74px, 0.4fr) minmax(90px, 1fr) 52px; + gap: 8px; + } + + .result-table { + min-width: 620px; + } + + .ticket-header, + .top-actions { + flex-direction: column; + align-items: stretch; + } + + .ticket-detail-grid { + grid-template-columns: 1fr; + } + + .certificate-stage { + min-height: 360px; + } +} + +/* Light visual refresh for query modules */ +html { + color-scheme: light; +} + +body { + background: + linear-gradient(135deg, rgba(236, 248, 255, 0.92), rgba(255, 255, 255, 0.96) 48%, rgba(245, 250, 255, 0.94)), + linear-gradient(90deg, rgba(37, 99, 235, 0.045) 1px, transparent 1px), + linear-gradient(0deg, rgba(20, 184, 166, 0.035) 1px, transparent 1px); + background-size: auto, 52px 52px, 52px 52px; + color: #172033; +} + +body::before { + background: + linear-gradient(120deg, rgba(37, 99, 235, 0.08), transparent 34%), + linear-gradient(300deg, rgba(20, 184, 166, 0.06), transparent 32%); + mask-image: none; +} + +body::after { + background: linear-gradient(180deg, rgba(255, 255, 255, 0.64), transparent 62%); +} + +.hero-card, +.stat-card, +.panel-card, +.landing-hero, +.entry-card, +.preview-panel, +.summary-panel, +.detail-panel { + background: rgba(255, 255, 255, 0.84); + border-color: rgba(120, 144, 176, 0.24); + box-shadow: 0 18px 44px rgba(47, 74, 112, 0.12); + backdrop-filter: blur(16px); +} + +.hero-card::before, +.stat-card::before, +.panel-card::before, +.entry-card::before, +.preview-panel::before, +.summary-panel::before, +.detail-panel::before { + background: linear-gradient(135deg, rgba(37, 99, 235, 0.07), transparent 46%, rgba(20, 184, 166, 0.06)); +} + +.eyebrow, +.entry-kicker, +.section-kicker, +.stat-value, +.summary-stat-tile strong, +.chart-row-value, +.table-highlight, +.summary-value.emphasis, +.detail-value.money, +.hint-orb { + color: #2563eb; + text-shadow: none; +} + +.hero-card h1, +.landing-hero h1, +.panel-title, +.entry-card h2, +.section-heading, +.ticket-title, +.chart-row-label, +.summary-value, +.detail-value, +.info-table td, +.result-table td { + color: #172033; +} + +.hero-card p, +.landing-hero p, +.entry-card p, +.stat-card p, +.panel-subtitle, +.empty-state, +.loading-state, +.scanner-text, +.ticket-subtitle, +.section-copy, +.summary-label, +.detail-label, +.form-label, +.stats-panel-title, +.muted-note, +.award-count-chip span:last-child, +.info-table th, +.page-footer { + color: #66758a; +} + +.eyebrow { + border-color: rgba(37, 99, 235, 0.18); + background: rgba(37, 99, 235, 0.07); +} + +.meta-chip, +.summary-stat-tile, +.stats-panel, +.award-count-chip, +.summary-tile, +.detail-item { + background: rgba(248, 251, 255, 0.86); + border-color: rgba(120, 144, 176, 0.2); + color: #172033; +} + +.tech-input { + background: #ffffff; + border-color: rgba(120, 144, 176, 0.32); + color: #172033; + box-shadow: 0 1px 2px rgba(47, 74, 112, 0.04); +} + +.tech-input::placeholder { + color: #94a3b8; +} + +.tech-input:focus { + border-color: rgba(37, 99, 235, 0.55); + box-shadow: 0 0 0 4px rgba(37, 99, 235, 0.1); +} + +.icon-action { + color: #2563eb; +} + +.icon-action:hover, +.entry-arrow { + background: rgba(37, 99, 235, 0.08); + border-color: rgba(37, 99, 235, 0.16); +} + +.tech-button, +.tech-link-button { + background: linear-gradient(135deg, #2563eb, #0891b2); + border-color: rgba(37, 99, 235, 0.16); + color: #ffffff; + box-shadow: 0 12px 24px rgba(37, 99, 235, 0.16); +} + +.tech-button:hover, +.tech-link-button:hover { + border-color: rgba(37, 99, 235, 0.36); + box-shadow: 0 14px 28px rgba(37, 99, 235, 0.2); +} + +.tech-button.secondary, +.tech-link-button.secondary { + background: #ffffff; + color: #172033; +} + +.results-shell, +.info-table-shell { + background: rgba(255, 255, 255, 0.72); + border-color: rgba(120, 144, 176, 0.2); +} + +.results-summary, +.result-table th, +.result-table td, +.info-table th, +.info-table td { + border-color: rgba(120, 144, 176, 0.16); +} + +.result-table th, +.info-table th { + background: rgba(37, 99, 235, 0.06); +} + +.result-table td { + background: rgba(255, 255, 255, 0.56); +} + +.result-table tbody tr:hover td { + background: rgba(37, 99, 235, 0.055); +} + +.chart-bar-track { + background: rgba(37, 99, 235, 0.12); +} + +.chart-bar-fill { + background: linear-gradient(90deg, #2563eb, #14b8a6); + box-shadow: none; +} + +.award-count-chip strong { + color: #047857; +} + +.status-pill.done { + color: #064e3b; + background: #bbf7d0; +} + +.status-pill.pending { + color: #854d0e; + background: #fef3c7; +} + +.error-state { + color: #be123c; +} + +.certificate-stage { + border-color: rgba(120, 144, 176, 0.18); + box-shadow: inset 0 0 0 1px rgba(120, 144, 176, 0.08); +} + +.scanner-overlay { + background: rgba(241, 247, 255, 0.92); +} + +.scanner-frame { + border-color: rgba(37, 99, 235, 0.28); + box-shadow: 0 20px 50px rgba(47, 74, 112, 0.22); +} + +.scanner-frame::before, +.scanner-frame::after { + border-color: rgba(37, 99, 235, 0.26); +} + +.scanner-line { + background: linear-gradient(90deg, transparent, #2563eb, transparent); + box-shadow: 0 0 18px rgba(37, 99, 235, 0.48); +} + +/* Youthful unified layout refresh */ +:root { + --joy-blue: #2563eb; + --joy-cyan: #06b6d4; + --joy-mint: #10b981; + --joy-coral: #fb7185; + --joy-yellow: #facc15; + --joy-ink: #172033; + --joy-muted: #627187; + --joy-line: rgba(96, 116, 148, 0.18); + --joy-card: rgba(255, 255, 255, 0.9); +} + +body { + background: + linear-gradient(128deg, rgba(255, 255, 255, 0.96) 0 34%, rgba(232, 249, 255, 0.9) 34% 58%, rgba(255, 246, 249, 0.92) 58% 100%), + linear-gradient(90deg, rgba(37, 99, 235, 0.04) 1px, transparent 1px), + linear-gradient(0deg, rgba(16, 185, 129, 0.035) 1px, transparent 1px); + background-size: auto, 44px 44px, 44px 44px; +} + +body::before { + background: + linear-gradient(110deg, transparent 0 8%, rgba(37, 99, 235, 0.1) 8% 9%, transparent 9% 100%), + linear-gradient(110deg, transparent 0 72%, rgba(251, 113, 133, 0.12) 72% 73%, transparent 73% 100%), + linear-gradient(110deg, transparent 0 84%, rgba(16, 185, 129, 0.1) 84% 85%, transparent 85% 100%); +} + +body::after { + background: + linear-gradient(180deg, rgba(255, 255, 255, 0.5), transparent 54%), + linear-gradient(90deg, rgba(250, 204, 21, 0.08), transparent 28%, rgba(6, 182, 212, 0.06)); +} + +.page-shell, +.landing-shell { + padding-top: 28px; +} + +.page-header { + grid-template-columns: minmax(0, 1fr) minmax(220px, 0.28fr); + gap: 16px; + margin-bottom: 16px; +} + +.hero-card, +.stat-card, +.panel-card, +.landing-hero, +.entry-card, +.preview-panel, +.summary-panel, +.detail-panel { + border-radius: 18px; + border-color: var(--joy-line); + background: var(--joy-card); + box-shadow: 0 16px 34px rgba(37, 63, 101, 0.1); +} + +.hero-card::before, +.stat-card::before, +.panel-card::before, +.entry-card::before, +.preview-panel::before, +.summary-panel::before, +.detail-panel::before { + background: + linear-gradient(135deg, rgba(37, 99, 235, 0.08), transparent 32%), + linear-gradient(315deg, rgba(251, 113, 133, 0.08), transparent 35%); +} + +.hero-card { + padding: 28px; + display: grid; + align-content: center; + min-height: 236px; +} + +.hero-card h1, +.landing-hero h1 { + margin-top: 16px; + letter-spacing: 0; + color: var(--joy-ink); +} + +.hero-card p, +.landing-hero p, +.entry-card p, +.section-copy { + line-height: 1.72; +} + +.eyebrow, +.entry-kicker, +.section-kicker { + border: 0; + border-radius: 999px; + background: linear-gradient(135deg, rgba(37, 99, 235, 0.11), rgba(6, 182, 212, 0.11)); + color: var(--joy-blue); + letter-spacing: 0.12em; + font-weight: 800; +} + +.hero-meta { + gap: 10px; + margin-top: 18px; +} + +.meta-chip { + border: 0; + background: #f8fbff; + box-shadow: inset 0 0 0 1px rgba(96, 116, 148, 0.12); +} + +.stat-card { + padding: 22px; + justify-content: center; + border-top: 5px solid var(--joy-coral); +} + +.stat-card::after, +.panel-card::after, +.entry-card::after { + content: ""; + position: absolute; + left: 0; + right: 0; + bottom: 0; + height: 4px; + background: linear-gradient(90deg, var(--joy-blue), var(--joy-cyan), var(--joy-mint), var(--joy-coral)); + pointer-events: none; +} + +.stat-value { + color: var(--joy-coral); + font-size: clamp(24px, 3vw, 36px); +} + +.panel-card { + padding: 22px; + margin-top: 16px; +} + +.panel-title-row { + margin-bottom: 16px; + padding-bottom: 14px; + border-bottom: 1px solid rgba(96, 116, 148, 0.12); +} + +.panel-title { + letter-spacing: 0; +} + +.search-grid { + grid-template-columns: minmax(260px, 1.5fr) repeat(2, minmax(150px, 0.72fr)) minmax(128px, 0.55fr); +} + +.search-grid.compact { + grid-template-columns: minmax(150px, 0.9fr) minmax(190px, 1.1fr) repeat(2, minmax(140px, 0.72fr)) minmax(128px, 0.55fr); +} + +.tech-input, +.tech-button, +.tech-link-button { + min-height: 46px; + border-radius: 12px; +} + +.tech-input { + background: #fbfdff; +} + +.tech-button, +.tech-link-button { + background: linear-gradient(135deg, var(--joy-blue), var(--joy-cyan)); + box-shadow: 0 12px 22px rgba(37, 99, 235, 0.18); +} + +.tech-button.secondary, +.tech-link-button.secondary { + background: #ffffff; + box-shadow: inset 0 0 0 1px rgba(96, 116, 148, 0.16); +} + +.results-shell, +.info-table-shell { + border-radius: 16px; +} + +.empty-state, +.loading-state, +.feedback-card { + min-height: 180px; + background: + linear-gradient(135deg, rgba(37, 99, 235, 0.045), transparent 42%), + linear-gradient(315deg, rgba(251, 113, 133, 0.05), transparent 36%); +} + +.result-table th { + background: #f3f8ff; + color: #4f5f74; +} + +.result-table tbody tr:nth-child(even) td { + background: rgba(248, 251, 255, 0.72); +} + +.status-pill.done { + color: #066047; + background: #d8fff0; +} + +.status-pill.pending { + color: #8a4b05; + background: #fff2bf; +} + +.landing-hero { + min-height: 260px; + padding: clamp(28px, 5vw, 54px); + display: grid; + align-content: end; + border-top: 5px solid var(--joy-blue); +} + +.landing-grid { + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 16px; +} + +.entry-card { + min-height: 246px; + align-content: space-between; + transform: translateY(0); +} + +.entry-card:nth-child(2) { + border-top: 5px solid var(--joy-mint); +} + +.entry-card:nth-child(3) { + border-top: 5px solid var(--joy-coral); +} + +.entry-card:hover { + transform: translateY(-6px); + box-shadow: 0 22px 42px rgba(37, 63, 101, 0.14); +} + +.entry-meta { + padding-top: 12px; + border-top: 1px solid rgba(96, 116, 148, 0.12); +} + +.entry-arrow { + color: #ffffff; + background: linear-gradient(135deg, var(--joy-blue), var(--joy-coral)); +} + +.detail-grid { + grid-template-columns: minmax(0, 1.05fr) minmax(280px, 0.72fr); +} + +.summary-stack, +.ticket-detail-grid { + gap: 12px; +} + +.summary-tile, +.detail-item, +.summary-stat-tile, +.stats-panel, +.award-count-chip { + border-radius: 14px; + background: #f8fbff; +} + +.certificate-stage { + border-radius: 16px; +} + +@media (max-width: 1040px) { + .page-header, + .landing-grid, + .detail-grid, + .search-grid, + .search-grid.compact { + grid-template-columns: 1fr; + } + + .stat-card { + min-height: 118px; + } +} + +@media (max-width: 720px) { + .page-shell, + .landing-shell, + .detail-shell { + padding-top: 14px; + } + + .hero-card, + .landing-hero, + .panel-card, + .entry-card, + .preview-panel, + .summary-panel, + .detail-panel { + padding: 18px; + } + + .panel-title-row { + align-items: flex-start; + flex-direction: column; + } +} + +@media print { + body { + background: #ffffff; + color: #111827; + } + + body::before, + body::after, + .page-footer, + .top-actions { + display: none !important; + } + + .detail-shell, + .page-shell { + width: 100%; + max-width: none; + padding: 0; + } + + .detail-grid { + display: block; + } + + .preview-panel, + .summary-panel, + .detail-panel, + .panel-card, + .hero-card, + .stat-card { + background: #ffffff !important; + color: #111827 !important; + box-shadow: none !important; + border: 1px solid #d1d5db !important; + } + + .preview-panel::before, + .summary-panel::before, + .detail-panel::before, + .panel-card::before, + .hero-card::before, + .stat-card::before { + display: none !important; + } + + .section-kicker, + .summary-label, + .detail-label, + .info-table th, + .ticket-subtitle, + .section-copy, + .summary-value, + .detail-value, + .top-actions-group, + .status-pill, + .page-shell * { + color: inherit !important; + } + + .certificate-stage { + min-height: 0; + border: none !important; + background: #ffffff !important; + page-break-after: always; + break-after: page; + } + + .preview-panel { + padding: 0 !important; + border: none !important; + background: #ffffff !important; + } + + .preview-panel > .section-kicker, + .preview-panel > .section-heading, + .preview-panel > .section-copy, + .summary-panel { + display: none !important; + } + + .certificate-hint { + display: none !important; + } + + .certificate-stage img { + display: block !important; + } + + .info-table-shell { + border: 1px solid #d1d5db !important; + background: #ffffff !important; + } + + .detail-panel { + break-before: page; + } + + @page { + size: A4 portrait; + margin: 10mm; + } +} diff --git a/2000s/css/ticket-print.css b/2000s/css/ticket-print.css new file mode 100644 index 0000000..99ebfeb --- /dev/null +++ b/2000s/css/ticket-print.css @@ -0,0 +1,95 @@ +body { + font-family: Arial, "Microsoft YaHei"; + margin: 0; + color: #172033; + background: + linear-gradient(128deg, rgba(255, 255, 255, 0.96) 0 34%, rgba(232, 249, 255, 0.9) 34% 58%, rgba(255, 246, 249, 0.92) 58% 100%); +} + +/* ===== A4 容器 ===== */ +.page { + width: 210mm; + min-height: 297mm; + margin: 18px auto; + padding: 20mm; + position: relative; + background: white; + box-shadow: 0 18px 44px rgba(47, 74, 112, 0.12); + border-top: 5px solid #2563eb; +} + +/* ===== 水印 ===== */ +.watermark { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%) rotate(-30deg); + font-size: 50px; + color: rgba(0, 0, 0, 0.08); + white-space: nowrap; + pointer-events: none; + z-index: 0; + text-align: center; +} + +/* ===== 标题 ===== */ +.title { + text-align: center; + font-size: 22px; + font-weight: bold; + margin-bottom: 20px; + color: #172033; + letter-spacing: 0.04em; +} + +/* ===== 信息表格 ===== */ +.table { + width: 100%; + border-collapse: collapse; + margin-top: 10px; + position: relative; + z-index: 1; +} + +.table td { + border: 1px solid #dbe4ef; + padding: 11px 12px; + font-size: 14px; +} + +.label { + width: 25%; + color: #66758a; + background: linear-gradient(135deg, #f3f8ff, #f8fbff); + font-weight: 700; +} + +/* ===== 页脚 ===== */ +.footer { + position: absolute; + bottom: 20mm; + left: 20mm; + right: 20mm; + font-size: 12px; + color: #666; + display: flex; + justify-content: space-between; +} + +/* ===== 打印优化 ===== */ +@media print { + .no-print { + display: none; + } + + body { + margin: 0; + background: #ffffff; + } + + .page { + margin: auto; + box-shadow: none; + border-top: 0; + } +} diff --git a/2000s/js/certs-certificate.js b/2000s/js/certs-certificate.js new file mode 100644 index 0000000..4c6fcd6 --- /dev/null +++ b/2000s/js/certs-certificate.js @@ -0,0 +1,119 @@ +const SUPABASE_URL = 'https://chixssrphfgxvqqigkzo.supabase.co'; + const SUPABASE_ANON_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImNoaXhzc3JwaGZneHZxcWlna3pvIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NzQ2OTE0OTEsImV4cCI6MjA5MDI2NzQ5MX0.Az_Ew2J2zdOMcSV0UNAjBS-LPqGpqhsaN4IyZ5R7iqU'; + const sbClient = supabase.createClient(SUPABASE_URL, SUPABASE_ANON_KEY); + + async function loadData() { + const id = new URLSearchParams(window.location.search).get('id'); + if (!id) return; + + try { + const { data, error } = await sbClient + .from('certificates') + .select('*') + .eq('id', id) + .single(); + + if (error || !data) throw error || new Error('未找到证书信息'); + + const verifyTime = new Date().toLocaleString('zh-CN'); + document.getElementById('info-card').style.display = 'block'; + document.getElementById('d-cert-number').innerText = data.cert_number || '-'; + document.getElementById('d-holder-name').innerText = data.holder_name || '-'; + document.getElementById('d-honor-title').innerText = data.honor_title || '-'; + document.getElementById('d-issue-date').innerText = data.issue_date || '-'; + document.getElementById('d-issuer').innerText = data.issuer || '官方授权机构'; + document.getElementById('d-desc').innerText = data.description || '官方荣誉认证'; + document.getElementById('d-remarks').innerText = data.remarks || '无'; + document.getElementById('d-verify-time').innerText = verifyTime; + + document.getElementById('summary-cert-number').innerText = data.cert_number || '-'; + document.getElementById('summary-holder-name').innerText = data.holder_name || '-'; + document.getElementById('summary-verify-time').innerText = verifyTime; + + if (data.status === 'valid') { + document.getElementById('display-status').innerHTML = '有效'; + } else if (data.status === 'invalid') { + document.getElementById('display-status').innerHTML = '无效'; + } else { + document.getElementById('display-status').innerHTML = '待核验'; + } + + window.currentCertNumber = data.cert_number; + } catch (e) { + console.error('加载失败:', e); + alert('证书信息检索失败。'); + } + } + + function loadCertificateImage() { + const certNumber = window.currentCertNumber; + if (!certNumber) return; + + const img = document.getElementById('cert-img'); + const hint = document.getElementById('click-hint'); + + if (img.src && img.complete && img.naturalWidth > 0) { + img.style.display = 'block'; + if (hint) hint.style.display = 'none'; + return; + } + + if (hint) { + hint.innerHTML = '图片加载中正在读取证书原件,请稍候。'; + } + + img.src = `https://s3.biss.click/CERTS/${encodeURIComponent(certNumber)}.svg`; + img.onload = () => { + img.style.display = 'block'; + if (hint) hint.style.display = 'none'; + }; + img.onerror = () => { + if (hint) { + hint.innerHTML = '!图片加载失败未找到对应证书图片文件'; + } + }; + } + + async function ensureCertificateImageLoaded() { + const certNumber = window.currentCertNumber; + const img = document.getElementById('cert-img'); + const hint = document.getElementById('click-hint'); + + if (!certNumber) { + throw new Error('未找到证书编号'); + } + + if (img.src && img.complete && img.naturalWidth > 0) { + img.style.display = 'block'; + if (hint) hint.style.display = 'none'; + return; + } + + if (hint) { + hint.innerHTML = '图片加载中正在为打印准备证书原件,请稍候。'; + } + + await new Promise((resolve, reject) => { + img.onload = () => { + img.style.display = 'block'; + if (hint) hint.style.display = 'none'; + resolve(); + }; + img.onerror = () => { + reject(new Error('证书图片加载失败')); + }; + img.src = `https://s3.biss.click/CERTS/${encodeURIComponent(certNumber)}.svg`; + }); + } + + async function printCertificate() { + try { + await ensureCertificateImageLoaded(); + window.print(); + } catch (error) { + console.error('打印前加载证书失败:', error); + alert('证书原件加载失败,无法打印。'); + } + } + + loadData(); diff --git a/2000s/js/certs-index.js b/2000s/js/certs-index.js new file mode 100644 index 0000000..ce51650 --- /dev/null +++ b/2000s/js/certs-index.js @@ -0,0 +1,246 @@ +const SUPABASE_URL = 'https://chixssrphfgxvqqigkzo.supabase.co'; + const SUPABASE_ANON_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImNoaXhzc3JwaGZneHZxcWlna3pvIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NzQ2OTE0OTEsImV4cCI6MjA5MDI2NzQ5MX0.Az_Ew2J2zdOMcSV0UNAjBS-LPqGpqhsaN4IyZ5R7iqU'; + const sbClient = supabase.createClient(SUPABASE_URL, SUPABASE_ANON_KEY); + + const html5QrCode = new Html5Qrcode("reader"); + const scannerOverlay = document.getElementById('scanner-overlay'); + + document.getElementById('startScanBtn').addEventListener('click', async () => { + scannerOverlay.style.display = 'flex'; + + const config = { + fps: 15, + qrbox: { width: 320, height: 140 }, + aspectRatio: 1.0 + }; + + if (typeof Html5QrcodeSupportedFormats !== 'undefined') { + config.formatsToSupport = [ + Html5QrcodeSupportedFormats.CODE_128, + Html5QrcodeSupportedFormats.CODE_39, + Html5QrcodeSupportedFormats.CODE_93, + Html5QrcodeSupportedFormats.EAN_13, + Html5QrcodeSupportedFormats.EAN_8, + Html5QrcodeSupportedFormats.UPC_A, + Html5QrcodeSupportedFormats.UPC_E, + Html5QrcodeSupportedFormats.ITF, + Html5QrcodeSupportedFormats.CODABAR + ]; + } + + try { + await html5QrCode.start( + { facingMode: "environment" }, + config, + (decodedText) => { + document.getElementById('searchTerm').value = decodedText; + closeScanner(); + handleSearch(); + }, + () => {} + ); + } catch (err) { + alert("无法启动摄像头,请检查 HTTPS 权限或设备连接。"); + scannerOverlay.style.display = 'none'; + } + }); + + async function closeScanner() { + if (html5QrCode.isScanning) { + await html5QrCode.stop(); + } + scannerOverlay.style.display = 'none'; + } + + document.getElementById('stopScanBtn').addEventListener('click', closeScanner); + + async function handleSearch() { + const term = document.getElementById('searchTerm').value.trim(); + const start = document.getElementById('dateStart').value; + const end = document.getElementById('dateEnd').value; + const display = document.getElementById('resultsArea'); + + if (!term) { + alert("请输入证书编号、持有人姓名或奖项名。"); + return; + } + + display.innerHTML = '
正在连接证书数据库并执行检索...
'; + + try { + let query = sbClient.from('certificates').select('*'); + query = query.or(`cert_number.ilike.%${term}%,holder_name.ilike.%${term}%,honor_title.ilike.%${term}%`); + + if (start) query = query.gte('issue_date', start); + if (end) query = query.lte('issue_date', end); + + const { data, error } = await query.order('issue_date', { ascending: false }); + if (error) throw error; + + const awardRecipientCounts = await loadAwardRecipientCounts(data); + renderResults(data, awardRecipientCounts); + } catch (err) { + display.innerHTML = `
检索失败:${err.message}
`; + } + } + + async function loadAwardRecipientCounts(data) { + const awardTitles = [...new Set((data || []).map(item => item.honor_title).filter(Boolean))]; + if (awardTitles.length === 0) return {}; + + const countPairs = await Promise.all(awardTitles.map(async title => { + const { count, error } = await sbClient + .from('certificates') + .select('id', { count: 'exact', head: true }) + .eq('honor_title', title); + + if (error) throw error; + return [title, count || 0]; + })); + + return Object.fromEntries(countPairs); + } + + function escapeHtml(value) { + return String(value ?? '').replace(/[&<>"']/g, char => ({ + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''' + }[char])); + } + + function renderAwardStats(data, awardRecipientCounts) { + const holderCounts = (data || []).reduce((counts, item) => { + const holderName = item.holder_name || '未填写'; + counts[holderName] = (counts[holderName] || 0) + 1; + return counts; + }, {}); + + const holderStats = Object.entries(holderCounts) + .sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0], 'zh-CN')); + const maxHolderCount = Math.max(...holderStats.map(([, count]) => count), 1); + + const awardStats = [...new Set((data || []).map(item => item.honor_title).filter(Boolean))] + .map(title => ({ + title, + count: awardRecipientCounts[title] || 0 + })) + .sort((a, b) => b.count - a.count || a.title.localeCompare(b.title, 'zh-CN')); + + const holderBars = holderStats.map(([name, count]) => ` +
+
${escapeHtml(name)}
+
+
+
+
${count} 项
+
+ `).join(''); + + const awardChips = awardStats.map(item => ` +
+ ${escapeHtml(item.title)} + ${item.count} + 人获得 +
+ `).join(''); + + return ` +
+
+ 查询结果 + ${data.length} +
+
+ 涉及人员 + ${holderStats.length} +
+
+ 奖项种类 + ${awardStats.length} +
+
+
+
+
个人奖项数量
+
${holderBars}
+
+
+
查询奖项获得人数
+
${awardChips || '
暂无奖项名称
'}
+
+
+ `; + } + + function renderResults(data, awardRecipientCounts = {}) { + const display = document.getElementById('resultsArea'); + if (!data || data.length === 0) { + display.innerHTML = '
未找到匹配的证书记录。
'; + return; + } + + let html = ` + ${renderAwardStats(data, awardRecipientCounts)} +
+ + + + + + + + + + + + `; + + data.forEach(item => { + html += ` + + + + + + + + `; + }); + + html += '
证书编号持有人荣誉标题颁发日期操作
${escapeHtml(item.cert_number || '-')}${escapeHtml(item.holder_name || '-')}${escapeHtml(item.honor_title || '-')}${escapeHtml(item.issue_date || '-')}
'; + display.innerHTML = html; + } + + function goToDetail(id) { + window.location.href = `certificate.html?id=${id}`; + } + + function initializeSearchTermFromUrl() { + const params = new URLSearchParams(window.location.search); + const presetTerm = + params.get('searchTerm') || + params.get('term') || + params.get('keyword') || + params.get('cert_number') || + params.get('certNumber') || + params.get('number') || + params.get('awardName') || + params.get('honor_title') || + params.get('honorTitle') || + params.get('award') || + params.get('q') || + ''; + + if (presetTerm) { + document.getElementById('searchTerm').value = presetTerm; + } + } + + document.getElementById('searchBtn').addEventListener('click', handleSearch); + document.getElementById('searchTerm').addEventListener('keypress', e => { + if (e.key === 'Enter') handleSearch(); + }); + initializeSearchTermFromUrl(); diff --git a/2000s/js/notice-banner.js b/2000s/js/notice-banner.js new file mode 100644 index 0000000..798e694 --- /dev/null +++ b/2000s/js/notice-banner.js @@ -0,0 +1,175 @@ +(function () { + var currentScript = document.currentScript; + var source = currentScript && currentScript.getAttribute("data-notice-src"); + + if (!source && currentScript && currentScript.src) { + source = currentScript.src.replace(/js\/notice-banner\.js(?:\?.*)?$/, "notices.json"); + } + + if (!source) { + source = "notices.json"; + } + + var cacheKey = Math.floor(Date.now() / (5 * 60 * 1000)); + var joiner = source.indexOf("?") === -1 ? "?" : "&"; + + fetch(source + joiner + "v=" + cacheKey, { cache: "no-store" }) + .then(function (response) { + if (!response.ok) { + throw new Error("Notice source unavailable"); + } + return response.json(); + }) + .then(function (payload) { + var notice = selectNotice(payload); + if (notice) { + renderNotice(notice); + } + }) + .catch(function () { + // The page should stay quiet when the optional notice source is missing. + }); + + function selectNotice(payload) { + var notices = Array.isArray(payload) ? payload : payload && payload.notices; + + if (!Array.isArray(notices)) { + return null; + } + + var now = Date.now(); + var path = normalizePath(window.location.pathname); + + return notices.find(function (notice) { + if (!notice || notice.enabled === false) { + return false; + } + + if (notice.startsAt && Date.parse(notice.startsAt) > now) { + return false; + } + + if (notice.endsAt && Date.parse(notice.endsAt) < now) { + return false; + } + + if (notice.pages && notice.pages.length) { + return notice.pages.some(function (page) { + return pathMatches(path, normalizePath(page)); + }); + } + + return true; + }); + } + + function renderNotice(notice) { + var dismissedId = window.localStorage.getItem("dismissedNoticeId"); + var noticeId = String(notice.id || ""); + + if (notice.dismissible !== false && noticeId && dismissedId === noticeId) { + return; + } + + var body = document.body; + var originalPadding = window.getComputedStyle(body).paddingTop || "0px"; + body.style.setProperty("--notice-body-pad-top", originalPadding); + + var banner = document.createElement("div"); + banner.className = "notice-banner"; + banner.setAttribute("role", "status"); + banner.setAttribute("aria-live", "polite"); + banner.dataset.level = notice.level || "info"; + + var inner = document.createElement("div"); + inner.className = "notice-banner__inner"; + + var badge = document.createElement("span"); + badge.className = "notice-banner__badge"; + badge.textContent = notice.badge || levelLabel(notice.level); + + var content = document.createElement("div"); + content.className = "notice-banner__content"; + + if (notice.title) { + var title = document.createElement("span"); + title.className = "notice-banner__title"; + title.textContent = notice.title; + content.appendChild(title); + } + + var message = document.createElement("span"); + message.className = "notice-banner__message"; + message.textContent = notice.message || ""; + content.appendChild(message); + + inner.appendChild(badge); + inner.appendChild(content); + + if (notice.url) { + var link = document.createElement("a"); + link.className = "notice-banner__link"; + link.href = resolveUrl(notice.url, source); + link.textContent = notice.linkText || "查看详情"; + inner.appendChild(link); + } + + var close = document.createElement("button"); + close.className = "notice-banner__close"; + close.type = "button"; + close.setAttribute("aria-label", "关闭通知"); + close.textContent = "×"; + close.addEventListener("click", function () { + if (notice.dismissible !== false && noticeId) { + window.localStorage.setItem("dismissedNoticeId", noticeId); + } + banner.remove(); + body.classList.remove("has-notice-banner"); + body.style.removeProperty("--notice-banner-height"); + }); + + inner.appendChild(close); + banner.appendChild(inner); + body.insertBefore(banner, body.firstChild); + + requestAnimationFrame(function () { + banner.classList.add("is-visible"); + body.style.setProperty("--notice-banner-height", banner.offsetHeight + "px"); + body.classList.add("has-notice-banner"); + }); + } + + function levelLabel(level) { + var labels = { + warning: "提醒", + error: "紧急", + success: "完成" + }; + + return labels[level] || "通知"; + } + + function normalizePath(path) { + return String(path || "").replace(/\\/g, "/").replace(/^.*?:\/\/[^/]+/, ""); + } + + function resolveUrl(url, base) { + try { + return new URL(url, new URL(base, window.location.href)).href; + } catch (error) { + return url; + } + } + + function pathMatches(path, pattern) { + if (!pattern || pattern === "*") { + return true; + } + + if (pattern.charAt(pattern.length - 1) === "*") { + return path.indexOf(pattern.slice(0, -1)) === 0; + } + + return path === pattern || path.endsWith(pattern); + } +})(); diff --git a/2000s/js/notice-index.js b/2000s/js/notice-index.js new file mode 100644 index 0000000..f7c87e4 --- /dev/null +++ b/2000s/js/notice-index.js @@ -0,0 +1,70 @@ +(function () { + fetch("../notices.json?v=" + Math.floor(Date.now() / 300000), { cache: "no-store" }) + .then(function (response) { + if (!response.ok) { + throw new Error("notice source unavailable"); + } + return response.json(); + }) + .then(function (payload) { + var notices = Array.isArray(payload) ? payload : payload.notices; + var notice = Array.isArray(notices) && notices.find(function (item) { + return item && item.enabled !== false; + }); + + if (notice) { + renderNotice(notice); + } + }) + .catch(function () {}); + + function renderNotice(notice) { + setText("noticeTitle", notice.title || "重要通知"); + setText("noticeSummary", notice.message || ""); + setText("noticeBadge", notice.badge || "通知"); + setText("noticeLevel", String(notice.level || "info").toUpperCase()); + setText("articleTitle", notice.title || "重要通知"); + setText("articleMessage", notice.message || ""); + setText("noticeDate", formatDate(notice.startsAt) || "未设置开始时间"); + setText("noticeWindow", formatWindow(notice.startsAt, notice.endsAt)); + } + + function setText(id, text) { + var node = document.getElementById(id); + if (node) { + node.textContent = text; + } + } + + function formatDate(value) { + if (!value) { + return ""; + } + + var date = new Date(value); + if (Number.isNaN(date.getTime())) { + return ""; + } + + return date.toLocaleDateString("zh-CN", { + year: "numeric", + month: "2-digit", + day: "2-digit" + }); + } + + function formatWindow(start, end) { + var startText = formatDate(start); + var endText = formatDate(end); + + if (startText && endText) { + return startText + " 至 " + endText; + } + + if (startText) { + return startText + " 起生效"; + } + + return "长期有效"; + } + })(); diff --git a/2000s/js/ticket-detail.js b/2000s/js/ticket-detail.js new file mode 100644 index 0000000..8ca1f79 --- /dev/null +++ b/2000s/js/ticket-detail.js @@ -0,0 +1,100 @@ +const SUPABASE_URL = 'https://chixssrphfgxvqqigkzo.supabase.co'; + const SUPABASE_ANON_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImNoaXhzc3JwaGZneHZxcWlna3pvIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NzQ2OTE0OTEsImV4cCI6MjA5MDI2NzQ5MX0.Az_Ew2J2zdOMcSV0UNAjBS-LPqGpqhsaN4IyZ5R7iqU'; + + if (!window._sbClient) { + window._sbClient = window.supabase.createClient(SUPABASE_URL, SUPABASE_ANON_KEY); + } + const sbClient = window._sbClient; + + async function loadTicketDetail() { + const urlParams = new URLSearchParams(window.location.search); + const ticketId = urlParams.get('id'); + + if (!ticketId) { + showError('未提供单据 ID。'); + return; + } + + try { + const { data: ticket, error } = await sbClient + .from('tickets') + .select('*') + .eq('id', ticketId) + .single(); + + if (error) throw error; + if (!ticket) { + showError('未找到该单据。'); + return; + } + + displayTicketDetail(ticket); + } catch (error) { + showError(error.message || '加载失败'); + } + } + + function displayTicketDetail(ticket) { + const el = document.getElementById('detailContent'); + const processedLabel = ticket.processed ? '已处理' : '未处理'; + const completionLabel = ticket.status ? '已办结' : '未办结'; + const amount = Number(ticket.amount || 0).toLocaleString('zh-CN', { + style: 'currency', + currency: 'CNY' + }); + + el.classList.remove('feedback-card'); + el.innerHTML = ` +
+
+
Ticket Detail
+

${ticket.ticket_number || '-'} / ${ticket.customer_name || '-'}

+

单据全量信息、处理状态与打印操作在此统一展示。

+
+
+ ${processedLabel} + ${completionLabel} +
+
+ +
+ ${item('编号', ticket.ticket_number)} + ${item('姓名', ticket.customer_name)} + ${item('事由', ticket.reason)} + ${item('处理结果', ticket.result)} + ${item('金额', amount, 'money')} + ${item('开具人', ticket.issuer)} + ${item('创建时间', formatDate(ticket.created_at))} + ${item('办结日期', formatDate(ticket.processed_at))} + ${item('处理状态', `${processedLabel}`, '', true)} + ${item('办结状态', `${completionLabel}`, '', true)} + ${item('备注', ticket.remarks || '无', '', false, true)} +
+ `; + } + + function item(label, value, extraClass = '', isHTML = false, isWide = false) { + return ` +
+ ${label} +
${isHTML ? value : (value || '无')}
+
+ `; + } + + function goPrint() { + window.open(`print.html?id=${new URLSearchParams(location.search).get('id')}`, '_blank'); + } + + function formatDate(dateString) { + if (!dateString) return '暂无'; + return new Date(dateString).toLocaleString('zh-CN'); + } + + function showError(msg) { + const el = document.getElementById('detailContent'); + el.classList.add('feedback-card'); + el.innerHTML = `
${msg}
`; + } + + document.addEventListener('DOMContentLoaded', loadTicketDetail); diff --git a/2000s/js/ticket-index.js b/2000s/js/ticket-index.js new file mode 100644 index 0000000..8488d38 --- /dev/null +++ b/2000s/js/ticket-index.js @@ -0,0 +1,132 @@ +const SUPABASE_URL = 'https://chixssrphfgxvqqigkzo.supabase.co'; + const SUPABASE_ANON_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImNoaXhzc3JwaGZneHZxcWlna3pvIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NzQ2OTE0OTEsImV4cCI6MjA5MDI2NzQ5MX0.Az_Ew2J2zdOMcSV0UNAjBS-LPqGpqhsaN4IyZ5R7iqU'; + const sbClient = supabase.createClient(SUPABASE_URL, SUPABASE_ANON_KEY); + + let html5QrCode = null; + + document.getElementById('startScanBtn').addEventListener('click', async () => { + document.getElementById('scanner-overlay').style.display = 'flex'; + if (html5QrCode) { + try { + await html5QrCode.stop(); + } catch (e) {} + } + html5QrCode = new Html5Qrcode("reader"); + const config = { fps: 15, qrbox: { width: 250, height: 250 }, aspectRatio: 1.0 }; + try { + await html5QrCode.start({ facingMode: "environment" }, config, (text) => { + document.getElementById('searchTerm').value = text; + closeScanner(); + handleSearch(); + }); + } catch (err) { + alert("摄像头启动失败。"); + closeScanner(); + } + }); + + async function closeScanner() { + if (html5QrCode && html5QrCode.isScanning) { + await html5QrCode.stop(); + } + document.getElementById('scanner-overlay').style.display = 'none'; + } + + document.getElementById('stopScanBtn').addEventListener('click', closeScanner); + + async function handleSearch() { + const searchTerm = document.getElementById('searchTerm').value.trim(); + const dateFrom = document.getElementById('dateFrom').value; + const dateTo = document.getElementById('dateTo').value; + const resultsDiv = document.getElementById('searchResults'); + + resultsDiv.innerHTML = '
正在连接单据数据库并执行检索...
'; + + try { + let query = sbClient.from('tickets').select('*'); + if (searchTerm) { + query = query.or(`ticket_number.ilike.%${searchTerm}%,customer_name.ilike.%${searchTerm}%`); + } + if (dateFrom) query = query.gte('created_at', dateFrom); + if (dateTo) query = query.lte('created_at', dateTo); + + const { data, error } = await query.order('created_at', { ascending: false }); + if (error) throw error; + + displayResults(data); + } catch (error) { + resultsDiv.innerHTML = `
查询失败:${error.message}
`; + } + } + + function displayResults(tickets) { + const resultsDiv = document.getElementById('searchResults'); + if (!tickets || tickets.length === 0) { + resultsDiv.innerHTML = '
未找到符合条件的单据记录。
'; + return; + } + + let html = ` +
+ + + + + + + + + + + + + + `; + + tickets.forEach(ticket => { + const amount = (ticket.amount || 0).toLocaleString('zh-CN', { style: 'currency', currency: 'CNY' }); + const reason = ticket.reason || ''; + const displayReason = reason.length > 18 + ? `${reason}` + : reason; + + html += ` + + + + + + + + + + `; + }); + + html += '
编号姓名事由金额日期状态操作
${ticket.ticket_number || ''}${ticket.customer_name || ''}${displayReason}${amount}${ticket.created_at ? new Date(ticket.created_at).toLocaleDateString('zh-CN') : '-'} + + ${ticket.processed ? '已处理' : '未处理'} + +
'; + resultsDiv.innerHTML = html; + } + + function initializeSearchTermFromUrl() { + const params = new URLSearchParams(window.location.search); + const presetTerm = + params.get('searchTerm') || + params.get('term') || + params.get('keyword') || + params.get('ticket_number') || + params.get('ticketNumber') || + params.get('number') || + params.get('q') || + ''; + + if (presetTerm) { + document.getElementById('searchTerm').value = presetTerm; + } + } + + document.getElementById('searchBtn').addEventListener('click', handleSearch); + initializeSearchTermFromUrl(); diff --git a/2000s/js/ticket-print.js b/2000s/js/ticket-print.js new file mode 100644 index 0000000..41006d8 --- /dev/null +++ b/2000s/js/ticket-print.js @@ -0,0 +1,47 @@ +const SUPABASE_URL = 'https://chixssrphfgxvqqigkzo.supabase.co'; +const SUPABASE_ANON_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImNoaXhzc3JwaGZneHZxcWlna3pvIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NzQ2OTE0OTEsImV4cCI6MjA5MDI2NzQ5MX0.Az_Ew2J2zdOMcSV0UNAjBS-LPqGpqhsaN4IyZ5R7iqU'; + +const sb = window.supabase.createClient(SUPABASE_URL, SUPABASE_ANON_KEY); + +function formatDate(d){ + return new Date(d).toLocaleString('zh-CN'); +} + +function updateWatermark(customerName) { + const now = new Date().toLocaleString('zh-CN'); + + const watermarkText = `BISS · ${customerName || 'Unknown'} · ${now}`; + + document.getElementById('watermark').innerText = watermarkText; +} + +async function load() { + const id = new URLSearchParams(location.search).get('id'); + + const { data } = await sb.from('tickets').select('*').eq('id', id).single(); + + if (!data) return; + + document.getElementById('ticket_number').innerText = data.ticket_number || ''; + document.getElementById('customer_name').innerText = data.customer_name || ''; + document.getElementById('reason').innerText = data.reason || ''; + document.getElementById('amount').innerText = '¥' + (data.amount || 0).toFixed(2); + document.getElementById('issuer').innerText = data.issuer || ''; + document.getElementById('created_at').innerText = formatDate(data.created_at); + document.getElementById('processed').innerText = data.processed ? '已办结' : '未办结'; + document.getElementById('processed_at').innerText = data.processed_at ? formatDate(data.processed_at) : '暂无'; + document.getElementById('remarks').innerText = data.remarks || '无'; + + // 打印时间 + document.getElementById('print_time').innerText = + new Date().toLocaleString('zh-CN'); + + updateWatermark(data.customer_name); + + // 自动打印 + setTimeout(() => { + window.print(); + }, 300); +} + +load(); diff --git a/2000s/js/xinhan-index.js b/2000s/js/xinhan-index.js new file mode 100644 index 0000000..a929d39 --- /dev/null +++ b/2000s/js/xinhan-index.js @@ -0,0 +1,73 @@ +const SUPABASE_URL = 'https://chixssrphfgxvqqigkzo.supabase.co'; + const SUPABASE_ANON_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImNoaXhzc3JwaGZneHZxcWlna3pvIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NzQ2OTE0OTEsImV4cCI6MjA5MDI2NzQ5MX0.Az_Ew2J2zdOMcSV0UNAjBS-LPqGpqhsaN4IyZ5R7iqU'; + const sb = supabase.createClient(SUPABASE_URL, SUPABASE_ANON_KEY); + + async function handleSearch() { + const recipientTerm = document.getElementById('recipientTerm').value.trim(); + const contentTerm = document.getElementById('searchTerm').value.trim(); + const from = document.getElementById('dateFrom').value; + const to = document.getElementById('dateTo').value; + const out = document.getElementById('searchResults'); + + out.innerHTML = '
正在连接信函数据库并执行检索...
'; + + let q = sb.from('xinhan').select('*'); + if (recipientTerm) q = q.ilike('recipient', `%${recipientTerm}%`); + if (contentTerm) q = q.ilike('content', `%${contentTerm}%`); + if (from) q = q.gte('sent_date', from); + if (to) q = q.lte('sent_date', to); + + const { data, error } = await q.order('sent_date', { ascending: false }); + if (error) { + out.innerHTML = `
查询失败:${error.message}
`; + return; + } + renderResults(data || []); + } + + function renderResults(rows) { + const container = document.getElementById('searchResults'); + if (!rows.length) { + container.innerHTML = '
未找到符合条件的信函记录。
'; + return; + } + + let html = ` +
+ + + + + + + + + + + + + `; + + rows.forEach(row => { + const content = row.content || ''; + const summary = content.length > 60 + ? `${content}` + : content; + + html += ` + + + + + + + + + `; + }); + + html += '
ID收件人目的地寄出日期寄达日期内容摘要
${row.id}${row.recipient || ''}${row.destination || ''}${row.sent_date || ''}${row.arrival_date || ''}${summary}
'; + container.innerHTML = html; + } + + document.getElementById('searchBtn').addEventListener('click', handleSearch); diff --git a/2000s/notice/index.html b/2000s/notice/index.html new file mode 100644 index 0000000..25c5ad8 --- /dev/null +++ b/2000s/notice/index.html @@ -0,0 +1,70 @@ + + + + + + 通知详情 + + + + + + +
+ + +
+
+ Notice Center +

重要通知

+

2026 年上半年 4 月数据已完成更新。请按需进入相关查询页面查看最新记录。

+
+
+ 通知 +
INFO
+

长期有效

+
+
+ +
+
+
+ 2026-05-01 + 当前生效 +
+

重要通知

+

2026 年上半年 4 月数据已完成更新。请按需进入相关查询页面查看最新记录。

+ +
+
+ 适用范围 + 证书、信函与单据查询 +
+
+ 提醒类型 + 服务公告与使用提示 +
+
+ 查看方式 + 页面顶部通知横幅 +
+
+
+ + +
+
+ + + + diff --git a/2000s/ticket/detail.html b/2000s/ticket/detail.html new file mode 100644 index 0000000..ea0cf28 --- /dev/null +++ b/2000s/ticket/detail.html @@ -0,0 +1,37 @@ + + + + + + 单据详情 + + + + + + + + +
+
+ 返回查询页 +
+ + +
+
+ + +
+ + + + + + + + diff --git a/2000s/ticket/index.html b/2000s/ticket/index.html new file mode 100644 index 0000000..b3e7542 --- /dev/null +++ b/2000s/ticket/index.html @@ -0,0 +1,96 @@ + + + + + + 单据查询系统 + + + + + + + + + + +
+ + +
+
+
+

检索条件

+
支持文本检索与扫码录入
+
+
+ +
+
+ +
+ + +
+
+
+ + +
+
+ + +
+ +
+
+ +
+
+
+

查询结果

+
金额、状态与详情一屏展示
+
+
+
+
输入查询条件后开始检索,或使用扫码功能快速定位单据。
+
+
+
+ +
+
+
+
+
+
请将二维码保持在扫描框内
+ +
+ + + + + + + diff --git a/2000s/ticket/print.html b/2000s/ticket/print.html new file mode 100644 index 0000000..b30b043 --- /dev/null +++ b/2000s/ticket/print.html @@ -0,0 +1,46 @@ + + + + +打印单据 + + + + + + + + +
+ + +
+ +
单据详情
+ + + + + + + + + + + +
编号
姓名
事由
金额
开具人
日期
办结否
办结日期
备注
+ + + +
+ + + + + + + + diff --git a/2000s/xinhan/index.html b/2000s/xinhan/index.html new file mode 100644 index 0000000..b4857e0 --- /dev/null +++ b/2000s/xinhan/index.html @@ -0,0 +1,84 @@ + + + + + + 信函查询系统 + + + + + + + + +
+ + +
+
+
+

检索条件

+
多字段组合查询,快速过滤信函记录
+
+
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ +
+
+ +
+
+
+

查询结果

+
寄送路径与摘要信息集中展示
+
+
+
+
设置检索条件后即可查询信函流转记录。
+
+
+
+ + + + + + +