diff --git a/.gitignore b/.gitignore
index 246e0be..f4f24d4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,3 +5,11 @@
src/analysis/ARCHITECTURE.md
.serena/.gitignore
.serena/project.yml
+debug_output.html
+src/models/__pycache__/__init__.cpython-312.pyc
+src/models/__pycache__/data_models.cpython-312.pyc
+src/reports/__pycache__/__init__.cpython-312.pyc
+src/reports/__pycache__/generators.cpython-312.pyc
+src/reports/__pycache__/templates.cpython-312.pyc
+src/visualization/__pycache__/__init__.cpython-312.pyc
+src/visualization/__pycache__/activity_charts.cpython-312.pyc
diff --git a/src/reports/templates/scrapbook/image_template.html b/src/reports/templates/scrapbook/image_template.html
index 34263bc..b48c4b8 100644
--- a/src/reports/templates/scrapbook/image_template.html
+++ b/src/reports/templates/scrapbook/image_template.html
@@ -77,6 +77,29 @@
max-width: 1000px;
margin: 0 auto;
position: relative;
+ background: #fff;
+ border: 2px solid var(--ink-primary);
+ border-radius: 20px;
+ padding: 40px;
+ /* Stacked "Paper" Effect: Blue Shadow -> Pink Shadow -> Soft Drop Shadow */
+ box-shadow:
+ 8px 8px 0 var(--color-blue),
+ 16px 16px 0 var(--color-pink),
+ 0 20px 40px rgba(0, 0, 0, 0.1);
+ }
+
+ /* Stitching Effect */
+ .container::before {
+ content: "";
+ position: absolute;
+ top: 12px;
+ bottom: 12px;
+ left: 12px;
+ right: 12px;
+ border: 2px dashed var(--ink-secondary);
+ border-radius: 15px;
+ pointer-events: none;
+ opacity: 0.5;
}
/* ==================== 1. 头部设计 ==================== */
@@ -134,43 +157,57 @@
}
/* ==================== 2. 统计邮票 ==================== */
- .stats-row {
+ /* ==================== 2. 统计区域 (新版) ==================== */
+ .stats-wrapper {
display: flex;
- justify-content: center;
- gap: 30px;
+ gap: 25px;
margin-bottom: 40px;
- flex-wrap: wrap;
+ align-items: stretch;
+ }
+
+ .stats-grid {
+ flex: 2;
+ display: grid;
+ grid-template-columns: repeat(2, 1fr);
+ gap: 20px;
}
.stamp {
- width: 150px;
+ width: 100%;
+ height: 100%;
background: #fff;
- padding: 10px;
- box-shadow: 3px 3px 8px rgba(0, 0, 0, 0.05);
- /* 邮票齿孔背景 */
- background-image: radial-gradient(transparent 50%, #fff 51%);
- background-size: 10px 10px;
- background-position: -5px -5px;
+ padding: 15px;
+ box-shadow: 4px 4px 0 rgba(0, 0, 0, 0.1);
+ border: 2px solid var(--ink-primary);
+ border-radius: 12px;
+ position: relative;
display: flex;
flex-direction: column;
align-items: center;
- transition: transform 0.3s;
- border: 1px solid #eee;
+ justify-content: center;
+ transition: transform 0.2s;
+ }
+
+ /* 装饰性背景纹理 */
+ .stamp::after {
+ content: "";
+ position: absolute;
+ top: 5px;
+ bottom: 5px;
+ left: 5px;
+ right: 5px;
+ border: 1px dotted #e0e0e0;
+ border-radius: 8px;
+ pointer-events: none;
}
.stamp:hover {
- transform: scale(1.1) rotate(0deg) !important;
- z-index: 10;
+ transform: translateY(-2px);
}
.stamp-inner {
- border: 1px solid var(--ink-secondary);
- width: 100%;
- padding: 15px 0;
- display: flex;
- flex-direction: column;
- align-items: center;
- background: radial-gradient(circle, #fff 50%, #fafafa 100%);
+ text-align: center;
+ z-index: 1;
}
.stamp-num {
@@ -255,18 +292,21 @@
}
/* ==================== 4. 活跃时段 ==================== */
+ /* ==================== 4. 活跃时段 (新版) ==================== */
.highlight-section {
- grid-column: span 5;
+ flex: 1;
background: var(--color-yellow);
- padding: 30px;
- transform: rotate(2deg);
- box-shadow: 3px 3px 5px rgba(0, 0, 0, 0.1);
+ padding: 20px;
+ border: 2px solid var(--ink-primary);
+ border-radius: 20px;
+ box-shadow: 6px 6px 0 var(--color-pink);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
position: relative;
+ background-image: repeating-linear-gradient(45deg, rgba(255, 255, 255, 0.2) 0, rgba(255, 255, 255, 0.2) 10px, transparent 10px, transparent 20px);
}
.tape-top {
@@ -386,42 +426,59 @@
.user-card {
break-inside: avoid;
background: #fff;
- border: 2px solid #e0e0e0;
- border-radius: 12px;
- padding: 20px;
- margin-bottom: 25px;
- box-shadow: 4px 4px 0 rgba(0, 0, 0, 0.05);
+ border: 2px solid var(--ink-primary);
+ border-radius: 16px;
+ padding: 24px;
+ margin-bottom: 30px;
+ /* Muted Blue-Grey Shadow */
+ box-shadow: 6px 6px 0 rgba(70, 80, 100, 0.15), 6px 6px 0 1px var(--ink-primary);
position: relative;
display: flex;
flex-direction: column;
transition: transform 0.2s;
+ /* Very subtle grain */
+ background-color: #fff;
+ background-image: url("data:image/svg+xml,%3Csvg width='100' height='100' viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)' opacity='0.03'/%3E%3C/svg%3E");
}
.user-card:hover {
- transform: translateY(-3px);
+ transform: translateY(-4px) rotate(1deg);
z-index: 5;
- border-color: var(--ink-primary);
+ box-shadow: 8px 8px 0 rgba(0, 0, 0, 0.15), 8px 8px 0 2px var(--ink-primary);
}
.card-tape {
position: absolute;
- top: -10px;
+ top: -12px;
left: 50%;
- transform: translateX(-50%);
- width: 60px;
- height: 18px;
- background: var(--color-blue);
- opacity: 0.9;
+ transform: translateX(-50%) rotate(-2deg);
+ width: 80px;
+ height: 24px;
+ background: rgba(255, 255, 255, 0.4);
+ /* Fallback */
+ background-color: var(--color-blue);
+ opacity: 0.8;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+ /* Jagged edges for tape look */
+ mask-image: linear-gradient(135deg, transparent 5px, black 0) top left, linear-gradient(-135deg, transparent 5px, black 0) top right, linear-gradient(45deg, transparent 5px, black 0) bottom left, linear-gradient(-45deg, transparent 5px, black 0) bottom right;
+ mask-size: 51% 51%;
+ mask-repeat: no-repeat;
+ -webkit-mask-image: radial-gradient(circle at 2px 2px, transparent 2px, black 2.5px);
+ -webkit-mask-size: 100% 100%;
+ /* Simplify mask for compatibility */
+ /* Simpler tape look since masks can be tricky across renderers */
+ border-left: 2px dashed rgba(255, 255, 255, 0.3);
+ border-right: 2px dashed rgba(255, 255, 255, 0.3);
}
.user-card:nth-child(2n) .card-tape {
- background: var(--color-pink);
- transform: rotate(2deg);
+ background-color: var(--color-pink);
+ transform: translateX(-50%) rotate(3deg);
}
.user-card:nth-child(3n) .card-tape {
- background: var(--color-green);
- transform: rotate(-2deg);
+ background-color: var(--color-green);
+ transform: translateX(-50%) rotate(-1deg);
}
.user-header {
@@ -494,16 +551,24 @@
.u-reason {
font-family: var(--font-hand);
- font-size: 0.95rem;
- color: #555;
+ font-size: 1.05rem;
+ color: #444;
line-height: 1.6;
- text-align: justify;
- background: #fafafa;
- padding: 12px;
- border-radius: 8px;
+
+ /* Quote Block Style */
+ background: #f8fbff;
+ border-left: 4px solid var(--color-blue);
+ padding: 12px 15px;
+ margin-top: 15px;
+ border-radius: 4px;
position: relative;
}
+ .u-reason::before {
+ content: "";
+ /* Removed big quote mark to clean up */
+ }
+
/* ==================== 7. 每日回响 ==================== */
.quotes-section {
grid-column: span 12;
@@ -704,66 +769,62 @@
-
-
-
-
-
-
-
-
-
{{message_count}}
-
消息总数
-
+
+
+
+
+
+
+
+
{{message_count}}
+
消息总数
-
-
-
-
-
{{participant_count}}
-
参与人数
-
+
+
+
+
+
+
{{participant_count}}
+
参与人数
-
-
-
-
-
{{emoji_count}}
-
表情统计
-
+
+
+
+
+
+
{{emoji_count}}
+
表情统计
-
-
-
-
-
{{total_characters}}
-
总字符数
-
+
+
+
+
+
+
{{total_characters}}
+
总字符数
-
-
-
-
✨ Highlight
- Time
+
+
+
+
+ ✨ Highlight Time
+
{{most_active_period}}
(此刻,世界色彩斑斓)
diff --git a/src/reports/templates/scrapbook/pdf_template.html b/src/reports/templates/scrapbook/pdf_template.html
index 34263bc..b48c4b8 100644
--- a/src/reports/templates/scrapbook/pdf_template.html
+++ b/src/reports/templates/scrapbook/pdf_template.html
@@ -77,6 +77,29 @@
max-width: 1000px;
margin: 0 auto;
position: relative;
+ background: #fff;
+ border: 2px solid var(--ink-primary);
+ border-radius: 20px;
+ padding: 40px;
+ /* Stacked "Paper" Effect: Blue Shadow -> Pink Shadow -> Soft Drop Shadow */
+ box-shadow:
+ 8px 8px 0 var(--color-blue),
+ 16px 16px 0 var(--color-pink),
+ 0 20px 40px rgba(0, 0, 0, 0.1);
+ }
+
+ /* Stitching Effect */
+ .container::before {
+ content: "";
+ position: absolute;
+ top: 12px;
+ bottom: 12px;
+ left: 12px;
+ right: 12px;
+ border: 2px dashed var(--ink-secondary);
+ border-radius: 15px;
+ pointer-events: none;
+ opacity: 0.5;
}
/* ==================== 1. 头部设计 ==================== */
@@ -134,43 +157,57 @@
}
/* ==================== 2. 统计邮票 ==================== */
- .stats-row {
+ /* ==================== 2. 统计区域 (新版) ==================== */
+ .stats-wrapper {
display: flex;
- justify-content: center;
- gap: 30px;
+ gap: 25px;
margin-bottom: 40px;
- flex-wrap: wrap;
+ align-items: stretch;
+ }
+
+ .stats-grid {
+ flex: 2;
+ display: grid;
+ grid-template-columns: repeat(2, 1fr);
+ gap: 20px;
}
.stamp {
- width: 150px;
+ width: 100%;
+ height: 100%;
background: #fff;
- padding: 10px;
- box-shadow: 3px 3px 8px rgba(0, 0, 0, 0.05);
- /* 邮票齿孔背景 */
- background-image: radial-gradient(transparent 50%, #fff 51%);
- background-size: 10px 10px;
- background-position: -5px -5px;
+ padding: 15px;
+ box-shadow: 4px 4px 0 rgba(0, 0, 0, 0.1);
+ border: 2px solid var(--ink-primary);
+ border-radius: 12px;
+ position: relative;
display: flex;
flex-direction: column;
align-items: center;
- transition: transform 0.3s;
- border: 1px solid #eee;
+ justify-content: center;
+ transition: transform 0.2s;
+ }
+
+ /* 装饰性背景纹理 */
+ .stamp::after {
+ content: "";
+ position: absolute;
+ top: 5px;
+ bottom: 5px;
+ left: 5px;
+ right: 5px;
+ border: 1px dotted #e0e0e0;
+ border-radius: 8px;
+ pointer-events: none;
}
.stamp:hover {
- transform: scale(1.1) rotate(0deg) !important;
- z-index: 10;
+ transform: translateY(-2px);
}
.stamp-inner {
- border: 1px solid var(--ink-secondary);
- width: 100%;
- padding: 15px 0;
- display: flex;
- flex-direction: column;
- align-items: center;
- background: radial-gradient(circle, #fff 50%, #fafafa 100%);
+ text-align: center;
+ z-index: 1;
}
.stamp-num {
@@ -255,18 +292,21 @@
}
/* ==================== 4. 活跃时段 ==================== */
+ /* ==================== 4. 活跃时段 (新版) ==================== */
.highlight-section {
- grid-column: span 5;
+ flex: 1;
background: var(--color-yellow);
- padding: 30px;
- transform: rotate(2deg);
- box-shadow: 3px 3px 5px rgba(0, 0, 0, 0.1);
+ padding: 20px;
+ border: 2px solid var(--ink-primary);
+ border-radius: 20px;
+ box-shadow: 6px 6px 0 var(--color-pink);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
position: relative;
+ background-image: repeating-linear-gradient(45deg, rgba(255, 255, 255, 0.2) 0, rgba(255, 255, 255, 0.2) 10px, transparent 10px, transparent 20px);
}
.tape-top {
@@ -386,42 +426,59 @@
.user-card {
break-inside: avoid;
background: #fff;
- border: 2px solid #e0e0e0;
- border-radius: 12px;
- padding: 20px;
- margin-bottom: 25px;
- box-shadow: 4px 4px 0 rgba(0, 0, 0, 0.05);
+ border: 2px solid var(--ink-primary);
+ border-radius: 16px;
+ padding: 24px;
+ margin-bottom: 30px;
+ /* Muted Blue-Grey Shadow */
+ box-shadow: 6px 6px 0 rgba(70, 80, 100, 0.15), 6px 6px 0 1px var(--ink-primary);
position: relative;
display: flex;
flex-direction: column;
transition: transform 0.2s;
+ /* Very subtle grain */
+ background-color: #fff;
+ background-image: url("data:image/svg+xml,%3Csvg width='100' height='100' viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)' opacity='0.03'/%3E%3C/svg%3E");
}
.user-card:hover {
- transform: translateY(-3px);
+ transform: translateY(-4px) rotate(1deg);
z-index: 5;
- border-color: var(--ink-primary);
+ box-shadow: 8px 8px 0 rgba(0, 0, 0, 0.15), 8px 8px 0 2px var(--ink-primary);
}
.card-tape {
position: absolute;
- top: -10px;
+ top: -12px;
left: 50%;
- transform: translateX(-50%);
- width: 60px;
- height: 18px;
- background: var(--color-blue);
- opacity: 0.9;
+ transform: translateX(-50%) rotate(-2deg);
+ width: 80px;
+ height: 24px;
+ background: rgba(255, 255, 255, 0.4);
+ /* Fallback */
+ background-color: var(--color-blue);
+ opacity: 0.8;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+ /* Jagged edges for tape look */
+ mask-image: linear-gradient(135deg, transparent 5px, black 0) top left, linear-gradient(-135deg, transparent 5px, black 0) top right, linear-gradient(45deg, transparent 5px, black 0) bottom left, linear-gradient(-45deg, transparent 5px, black 0) bottom right;
+ mask-size: 51% 51%;
+ mask-repeat: no-repeat;
+ -webkit-mask-image: radial-gradient(circle at 2px 2px, transparent 2px, black 2.5px);
+ -webkit-mask-size: 100% 100%;
+ /* Simplify mask for compatibility */
+ /* Simpler tape look since masks can be tricky across renderers */
+ border-left: 2px dashed rgba(255, 255, 255, 0.3);
+ border-right: 2px dashed rgba(255, 255, 255, 0.3);
}
.user-card:nth-child(2n) .card-tape {
- background: var(--color-pink);
- transform: rotate(2deg);
+ background-color: var(--color-pink);
+ transform: translateX(-50%) rotate(3deg);
}
.user-card:nth-child(3n) .card-tape {
- background: var(--color-green);
- transform: rotate(-2deg);
+ background-color: var(--color-green);
+ transform: translateX(-50%) rotate(-1deg);
}
.user-header {
@@ -494,16 +551,24 @@
.u-reason {
font-family: var(--font-hand);
- font-size: 0.95rem;
- color: #555;
+ font-size: 1.05rem;
+ color: #444;
line-height: 1.6;
- text-align: justify;
- background: #fafafa;
- padding: 12px;
- border-radius: 8px;
+
+ /* Quote Block Style */
+ background: #f8fbff;
+ border-left: 4px solid var(--color-blue);
+ padding: 12px 15px;
+ margin-top: 15px;
+ border-radius: 4px;
position: relative;
}
+ .u-reason::before {
+ content: "";
+ /* Removed big quote mark to clean up */
+ }
+
/* ==================== 7. 每日回响 ==================== */
.quotes-section {
grid-column: span 12;
@@ -704,66 +769,62 @@
-
-
-
-
-
-
-
-
-
{{message_count}}
-
消息总数
-
+
+
+
+
+
+
+
+
{{message_count}}
+
消息总数
-
-
-
-
-
{{participant_count}}
-
参与人数
-
+
+
+
+
+
+
{{participant_count}}
+
参与人数
-
-
-
-
-
{{emoji_count}}
-
表情统计
-
+
+
+
+
+
+
{{emoji_count}}
+
表情统计
-
-
-
-
-
{{total_characters}}
-
总字符数
-
+
+
+
+
+
+
{{total_characters}}
+
总字符数
-
-
-
-
✨ Highlight
- Time
+
+
+
+
+ ✨ Highlight Time
+
{{most_active_period}}
(此刻,世界色彩斑斓)