refactor: 清理无用参数和优化代码结构

- 移除多个文件中的无用参数如sortOrder、keyword、limit等
- 优化日期处理逻辑,使用DateTime(year)替代DateTime(year,1,1)
- 修复颜色和边框样式的一致性
- 更新API调用参数,移除冗余的limit和page参数
- 新增SessionPopupMenu组件和ChatSession模型
- 优化笔记模型的时间显示和类型转换
- 修复验证码发送逻辑和加载状态
- 更新文档和脚本文件
This commit is contained in:
Developer
2026-05-01 09:37:15 +08:00
parent 3fc78006f8
commit 839e118cdb
123 changed files with 17455 additions and 7339 deletions

820
preview/note_redesign.html Normal file
View File

@@ -0,0 +1,820 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>闲言APP — 笔记页重新设计方案预览</title>
<style>
:root {
--primary: #007AFF;
--primary-light: rgba(0,122,255,0.12);
--bg: #F2F2F7;
--bg-card: #FFFFFF;
--bg-grouped: #F2F2F7;
--text-primary: #1C1C1E;
--text-secondary: #8E8E93;
--text-hint: #AEAEB2;
--separator: rgba(60,60,67,0.12);
--red: #FF3B30;
--orange: #FF9500;
--green: #34C759;
--purple: #AF52DE;
--radius-sm: 8px;
--radius-md: 12px;
--radius-lg: 16px;
--radius-xl: 20px;
--shadow-sm: 0 1px 3px rgba(0,0,0,0.06);
--shadow-md: 0 4px 12px rgba(0,0,0,0.08);
--shadow-lg: 0 8px 24px rgba(0,0,0,0.12);
--font: -apple-system, 'SF Pro Display', 'SF Pro Text', 'Helvetica Neue', sans-serif;
}
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: var(--font);
background: var(--bg);
color: var(--text-primary);
-webkit-font-smoothing: antialiased;
min-height: 100vh;
}
.phone-frame {
width: 393px;
height: 852px;
margin: 20px auto;
border-radius: 44px;
overflow: hidden;
background: var(--bg);
box-shadow: 0 20px 60px rgba(0,0,0,0.2), 0 0 0 1px rgba(0,0,0,0.05);
position: relative;
display: flex;
flex-direction: column;
}
.status-bar {
height: 54px;
padding: 14px 24px 0;
display: flex;
justify-content: space-between;
align-items: center;
font-size: 15px;
font-weight: 600;
flex-shrink: 0;
}
.nav-bar {
height: 52px;
padding: 0 16px;
display: flex;
align-items: center;
justify-content: space-between;
flex-shrink: 0;
background: rgba(242,242,247,0.85);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
border-bottom: 0.5px solid var(--separator);
}
.nav-title {
font-size: 17px;
font-weight: 600;
position: absolute;
left: 50%;
transform: translateX(-50%);
}
.nav-btn {
background: none;
border: none;
font-size: 17px;
color: var(--primary);
cursor: pointer;
font-family: var(--font);
padding: 8px 4px;
}
.nav-btn.secondary { color: var(--text-secondary); }
.content {
flex: 1;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
}
.content::-webkit-scrollbar { display: none; }
/* ===== 筛选Tab ===== */
.filter-tabs {
display: flex;
padding: 8px 16px;
gap: 6px;
}
.filter-tab {
flex: 1;
padding: 7px 0;
border-radius: var(--radius-sm);
text-align: center;
font-size: 13px;
font-weight: 500;
cursor: pointer;
transition: all 0.25s ease;
border: none;
background: var(--bg-card);
color: var(--text-secondary);
}
.filter-tab.active {
background: var(--primary-light);
color: var(--primary);
font-weight: 600;
}
/* ===== 统计概览 ===== */
.stats-bar {
display: flex;
padding: 0 16px 12px;
gap: 8px;
}
.stat-chip {
padding: 5px 10px;
border-radius: 20px;
font-size: 12px;
font-weight: 500;
background: var(--bg-card);
color: var(--text-secondary);
box-shadow: var(--shadow-sm);
}
.stat-chip .num { font-weight: 700; color: var(--text-primary); }
/* ===== 笔记卡片 ===== */
.note-list {
padding: 0 16px 100px;
display: flex;
flex-direction: column;
gap: 10px;
}
.note-card {
background: var(--bg-card);
border-radius: var(--radius-lg);
padding: 16px;
box-shadow: var(--shadow-sm);
cursor: pointer;
transition: transform 0.2s ease, box-shadow 0.2s ease;
position: relative;
overflow: hidden;
}
.note-card:active {
transform: scale(0.98);
box-shadow: var(--shadow-md);
}
.note-card .type-badge {
position: absolute;
top: 0;
right: 0;
padding: 4px 10px 4px 12px;
border-radius: 0 var(--radius-lg) 0 var(--radius-lg);
font-size: 11px;
font-weight: 600;
}
.type-badge.note { background: var(--primary-light); color: var(--primary); }
.type-badge.excerpt { background: rgba(255,149,0,0.12); color: var(--orange); }
.type-badge.checklist { background: rgba(52,199,89,0.12); color: var(--green); }
.note-card .title {
font-size: 17px;
font-weight: 600;
line-height: 1.35;
margin-bottom: 6px;
padding-right: 60px;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.note-card .preview {
font-size: 14px;
color: var(--text-secondary);
line-height: 1.55;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
margin-bottom: 10px;
}
.note-card .meta {
display: flex;
align-items: center;
gap: 8px;
font-size: 12px;
color: var(--text-hint);
}
.note-card .meta .dot {
width: 3px;
height: 3px;
border-radius: 50%;
background: var(--text-hint);
}
.note-card .category-tag {
padding: 2px 8px;
border-radius: 4px;
font-size: 11px;
font-weight: 500;
background: rgba(175,82,222,0.1);
color: var(--purple);
}
/* ===== 清单样式 ===== */
.checklist-items {
margin-bottom: 10px;
}
.checklist-item {
display: flex;
align-items: center;
gap: 8px;
padding: 3px 0;
font-size: 14px;
color: var(--text-secondary);
}
.checklist-item .check {
width: 18px;
height: 18px;
border-radius: 50%;
border: 1.5px solid var(--text-hint);
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
font-size: 10px;
}
.checklist-item .check.done {
background: var(--green);
border-color: var(--green);
color: white;
}
.checklist-item.done-text {
text-decoration: line-through;
color: var(--text-hint);
}
/* ===== 摘抄样式 ===== */
.excerpt-source {
display: flex;
align-items: center;
gap: 6px;
padding: 8px 10px;
background: rgba(255,149,0,0.06);
border-radius: var(--radius-sm);
margin-bottom: 8px;
font-size: 12px;
color: var(--orange);
}
.excerpt-source .icon { font-size: 14px; }
/* ===== FAB ===== */
.fab {
position: absolute;
bottom: 24px;
right: 20px;
width: 56px;
height: 56px;
border-radius: 50%;
background: var(--primary);
color: white;
border: none;
font-size: 28px;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 4px 16px rgba(0,122,255,0.4);
cursor: pointer;
transition: transform 0.2s ease;
z-index: 10;
}
.fab:active { transform: scale(0.9); }
/* ===== 空状态 ===== */
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 80px 40px;
text-align: center;
}
.empty-state .icon { font-size: 56px; margin-bottom: 16px; }
.empty-state .title { font-size: 20px; font-weight: 600; margin-bottom: 8px; }
.empty-state .desc { font-size: 15px; color: var(--text-secondary); line-height: 1.5; }
/* ===== 搜索栏 ===== */
.search-bar {
padding: 0 16px 8px;
}
.search-input {
width: 100%;
padding: 9px 12px 9px 34px;
border-radius: var(--radius-sm);
border: none;
background: rgba(118,118,128,0.12);
font-size: 15px;
font-family: var(--font);
color: var(--text-primary);
outline: none;
}
.search-icon {
position: absolute;
left: 28px;
top: 50%;
transform: translateY(-50%);
font-size: 14px;
color: var(--text-hint);
}
/* ===== 底部安全区 ===== */
.home-indicator {
height: 34px;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.home-indicator::after {
content: '';
width: 134px;
height: 5px;
border-radius: 3px;
background: rgba(0,0,0,0.15);
}
/* ===== 页面切换Tab ===== */
.page-tabs {
display: flex;
justify-content: center;
gap: 12px;
padding: 16px;
background: #1C1C1E;
position: fixed;
bottom: 0;
left: 0;
right: 0;
z-index: 100;
}
.page-tab {
padding: 8px 20px;
border-radius: 20px;
font-size: 13px;
font-weight: 600;
border: none;
cursor: pointer;
transition: all 0.2s ease;
font-family: var(--font);
}
.page-tab.active {
background: var(--primary);
color: white;
}
.page-tab:not(.active) {
background: rgba(255,255,255,0.1);
color: rgba(255,255,255,0.6);
}
/* ===== 方案B: 卡片网格 ===== */
.note-grid {
padding: 0 16px 100px;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 10px;
}
.note-grid .note-card {
padding: 14px;
}
.note-grid .note-card .title {
font-size: 15px;
padding-right: 0;
-webkit-line-clamp: 2;
}
.note-grid .note-card .preview {
font-size: 13px;
-webkit-line-clamp: 4;
}
/* ===== 方案C: 时间线 ===== */
.timeline {
padding: 0 16px 100px;
}
.timeline-date {
font-size: 13px;
font-weight: 600;
color: var(--text-secondary);
padding: 12px 0 6px 28px;
position: relative;
}
.timeline-date::before {
content: '';
position: absolute;
left: 8px;
top: 50%;
width: 8px;
height: 8px;
border-radius: 50%;
background: var(--primary);
transform: translateY(-50%);
}
.timeline-line {
position: absolute;
left: 11px;
top: 0;
bottom: 0;
width: 2px;
background: var(--separator);
}
.timeline-item {
position: relative;
padding-left: 28px;
margin-bottom: 10px;
}
.timeline-item::before {
content: '';
position: absolute;
left: 5px;
top: 20px;
width: 12px;
height: 12px;
border-radius: 50%;
border: 2px solid var(--primary);
background: var(--bg);
}
.timeline-item .note-card {
margin-left: 0;
}
/* ===== 动画 ===== */
@keyframes fadeInUp {
from { opacity: 0; transform: translateY(12px); }
to { opacity: 1; transform: translateY(0); }
}
.note-card {
animation: fadeInUp 0.35s ease both;
}
.note-card:nth-child(1) { animation-delay: 0.05s; }
.note-card:nth-child(2) { animation-delay: 0.1s; }
.note-card:nth-child(3) { animation-delay: 0.15s; }
.note-card:nth-child(4) { animation-delay: 0.2s; }
.note-card:nth-child(5) { animation-delay: 0.25s; }
.note-card:nth-child(6) { animation-delay: 0.3s; }
/* ===== 深色模式 ===== */
@media (prefers-color-scheme: dark) {
:root {
--bg: #000000;
--bg-card: #1C1C1E;
--bg-grouped: #000000;
--text-primary: #FFFFFF;
--text-secondary: #98989D;
--text-hint: #636366;
--separator: rgba(84,84,88,0.65);
--primary-light: rgba(0,122,255,0.2);
--shadow-sm: 0 1px 3px rgba(0,0,0,0.3);
--shadow-md: 0 4px 12px rgba(0,0,0,0.4);
}
}
</style>
</head>
<body>
<!-- ===== 方案A: iOS列表风格 ===== -->
<div id="planA" class="phone-frame">
<div class="status-bar">
<span>9:41</span>
<span>📶 🔋</span>
</div>
<div class="nav-bar">
<button class="nav-btn secondary"> 返回</button>
<span class="nav-title">📝 我的笔记</span>
<button class="nav-btn"></button>
</div>
<div class="content">
<div class="search-bar" style="position:relative;">
<span class="search-icon">🔍</span>
<input class="search-input" placeholder="搜索笔记..." readonly>
</div>
<div class="filter-tabs">
<button class="filter-tab active">📋 全部</button>
<button class="filter-tab">📝 笔记</button>
<button class="filter-tab">✂️ 摘抄</button>
<button class="filter-tab">✅ 清单</button>
</div>
<div class="stats-bar">
<span class="stat-chip"><span class="num">12</span></span>
<span class="stat-chip">📝 <span class="num">6</span></span>
<span class="stat-chip">✂️ <span class="num">3</span></span>
<span class="stat-chip"><span class="num">3</span></span>
</div>
<div class="note-list">
<!-- 笔记类型 -->
<div class="note-card">
<span class="type-badge note">📝 笔记</span>
<div class="title">读《人间词话》有感</div>
<div class="preview">王国维先生的三重境界说,至今读来仍觉醍醐灌顶。昨夜西风凋碧树,独上高楼望尽天涯路…</div>
<div class="meta">
<span class="category-tag">读书笔记</span>
<span class="dot"></span>
<span>今天 14:30</span>
<span class="dot"></span>
<span>📖 诗词</span>
</div>
</div>
<!-- 摘抄类型 -->
<div class="note-card">
<span class="type-badge excerpt">✂️ 摘抄</span>
<div class="title">静夜思 — 李白</div>
<div class="excerpt-source">
<span class="icon">📖</span>
<span>摘自: 诗词 · 唐诗三百首</span>
</div>
<div class="preview">床前明月光,疑是地上霜。举头望明月,低头思故乡。</div>
<div class="meta">
<span>今天 10:15</span>
<span class="dot"></span>
<span>🌐 公开</span>
</div>
</div>
<!-- 清单类型 -->
<div class="note-card">
<span class="type-badge checklist">✅ 清单</span>
<div class="title">本周阅读计划</div>
<div class="checklist-items">
<div class="checklist-item">
<span class="check done"></span>
<span class="done-text">《人间词话》第一章节</span>
</div>
<div class="checklist-item">
<span class="check done"></span>
<span class="done-text">《浮生六记》序言</span>
</div>
<div class="checklist-item">
<span class="check"></span>
<span>《古文观止》选读三篇</span>
</div>
<div class="checklist-item">
<span class="check"></span>
<span>整理上周摘抄笔记</span>
</div>
</div>
<div class="meta">
<span class="category-tag">阅读计划</span>
<span class="dot"></span>
<span>昨天 20:00</span>
<span class="dot"></span>
<span>2/4 已完成</span>
</div>
</div>
<!-- 普通笔记2 -->
<div class="note-card">
<span class="type-badge note">📝 笔记</span>
<div class="title">关于「闲言」的设计思考</div>
<div class="preview">一款好的诗词应用,不应只是工具,更应是陪伴。在信息过载的时代,每天一句恰到好处的诗词…</div>
<div class="meta">
<span>4月28日</span>
<span class="dot"></span>
<span>仅自己可见</span>
</div>
</div>
<!-- 摘抄2 -->
<div class="note-card">
<span class="type-badge excerpt">✂️ 摘抄</span>
<div class="title">水调歌头 — 苏轼</div>
<div class="excerpt-source">
<span class="icon">📖</span>
<span>摘自: 诗词 · 宋词精选</span>
</div>
<div class="preview">明月几时有,把酒问青天。不知天上宫阙,今夕是何年…</div>
<div class="meta">
<span>4月27日</span>
</div>
</div>
<!-- 清单2 -->
<div class="note-card">
<span class="type-badge checklist">✅ 清单</span>
<div class="title">写作灵感收集</div>
<div class="checklist-items">
<div class="checklist-item">
<span class="check"></span>
<span>春日意象整理</span>
</div>
<div class="checklist-item">
<span class="check"></span>
<span>秋思相关诗词</span>
</div>
<div class="checklist-item">
<span class="check"></span>
<span>山水画意境词句</span>
</div>
</div>
<div class="meta">
<span>4月25日</span>
<span class="dot"></span>
<span>0/3 已完成</span>
</div>
</div>
</div>
</div>
<button class="fab">✏️</button>
<div class="home-indicator"></div>
</div>
<!-- ===== 方案B: 瀑布流双列 ===== -->
<div id="planB" class="phone-frame" style="display:none;">
<div class="status-bar">
<span>9:41</span>
<span>📶 🔋</span>
</div>
<div class="nav-bar">
<button class="nav-btn secondary"> 返回</button>
<span class="nav-title">📝 我的笔记</span>
<button class="nav-btn"></button>
</div>
<div class="content">
<div class="filter-tabs">
<button class="filter-tab active">📋 全部</button>
<button class="filter-tab">📝 笔记</button>
<button class="filter-tab">✂️ 摘抄</button>
<button class="filter-tab">✅ 清单</button>
</div>
<div class="note-grid">
<div class="note-card">
<span class="type-badge note">📝</span>
<div class="title">读《人间词话》有感</div>
<div class="preview">王国维先生的三重境界说,至今读来仍觉醍醐灌顶…</div>
<div class="meta"><span>今天</span></div>
</div>
<div class="note-card">
<span class="type-badge excerpt">✂️</span>
<div class="title">静夜思</div>
<div class="preview">床前明月光,疑是地上霜。举头望明月,低头思故乡。</div>
<div class="meta"><span>今天</span></div>
</div>
<div class="note-card">
<span class="type-badge checklist"></span>
<div class="title">本周阅读计划</div>
<div class="checklist-items">
<div class="checklist-item"><span class="check done"></span><span class="done-text">人间词话</span></div>
<div class="checklist-item"><span class="check"></span><span>古文观止</span></div>
</div>
<div class="meta"><span>昨天</span></div>
</div>
<div class="note-card">
<span class="type-badge note">📝</span>
<div class="title">关于「闲言」的设计思考</div>
<div class="preview">一款好的诗词应用,不应只是工具,更应是陪伴…</div>
<div class="meta"><span>4月28日</span></div>
</div>
<div class="note-card">
<span class="type-badge excerpt">✂️</span>
<div class="title">水调歌头</div>
<div class="preview">明月几时有,把酒问青天</div>
<div class="meta"><span>4月27日</span></div>
</div>
<div class="note-card">
<span class="type-badge note">📝</span>
<div class="title">春日随笔</div>
<div class="preview">春风又绿江南岸,万物复苏之际,心亦随之舒展…</div>
<div class="meta"><span>4月26日</span></div>
</div>
</div>
</div>
<button class="fab">✏️</button>
<div class="home-indicator"></div>
</div>
<!-- ===== 方案C: 时间线风格 ===== -->
<div id="planC" class="phone-frame" style="display:none;">
<div class="status-bar">
<span>9:41</span>
<span>📶 🔋</span>
</div>
<div class="nav-bar">
<button class="nav-btn secondary"> 返回</button>
<span class="nav-title">📝 我的笔记</span>
<button class="nav-btn"></button>
</div>
<div class="content">
<div class="filter-tabs">
<button class="filter-tab active">📋 全部</button>
<button class="filter-tab">📝 笔记</button>
<button class="filter-tab">✂️ 摘抄</button>
<button class="filter-tab">✅ 清单</button>
</div>
<div class="timeline" style="position:relative;">
<div class="timeline-line"></div>
<div class="timeline-date">今天</div>
<div class="timeline-item">
<div class="note-card">
<span class="type-badge note">📝 笔记</span>
<div class="title">读《人间词话》有感</div>
<div class="preview">王国维先生的三重境界说,至今读来仍觉醍醐灌顶…</div>
<div class="meta"><span>14:30</span></div>
</div>
</div>
<div class="timeline-item">
<div class="note-card">
<span class="type-badge excerpt">✂️ 摘抄</span>
<div class="title">静夜思 — 李白</div>
<div class="preview">床前明月光,疑是地上霜…</div>
<div class="meta"><span>10:15</span></div>
</div>
</div>
<div class="timeline-date">昨天</div>
<div class="timeline-item">
<div class="note-card">
<span class="type-badge checklist">✅ 清单</span>
<div class="title">本周阅读计划</div>
<div class="checklist-items">
<div class="checklist-item"><span class="check done"></span><span class="done-text">人间词话</span></div>
<div class="checklist-item"><span class="check"></span><span>古文观止</span></div>
</div>
<div class="meta"><span>20:00</span></div>
</div>
</div>
<div class="timeline-date">4月28日</div>
<div class="timeline-item">
<div class="note-card">
<span class="type-badge note">📝 笔记</span>
<div class="title">关于「闲言」的设计思考</div>
<div class="preview">一款好的诗词应用,不应只是工具…</div>
<div class="meta"><span>16:45</span></div>
</div>
</div>
</div>
</div>
<button class="fab">✏️</button>
<div class="home-indicator"></div>
</div>
<!-- ===== 底部切换 ===== -->
<div class="page-tabs">
<button class="page-tab active" onclick="switchPlan('A')">方案A<br><small>列表风格</small></button>
<button class="page-tab" onclick="switchPlan('B')">方案B<br><small>瀑布流</small></button>
<button class="page-tab" onclick="switchPlan('C')">方案C<br><small>时间线</small></button>
</div>
<script>
function switchPlan(plan) {
document.getElementById('planA').style.display = plan === 'A' ? 'flex' : 'none';
document.getElementById('planB').style.display = plan === 'B' ? 'flex' : 'none';
document.getElementById('planC').style.display = plan === 'C' ? 'flex' : 'none';
document.querySelectorAll('.page-tab').forEach((btn, i) => {
btn.classList.toggle('active', ['A','B','C'][i] === plan);
});
}
document.querySelectorAll('.filter-tab').forEach(tab => {
tab.addEventListener('click', function() {
this.parentElement.querySelectorAll('.filter-tab').forEach(t => t.classList.remove('active'));
this.classList.add('active');
});
});
</script>
</body>
</html>