项目初始化 - 创建完整项目结构(src/, data/, docs/, examples/, tests/) - 配置requirements.txt依赖 - 创建.gitignore P0基础框架 - 数据库模型:Record模型,6种分类类型 - 配置管理:YAML配置,支持AI/OCR/云存储/UI配置 - OCR模块:PaddleOCR本地识别,支持云端扩展 - AI模块:支持OpenAI/Claude/通义/Ollama,6种分类 - 存储模块:完整CRUD,搜索,统计,导入导出 - 主窗口框架:侧边栏导航,米白配色方案 - 图片处理:截图/剪贴板/文件选择/图片预览 - 处理流程整合:OCR→AI→存储串联,Markdown展示,剪贴板复制 - 分类浏览:卡片网格展示,分类筛选,搜索,详情查看 技术栈 - PyQt6 + SQLAlchemy + PaddleOCR + OpenAI/Claude SDK - 共47个Python文件,4000+行代码 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1091 lines
36 KiB
HTML
1091 lines
36 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>CutThenThink</title>
|
||
<style>
|
||
@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@400;500;600;700&family=Space+Grotesk:wght@400;500;600;700&display=swap');
|
||
|
||
:root {
|
||
/* 明亮配色方案 */
|
||
--bg-primary: #faf8f5;
|
||
--bg-secondary: #ffffff;
|
||
--bg-card: #ffffff;
|
||
--accent: #ff6b6b;
|
||
--accent-light: #ff8787;
|
||
--accent-soft: #ffe0e0;
|
||
--success: #51cf66;
|
||
--warning: #ffd43b;
|
||
--text-primary: #2d3436;
|
||
--text-secondary: #868e96;
|
||
--border: #e9ecef;
|
||
--border-light: #f1f3f5;
|
||
--shadow: 0 2px 12px rgba(0,0,0,0.06);
|
||
--shadow-hover: 0 8px 24px rgba(0,0,0,0.1);
|
||
|
||
/* 分类颜色 */
|
||
--color-todo: #ff6b6b;
|
||
--color-note: #4dabf7;
|
||
--color-idea: #ffd43b;
|
||
--color-ref: #51cf66;
|
||
--color-funny: #ff922b;
|
||
--color-text: #adb5bd;
|
||
}
|
||
|
||
* {
|
||
margin: 0;
|
||
padding: 0;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
body {
|
||
font-family: 'Noto Sans SC', sans-serif;
|
||
background: var(--bg-primary);
|
||
color: var(--text-primary);
|
||
height: 100vh;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.app {
|
||
display: flex;
|
||
height: 100vh;
|
||
}
|
||
|
||
/* 侧边栏 */
|
||
.sidebar {
|
||
width: 240px;
|
||
background: var(--bg-secondary);
|
||
border-right: 1px solid var(--border);
|
||
display: flex;
|
||
flex-direction: column;
|
||
padding: 20px 16px;
|
||
}
|
||
|
||
.logo {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
padding: 0 8px 24px;
|
||
border-bottom: 1px solid var(--border);
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.logo-icon {
|
||
width: 36px;
|
||
height: 36px;
|
||
background: var(--accent);
|
||
border-radius: 10px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 20px;
|
||
}
|
||
|
||
.logo-text {
|
||
font-family: 'Space Grotesk', sans-serif;
|
||
font-weight: 700;
|
||
font-size: 18px;
|
||
color: var(--text-primary);
|
||
}
|
||
|
||
.nav-section {
|
||
margin-bottom: 24px;
|
||
}
|
||
|
||
.nav-title {
|
||
font-size: 11px;
|
||
font-weight: 600;
|
||
text-transform: uppercase;
|
||
letter-spacing: 1px;
|
||
color: var(--text-secondary);
|
||
padding: 0 8px;
|
||
margin-bottom: 8px;
|
||
}
|
||
|
||
.nav-item {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
padding: 10px 12px;
|
||
border-radius: 8px;
|
||
cursor: pointer;
|
||
transition: all 0.2s;
|
||
font-size: 14px;
|
||
color: var(--text-secondary);
|
||
}
|
||
|
||
.nav-item:hover {
|
||
background: var(--bg-primary);
|
||
color: var(--text-primary);
|
||
}
|
||
|
||
.nav-item.active {
|
||
background: var(--accent-soft);
|
||
color: var(--accent);
|
||
font-weight: 500;
|
||
}
|
||
|
||
.nav-icon {
|
||
font-size: 18px;
|
||
width: 20px;
|
||
text-align: center;
|
||
}
|
||
|
||
.nav-count {
|
||
margin-left: auto;
|
||
font-size: 12px;
|
||
padding: 2px 6px;
|
||
background: var(--border);
|
||
border-radius: 10px;
|
||
}
|
||
|
||
.sidebar-footer {
|
||
margin-top: auto;
|
||
padding-top: 16px;
|
||
border-top: 1px solid var(--border);
|
||
}
|
||
|
||
/* 主内容区 */
|
||
.main {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.header {
|
||
height: 60px;
|
||
background: var(--bg-secondary);
|
||
border-bottom: 1px solid var(--border);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 0 24px;
|
||
}
|
||
|
||
.header-title {
|
||
font-size: 18px;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.header-actions {
|
||
display: flex;
|
||
gap: 12px;
|
||
}
|
||
|
||
.btn {
|
||
padding: 8px 16px;
|
||
border-radius: 8px;
|
||
border: none;
|
||
font-size: 14px;
|
||
font-weight: 500;
|
||
cursor: pointer;
|
||
transition: all 0.2s;
|
||
font-family: inherit;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
}
|
||
|
||
.btn-secondary {
|
||
background: var(--bg-primary);
|
||
color: var(--text-secondary);
|
||
}
|
||
|
||
.btn-secondary:hover {
|
||
background: var(--border);
|
||
}
|
||
|
||
.btn-primary {
|
||
background: var(--accent);
|
||
color: white;
|
||
}
|
||
|
||
.btn-primary:hover {
|
||
background: var(--accent-light);
|
||
transform: translateY(-1px);
|
||
box-shadow: var(--shadow-hover);
|
||
}
|
||
|
||
/* 内容页面 */
|
||
.content {
|
||
flex: 1;
|
||
overflow-y: auto;
|
||
padding: 24px;
|
||
}
|
||
|
||
/* 卡片网格 */
|
||
.card-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
|
||
gap: 16px;
|
||
}
|
||
|
||
.card {
|
||
background: var(--bg-card);
|
||
border-radius: 12px;
|
||
border: 1px solid var(--border);
|
||
padding: 16px;
|
||
transition: all 0.2s;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.card:hover {
|
||
border-color: var(--accent-light);
|
||
box-shadow: var(--shadow);
|
||
transform: translateY(-2px);
|
||
}
|
||
|
||
.card-image {
|
||
width: 100%;
|
||
height: 160px;
|
||
border-radius: 8px;
|
||
overflow: hidden;
|
||
background: var(--bg-primary);
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
.card-image img {
|
||
width: 100%;
|
||
height: 100%;
|
||
object-fit: cover;
|
||
}
|
||
|
||
.card-badge {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 4px;
|
||
padding: 4px 8px;
|
||
border-radius: 6px;
|
||
font-size: 12px;
|
||
font-weight: 500;
|
||
margin-bottom: 8px;
|
||
}
|
||
|
||
.badge-todo { background: #ffe0e0; color: var(--color-todo); }
|
||
.badge-note { background: #e7f5ff; color: var(--color-note); }
|
||
.badge-idea { background: #fff9db; color: #f59f00; }
|
||
.badge-ref { background: #d3f9d8; color: var(--color-ref); }
|
||
.badge-funny { background: #ffe8cc; color: var(--color-funny); }
|
||
.badge-text { background: #f8f9fa; color: var(--color-text); }
|
||
|
||
.card-title {
|
||
font-size: 14px;
|
||
color: var(--text-secondary);
|
||
margin-bottom: 8px;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.card-preview {
|
||
font-size: 13px;
|
||
color: var(--text-primary);
|
||
line-height: 1.5;
|
||
display: -webkit-box;
|
||
-webkit-line-clamp: 2;
|
||
-webkit-box-orient: vertical;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.card-footer {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-top: 12px;
|
||
padding-top: 12px;
|
||
border-top: 1px solid var(--border-light);
|
||
}
|
||
|
||
.card-date {
|
||
font-size: 12px;
|
||
color: var(--text-secondary);
|
||
}
|
||
|
||
.card-actions {
|
||
display: flex;
|
||
gap: 8px;
|
||
}
|
||
|
||
.card-btn {
|
||
padding: 4px 10px;
|
||
font-size: 12px;
|
||
border-radius: 6px;
|
||
border: 1px solid var(--border);
|
||
background: transparent;
|
||
color: var(--text-secondary);
|
||
cursor: pointer;
|
||
transition: all 0.2s;
|
||
}
|
||
|
||
.card-btn:hover {
|
||
border-color: var(--accent);
|
||
color: var(--accent);
|
||
}
|
||
|
||
/* 批量上传页面 */
|
||
.batch-upload {
|
||
display: flex;
|
||
gap: 20px;
|
||
height: 100%;
|
||
}
|
||
|
||
.upload-zone {
|
||
flex: 0 0 300px;
|
||
background: var(--bg-card);
|
||
border-radius: 16px;
|
||
border: 2px dashed var(--border);
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
transition: all 0.3s;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.upload-zone:hover {
|
||
border-color: var(--accent);
|
||
background: var(--accent-soft);
|
||
}
|
||
|
||
.upload-icon {
|
||
width: 64px;
|
||
height: 64px;
|
||
background: var(--accent-soft);
|
||
border-radius: 50%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 28px;
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.upload-text {
|
||
font-size: 14px;
|
||
color: var(--text-secondary);
|
||
text-align: center;
|
||
}
|
||
|
||
.upload-text strong {
|
||
color: var(--accent);
|
||
}
|
||
|
||
.upload-hint {
|
||
font-size: 12px;
|
||
color: var(--text-secondary);
|
||
margin-top: 8px;
|
||
}
|
||
|
||
.image-list {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 12px;
|
||
overflow-y: auto;
|
||
}
|
||
|
||
.image-item {
|
||
display: flex;
|
||
gap: 12px;
|
||
background: var(--bg-card);
|
||
border-radius: 12px;
|
||
padding: 12px;
|
||
border: 1px solid var(--border);
|
||
}
|
||
|
||
.image-item input[type="checkbox"] {
|
||
width: 18px;
|
||
height: 18px;
|
||
margin-top: 4px;
|
||
accent-color: var(--accent);
|
||
}
|
||
|
||
.image-item-preview {
|
||
width: 60px;
|
||
height: 60px;
|
||
border-radius: 8px;
|
||
overflow: hidden;
|
||
background: var(--bg-primary);
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.image-item-preview img {
|
||
width: 100%;
|
||
height: 100%;
|
||
object-fit: cover;
|
||
}
|
||
|
||
.image-item-info {
|
||
flex: 1;
|
||
}
|
||
|
||
.image-item-name {
|
||
font-size: 14px;
|
||
font-weight: 500;
|
||
margin-bottom: 4px;
|
||
}
|
||
|
||
.image-item-meta {
|
||
font-size: 12px;
|
||
color: var(--text-secondary);
|
||
}
|
||
|
||
.image-item-remove {
|
||
padding: 4px 10px;
|
||
font-size: 12px;
|
||
border-radius: 6px;
|
||
border: 1px solid var(--border);
|
||
background: transparent;
|
||
color: var(--text-secondary);
|
||
cursor: pointer;
|
||
}
|
||
|
||
.image-item-remove:hover {
|
||
border-color: var(--accent);
|
||
color: var(--accent);
|
||
}
|
||
|
||
/* 空状态 */
|
||
.empty-state {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
flex: 1;
|
||
color: var(--text-secondary);
|
||
}
|
||
|
||
.empty-icon {
|
||
font-size: 64px;
|
||
margin-bottom: 16px;
|
||
opacity: 0.6;
|
||
}
|
||
|
||
.empty-text {
|
||
font-size: 16px;
|
||
}
|
||
|
||
/* 设置页面 */
|
||
.settings-page {
|
||
max-width: 600px;
|
||
}
|
||
|
||
.settings-section {
|
||
background: var(--bg-card);
|
||
border-radius: 12px;
|
||
padding: 20px;
|
||
margin-bottom: 16px;
|
||
border: 1px solid var(--border);
|
||
}
|
||
|
||
.settings-section h3 {
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
margin-bottom: 16px;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
}
|
||
|
||
.settings-row {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 12px 0;
|
||
border-bottom: 1px solid var(--border-light);
|
||
}
|
||
|
||
.settings-row:last-child {
|
||
border-bottom: none;
|
||
}
|
||
|
||
.settings-label {
|
||
font-size: 14px;
|
||
color: var(--text-primary);
|
||
}
|
||
|
||
.settings-desc {
|
||
font-size: 12px;
|
||
color: var(--text-secondary);
|
||
margin-top: 2px;
|
||
}
|
||
|
||
.settings-input {
|
||
padding: 8px 12px;
|
||
border: 1px solid var(--border);
|
||
border-radius: 6px;
|
||
font-size: 14px;
|
||
width: 200px;
|
||
font-family: inherit;
|
||
}
|
||
|
||
.settings-select {
|
||
padding: 8px 12px;
|
||
border: 1px solid var(--border);
|
||
border-radius: 6px;
|
||
font-size: 14px;
|
||
background: white;
|
||
font-family: inherit;
|
||
}
|
||
|
||
/* 页面切换 */
|
||
.page {
|
||
display: none;
|
||
}
|
||
|
||
.page.active {
|
||
display: block;
|
||
}
|
||
|
||
/* 详情弹窗 */
|
||
.modal {
|
||
display: none;
|
||
position: fixed;
|
||
inset: 0;
|
||
background: rgba(0,0,0,0.5);
|
||
z-index: 1000;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.modal.active {
|
||
display: flex;
|
||
}
|
||
|
||
.modal-content {
|
||
background: white;
|
||
border-radius: 16px;
|
||
width: 90%;
|
||
max-width: 600px;
|
||
max-height: 80vh;
|
||
overflow: hidden;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.modal-header {
|
||
padding: 20px;
|
||
border-bottom: 1px solid var(--border);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
}
|
||
|
||
.modal-header h2 {
|
||
font-size: 18px;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.modal-close {
|
||
width: 32px;
|
||
height: 32px;
|
||
border-radius: 8px;
|
||
border: none;
|
||
background: var(--bg-primary);
|
||
cursor: pointer;
|
||
font-size: 18px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.modal-body {
|
||
padding: 20px;
|
||
overflow-y: auto;
|
||
}
|
||
|
||
.modal-image {
|
||
width: 100%;
|
||
border-radius: 12px;
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.modal-markdown {
|
||
background: var(--bg-primary);
|
||
border-radius: 12px;
|
||
padding: 16px;
|
||
font-size: 14px;
|
||
line-height: 1.7;
|
||
}
|
||
|
||
.modal-footer {
|
||
padding: 16px 20px;
|
||
border-top: 1px solid var(--border);
|
||
display: flex;
|
||
gap: 12px;
|
||
justify-content: flex-end;
|
||
}
|
||
|
||
/* 进度条 */
|
||
.progress-bar {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
height: 3px;
|
||
background: var(--accent);
|
||
transform-origin: left;
|
||
transform: scaleX(0);
|
||
transition: transform 0.3s;
|
||
z-index: 1000;
|
||
}
|
||
|
||
.progress-bar.active {
|
||
animation: progress 2s ease-in-out infinite;
|
||
}
|
||
|
||
@keyframes progress {
|
||
0% { transform: scaleX(0); }
|
||
50% { transform: scaleX(0.5); }
|
||
100% { transform: scaleX(1); }
|
||
}
|
||
|
||
/* 状态标签 */
|
||
.status-badge {
|
||
padding: 4px 8px;
|
||
border-radius: 6px;
|
||
font-size: 11px;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.status-pending { background: var(--bg-primary); color: var(--text-secondary); }
|
||
.status-processing { background: var(--accent-soft); color: var(--accent); }
|
||
.status-done { background: #d3f9d8; color: var(--success); }
|
||
.status-error { background: #ffe3e3; color: var(--accent); }
|
||
|
||
#file-input { display: none; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="progress-bar" id="progress-bar"></div>
|
||
|
||
<div class="app">
|
||
<!-- 侧边栏 -->
|
||
<aside class="sidebar">
|
||
<div class="logo">
|
||
<div class="logo-icon">✂️</div>
|
||
<div class="logo-text">CutThenThink</div>
|
||
</div>
|
||
|
||
<nav class="nav-section">
|
||
<div class="nav-title">浏览</div>
|
||
<div class="nav-item active" data-page="all" onclick="switchPage('all')">
|
||
<span class="nav-icon">📋</span>
|
||
<span>全部</span>
|
||
<span class="nav-count">12</span>
|
||
</div>
|
||
<div class="nav-item" data-page="todo" onclick="switchPage('todo')">
|
||
<span class="nav-icon">✅</span>
|
||
<span>待办事项</span>
|
||
<span class="nav-count">4</span>
|
||
</div>
|
||
<div class="nav-item" data-page="note" onclick="switchPage('note')">
|
||
<span class="nav-icon">📝</span>
|
||
<span>笔记</span>
|
||
<span class="nav-count">3</span>
|
||
</div>
|
||
<div class="nav-item" data-page="idea" onclick="switchPage('idea')">
|
||
<span class="nav-icon">💡</span>
|
||
<span>灵感</span>
|
||
<span class="nav-count">2</span>
|
||
</div>
|
||
<div class="nav-item" data-page="ref" onclick="switchPage('ref')">
|
||
<span class="nav-icon">📚</span>
|
||
<span>参考资料</span>
|
||
<span class="nav-count">2</span>
|
||
</div>
|
||
<div class="nav-item" data-page="funny" onclick="switchPage('funny')">
|
||
<span class="nav-icon">😄</span>
|
||
<span>搞笑文案</span>
|
||
<span class="nav-count">1</span>
|
||
</div>
|
||
<div class="nav-item" data-page="text" onclick="switchPage('text')">
|
||
<span class="nav-icon">📄</span>
|
||
<span>纯文本</span>
|
||
<span class="nav-count">0</span>
|
||
</div>
|
||
</nav>
|
||
|
||
<nav class="nav-section">
|
||
<div class="nav-title">操作</div>
|
||
<div class="nav-item" data-page="upload" onclick="switchPage('upload')">
|
||
<span class="nav-icon">📤</span>
|
||
<span>批量上传</span>
|
||
</div>
|
||
<div class="nav-item" data-page="settings" onclick="switchPage('settings')">
|
||
<span class="nav-icon">⚙️</span>
|
||
<span>设置</span>
|
||
</div>
|
||
</nav>
|
||
|
||
<div class="sidebar-footer">
|
||
<div class="nav-item">
|
||
<span class="nav-icon">🔄</span>
|
||
<span>同步状态</span>
|
||
<span class="status-badge status-done">已同步</span>
|
||
</div>
|
||
</div>
|
||
</aside>
|
||
|
||
<!-- 主内容 -->
|
||
<main class="main">
|
||
<header class="header">
|
||
<h1 class="header-title" id="page-title">全部</h1>
|
||
<div class="header-actions" id="header-actions">
|
||
<button class="btn btn-secondary" onclick="alert('快速截图')">📷 截图</button>
|
||
<button class="btn btn-primary">➕ 新建</button>
|
||
</div>
|
||
</header>
|
||
|
||
<div class="content">
|
||
<!-- 全部/分类页面 -->
|
||
<div class="page active" id="page-all">
|
||
<div class="card-grid" id="card-grid">
|
||
<!-- 示例卡片 -->
|
||
<div class="card" onclick="openDetail(1)">
|
||
<div class="card-image">
|
||
<img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='320' height='160'%3E%3Crect fill='%23f1f3f5' width='320' height='160'/%3E%3Ctext x='50%25' y='50%25' text-anchor='middle' dy='.3em' fill='%23adb5bd' font-size='24'%3E📸%3C/text%3E%3C/svg%3E" alt="">
|
||
</div>
|
||
<span class="card-badge badge-todo">✅ 待办事项</span>
|
||
<div class="card-title">项目任务清单截图</div>
|
||
<div class="card-preview">## 待办事项\n- [ ] 完成界面设计\n- [ ] 编写 API 文档\n- [ ] 测试 OCR 功能...</div>
|
||
<div class="card-footer">
|
||
<span class="card-date">今天 14:30</span>
|
||
<div class="card-actions">
|
||
<button class="card-btn">复制</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card" onclick="openDetail(2)">
|
||
<div class="card-image">
|
||
<img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='320' height='160'%3E%3Crect fill='%23e7f5ff' width='320' height='160'/%3E%3Ctext x='50%25' y='50%25' text-anchor='middle' dy='.3em' fill='%234dabf7' font-size='24'%3E💭%3C/text%3E%3C/svg%3E" alt="">
|
||
</div>
|
||
<span class="card-badge badge-note">📝 笔记</span>
|
||
<div class="card-title">技术文章要点</div>
|
||
<div class="card-preview">Python 异步编程的关键点:\n1. async/await 语法\n2. 事件循环机制\n3. 协程的概念...</div>
|
||
<div class="card-footer">
|
||
<span class="card-date">昨天 09:15</span>
|
||
<div class="card-actions">
|
||
<button class="card-btn">复制</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card" onclick="openDetail(3)">
|
||
<div class="card-image">
|
||
<img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='320' height='160'%3E%3Crect fill='%23fff9db' width='320' height='160'/%3E%3Ctext x='50%25' y='50%25' text-anchor='middle' dy='.3em' fill='%23ffd43b' font-size='24'%3E💡%3C/text%3E%3C/svg%3E" alt="">
|
||
</div>
|
||
<span class="card-badge badge-idea">💡 灵感</span>
|
||
<div class="card-title">产品创意</div>
|
||
<div class="card-preview">做一个能自动整理桌面的工具,通过 AI 识别文件类型并分类...</div>
|
||
<div class="card-footer">
|
||
<span class="card-date">2天前</span>
|
||
<div class="card-actions">
|
||
<button class="card-btn">复制</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 批量上传页面 -->
|
||
<div class="page" id="page-upload">
|
||
<div class="batch-upload">
|
||
<div class="upload-zone" id="upload-zone">
|
||
<div class="upload-icon">📁</div>
|
||
<div class="upload-text"><strong>点击选择</strong> 或拖放图片</div>
|
||
<div class="upload-hint">支持 PNG, JPG, WEBP</div>
|
||
</div>
|
||
<div class="image-list" id="upload-list">
|
||
<div class="empty-state">
|
||
<div class="empty-icon">📷</div>
|
||
<div class="empty-text">暂无图片,请从左侧添加</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 设置页面 -->
|
||
<div class="page settings-page" id="page-settings">
|
||
<div class="settings-section">
|
||
<h3>🤖 AI 配置</h3>
|
||
<div class="settings-row">
|
||
<div>
|
||
<div class="settings-label">AI 提供商</div>
|
||
<div class="settings-desc">选择用于分类和生成计划的 AI 服务</div>
|
||
</div>
|
||
<select class="settings-select">
|
||
<option>OpenAI (GPT-4)</option>
|
||
<option>Anthropic (Claude)</option>
|
||
<option>通义千问</option>
|
||
<option>本地模型 (Ollama)</option>
|
||
</select>
|
||
</div>
|
||
<div class="settings-row">
|
||
<div>
|
||
<div class="settings-label">API Key</div>
|
||
<div class="settings-desc">您的 API 密钥</div>
|
||
</div>
|
||
<input type="password" class="settings-input" placeholder="sk-***">
|
||
</div>
|
||
<div class="settings-row">
|
||
<div>
|
||
<div class="settings-label">模型名称</div>
|
||
<div class="settings-desc">要使用的模型</div>
|
||
</div>
|
||
<input type="text" class="settings-input" value="gpt-4o">
|
||
</div>
|
||
</div>
|
||
|
||
<div class="settings-section">
|
||
<h3>🔍 OCR 配置</h3>
|
||
<div class="settings-row">
|
||
<div>
|
||
<div class="settings-label">OCR 提供商</div>
|
||
<div class="settings-desc">优先使用的 OCR 服务</div>
|
||
</div>
|
||
<select class="settings-select">
|
||
<option>本地 PaddleOCR</option>
|
||
<option>百度 OCR</option>
|
||
<option>腾讯 OCR</option>
|
||
<option>自定义 API</option>
|
||
</select>
|
||
</div>
|
||
<div class="settings-row">
|
||
<div>
|
||
<div class="settings-label">失败时降级到本地</div>
|
||
<div class="settings-desc">云端 OCR 失败时自动使用本地 OCR</div>
|
||
</div>
|
||
<input type="checkbox" checked>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="settings-section">
|
||
<h3>☁️ 云存储配置(可选)</h3>
|
||
<div class="settings-row">
|
||
<div>
|
||
<div class="settings-label">存储类型</div>
|
||
<div class="settings-desc">选择云存储服务</div>
|
||
</div>
|
||
<select class="settings-select">
|
||
<option>不使用云存储</option>
|
||
<option>WebDAV</option>
|
||
<option>阿里云 OSS</option>
|
||
<option>AWS S3</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="settings-section">
|
||
<h3>📝 提示词模板</h3>
|
||
<div class="settings-row">
|
||
<div>
|
||
<div class="settings-label">分类提示词</div>
|
||
<div class="settings-desc">自定义 AI 分类规则</div>
|
||
</div>
|
||
<button class="btn btn-secondary">编辑</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</main>
|
||
</div>
|
||
|
||
<!-- 详情弹窗 -->
|
||
<div class="modal" id="detail-modal">
|
||
<div class="modal-content">
|
||
<div class="modal-header">
|
||
<h2>详情</h2>
|
||
<button class="modal-close" onclick="closeDetail()">✕</button>
|
||
</div>
|
||
<div class="modal-body">
|
||
<img src="" class="modal-image" id="modal-image" alt="">
|
||
<div class="modal-markdown" id="modal-content">
|
||
## 待办事项
|
||
|
||
- [ ] 完成界面设计
|
||
- [ ] 编写 API 文档
|
||
- [ ] 测试 OCR 功能
|
||
|
||
---
|
||
*AI 分析于 2024-01-15 14:30*
|
||
</div>
|
||
</div>
|
||
<div class="modal-footer">
|
||
<button class="btn btn-secondary" onclick="closeDetail()">关闭</button>
|
||
<button class="btn btn-primary" onclick="copyMarkdown()">📋 复制 Markdown</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<input type="file" id="file-input" multiple accept="image/png,image/jpeg,image/webp">
|
||
|
||
<script>
|
||
let uploadImages = [];
|
||
|
||
// 页面切换
|
||
function switchPage(page) {
|
||
// 更新导航
|
||
document.querySelectorAll('.nav-item').forEach(item => {
|
||
item.classList.remove('active');
|
||
});
|
||
document.querySelector(`[data-page="${page}"]`).classList.add('active');
|
||
|
||
// 更新页面
|
||
document.querySelectorAll('.page').forEach(p => p.classList.remove('active'));
|
||
document.getElementById(`page-${page}`).classList.add('active');
|
||
|
||
// 更新标题
|
||
const titles = {
|
||
all: '全部',
|
||
todo: '待办事项',
|
||
note: '笔记',
|
||
idea: '灵感',
|
||
ref: '参考资料',
|
||
funny: '搞笑文案',
|
||
text: '纯文本',
|
||
upload: '批量上传',
|
||
settings: '设置'
|
||
};
|
||
document.getElementById('page-title').textContent = titles[page] || '全部';
|
||
|
||
// 更新头部按钮
|
||
const headerActions = document.getElementById('header-actions');
|
||
if (page === 'upload') {
|
||
headerActions.innerHTML = `
|
||
<button class="btn btn-secondary" onclick="clearUpload()">清空</button>
|
||
<button class="btn btn-primary" onclick="processUpload()">开始处理</button>
|
||
`;
|
||
} else if (page === 'settings') {
|
||
headerActions.innerHTML = '';
|
||
} else {
|
||
headerActions.innerHTML = `
|
||
<button class="btn btn-secondary" onclick="alert('快速截图')">📷 截图</button>
|
||
<button class="btn btn-primary">➕ 新建</button>
|
||
`;
|
||
}
|
||
}
|
||
|
||
// 详情弹窗
|
||
function openDetail(id) {
|
||
document.getElementById('detail-modal').classList.add('active');
|
||
}
|
||
|
||
function closeDetail() {
|
||
document.getElementById('detail-modal').classList.remove('active');
|
||
}
|
||
|
||
function copyMarkdown() {
|
||
const content = document.getElementById('modal-content').textContent;
|
||
navigator.clipboard.writeText(content);
|
||
alert('已复制到剪贴板');
|
||
}
|
||
|
||
// 批量上传
|
||
const uploadZone = document.getElementById('upload-zone');
|
||
const fileInput = document.getElementById('file-input');
|
||
const uploadList = document.getElementById('upload-list');
|
||
|
||
uploadZone.addEventListener('click', () => fileInput.click());
|
||
fileInput.addEventListener('change', (e) => handleFiles(e.target.files));
|
||
|
||
uploadZone.addEventListener('dragover', (e) => {
|
||
e.preventDefault();
|
||
uploadZone.style.borderColor = 'var(--accent)';
|
||
});
|
||
|
||
uploadZone.addEventListener('dragleave', () => {
|
||
uploadZone.style.borderColor = 'var(--border)';
|
||
});
|
||
|
||
uploadZone.addEventListener('drop', (e) => {
|
||
e.preventDefault();
|
||
uploadZone.style.borderColor = 'var(--border)';
|
||
handleFiles(e.dataTransfer.files);
|
||
});
|
||
|
||
function handleFiles(files) {
|
||
for (const file of files) {
|
||
if (file.type.startsWith('image/')) {
|
||
const reader = new FileReader();
|
||
reader.onload = (e) => {
|
||
uploadImages.push({
|
||
name: file.name,
|
||
size: formatSize(file.size),
|
||
preview: e.target.result
|
||
});
|
||
renderUploadList();
|
||
};
|
||
reader.readAsDataURL(file);
|
||
}
|
||
}
|
||
}
|
||
|
||
function formatSize(bytes) {
|
||
if (bytes < 1024) return bytes + ' B';
|
||
if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB';
|
||
return (bytes / (1024 * 1024)).toFixed(1) + ' MB';
|
||
}
|
||
|
||
function renderUploadList() {
|
||
if (uploadImages.length === 0) {
|
||
uploadList.innerHTML = `
|
||
<div class="empty-state">
|
||
<div class="empty-icon">📷</div>
|
||
<div class="empty-text">暂无图片,请从左侧添加</div>
|
||
</div>
|
||
`;
|
||
return;
|
||
}
|
||
|
||
uploadList.innerHTML = uploadImages.map((img, i) => `
|
||
<div class="image-item">
|
||
<input type="checkbox" checked>
|
||
<div class="image-item-preview">
|
||
<img src="${img.preview}" alt="${img.name}">
|
||
</div>
|
||
<div class="image-item-info">
|
||
<div class="image-item-name">${img.name}</div>
|
||
<div class="image-item-meta">${img.size}</div>
|
||
</div>
|
||
<button class="image-item-remove" onclick="removeUpload(${i})">移除</button>
|
||
</div>
|
||
`).join('');
|
||
}
|
||
|
||
function removeUpload(index) {
|
||
uploadImages.splice(index, 1);
|
||
renderUploadList();
|
||
}
|
||
|
||
function clearUpload() {
|
||
uploadImages = [];
|
||
renderUploadList();
|
||
}
|
||
|
||
function processUpload() {
|
||
if (uploadImages.length === 0) {
|
||
alert('请先添加图片');
|
||
return;
|
||
}
|
||
document.getElementById('progress-bar').classList.add('active');
|
||
setTimeout(() => {
|
||
document.getElementById('progress-bar').classList.remove('active');
|
||
alert('处理完成!');
|
||
uploadImages = [];
|
||
renderUploadList();
|
||
}, 2000);
|
||
}
|
||
|
||
// 点击模态框背景关闭
|
||
document.getElementById('detail-modal').addEventListener('click', (e) => {
|
||
if (e.target.id === 'detail-modal') {
|
||
closeDetail();
|
||
}
|
||
});
|
||
</script>
|
||
</body>
|
||
</html>
|