Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 75 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,75 @@
# Notes
# 网页版备忘录

一个基于Python Flask框架的简单备忘录应用,支持添加、删除、修改备忘录,以及按优先级排序和完成状态分组显示。

## 功能特性

1. **备忘录管理**:添加、删除、修改备忘录
2. **备忘录详情**:查看备忘录的详细信息
3. **时间管理**:自动记录创建时间,支持设置预计完成时间
4. **优先级管理**:支持设置P0、P1、P2三个优先级,并按优先级排序
5. **完成状态**:支持标记备忘录为完成/未完成,并分组显示

## 技术栈

- **后端**:Python Flask
- **前端**:HTML、CSS、Bootstrap 5
- **数据存储**:JSON文件

## 安装和运行

1. **安装依赖**:
```bash
pip install -r requirements.txt
```

2. **运行应用**:
```bash
python app.py
```

3. **访问应用**:在浏览器中打开 `http://localhost:5000`

## 使用说明

### 添加备忘录

1. 点击首页的"添加备忘录"按钮
2. 填写标题、详情、预计完成时间和优先级
3. 点击"添加"按钮保存

### 查看备忘录详情

1. 在首页点击备忘录标题
2. 即可查看备忘录的详细信息

### 编辑备忘录

1. 在首页或详情页点击"编辑"按钮
2. 修改备忘录信息
3. 点击"保存"按钮

### 删除备忘录

1. 在首页或详情页点击"删除"按钮
2. 确认删除操作

### 标记完成/未完成

1. 在首页或详情页点击"标记完成"或"标记未完成"按钮
2. 备忘录会自动分组显示

## 项目结构

```
Notes/
├── app.py # Flask应用主文件
├── requirements.txt # 项目依赖
├── memos.json # 备忘录数据文件(自动生成)
└── templates/ # HTML模板文件夹
├── base.html # 基础模板
├── index.html # 首页模板
├── add.html # 添加备忘录模板
├── detail.html # 备忘录详情模板
└── edit.html # 编辑备忘录模板
```
138 changes: 138 additions & 0 deletions app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
from flask import Flask, render_template, request, redirect, url_for, flash
from datetime import datetime
import json
import os

app = Flask(__name__)
app.secret_key = 'your_secret_key' # 用于Flash消息

# 备忘录数据文件路径
DATA_FILE = 'memos.json'

# 确保数据文件存在
if not os.path.exists(DATA_FILE):
with open(DATA_FILE, 'w') as f:
json.dump([], f)

# 读取备忘录数据
def read_memos():
with open(DATA_FILE, 'r') as f:
return json.load(f)

# 写入备忘录数据
def write_memos(memos):
with open(DATA_FILE, 'w') as f:
json.dump(memos, f, indent=4, default=str)

# 生成唯一ID
def generate_id():
memos = read_memos()
if not memos:
return 1
return max(memo['id'] for memo in memos) + 1

@app.route('/')
def index():
memos = read_memos()
# 按优先级排序,P0 > P1 > P2
priority_order = {'P0': 0, 'P1': 1, 'P2': 2}
memos.sort(key=lambda x: (priority_order[x['priority']], x['created_at']), reverse=False)

# 分组:未完成和已完成
unfinished_memos = [memo for memo in memos if not memo['completed']]
finished_memos = [memo for memo in memos if memo['completed']]

return render_template('index.html', unfinished_memos=unfinished_memos, finished_memos=finished_memos)

@app.route('/add', methods=['GET', 'POST'])
def add_memo():
if request.method == 'POST':
title = request.form['title']
details = request.form['details']
due_date = request.form['due_date']
priority = request.form['priority']

if not title or not due_date:
flash('标题和预计完成时间不能为空', 'error')
return redirect(url_for('add_memo'))

# 创建新备忘录
new_memo = {
'id': generate_id(),
'title': title,
'details': details,
'created_at': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
'due_date': due_date,
'priority': priority,
'completed': False
}

# 保存到文件
memos = read_memos()
memos.append(new_memo)
write_memos(memos)

flash('备忘录添加成功', 'success')
return redirect(url_for('index'))

return render_template('add.html')

@app.route('/detail/<int:memo_id>')
def detail(memo_id):
memos = read_memos()
memo = next((m for m in memos if m['id'] == memo_id), None)
if not memo:
flash('备忘录不存在', 'error')
return redirect(url_for('index'))
return render_template('detail.html', memo=memo)

@app.route('/edit/<int:memo_id>', methods=['GET', 'POST'])
def edit(memo_id):
memos = read_memos()
memo = next((m for m in memos if m['id'] == memo_id), None)
if not memo:
flash('备忘录不存在', 'error')
return redirect(url_for('index'))

if request.method == 'POST':
title = request.form['title']
details = request.form['details']
due_date = request.form['due_date']
priority = request.form['priority']

if not title or not due_date:
flash('标题和预计完成时间不能为空', 'error')
return redirect(url_for('edit', memo_id=memo_id))

# 更新备忘录
memo['title'] = title
memo['details'] = details
memo['due_date'] = due_date
memo['priority'] = priority

write_memos(memos)
flash('备忘录更新成功', 'success')
return redirect(url_for('detail', memo_id=memo_id))

return render_template('edit.html', memo=memo)

@app.route('/delete/<int:memo_id>')
def delete(memo_id):
memos = read_memos()
memos = [m for m in memos if m['id'] != memo_id]
write_memos(memos)
flash('备忘录删除成功', 'success')
return redirect(url_for('index'))

@app.route('/toggle_completed/<int:memo_id>')
def toggle_completed(memo_id):
memos = read_memos()
memo = next((m for m in memos if m['id'] == memo_id), None)
if memo:
memo['completed'] = not memo['completed']
write_memos(memos)
flash('备忘录状态更新成功', 'success')
return redirect(url_for('index'))

if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0', port=5000)
29 changes: 29 additions & 0 deletions memos.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
[
{
"id": 1,
"title": "1\u7b2c\u4e00\u4e2a\u8138ewke\u4eba\u812bewkekwwkkwkwkewkw\u6076\u5ba2wkwekwkewkewkekwkewekw\u6709\u5eb7\u6c83\u5c14\u6c83\u514b\u5c14\u6c83\u514b\u5c14\u4fdd\u80d1\u80d1\u80d7",
"details": "\u95ee\u95ee\u6709wkew\u5eb7\u6c83\u5c14",
"created_at": "2025-11-29 10:20:37",
"due_date": "2025-11-29T10:20",
"priority": "P1",
"completed": false
},
{
"id": 2,
"title": "122123333",
"details": "\u5947\u5947\u5728\u5947\u5947",
"created_at": "2025-11-29 10:20:58",
"due_date": "2025-11-08T10:20",
"priority": "P1",
"completed": false
},
{
"id": 4,
"title": "P0",
"details": "11111",
"created_at": "2025-11-29 10:22:36",
"due_date": "2025-10-31T10:22",
"priority": "P0",
"completed": true
}
]
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Flask==2.3.2
29 changes: 29 additions & 0 deletions templates/add.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{% extends 'base.html' %}

{% block content %}
<h2>添加备忘录</h2>
<form method="POST" class="mt-4">
<div class="mb-3">
<label for="title" class="form-label">标题</label>
<input type="text" class="form-control" id="title" name="title" required>
</div>
<div class="mb-3">
<label for="details" class="form-label">详情</label>
<textarea class="form-control" id="details" name="details" rows="3"></textarea>
</div>
<div class="mb-3">
<label for="due_date" class="form-label">预计完成时间</label>
<input type="datetime-local" class="form-control" id="due_date" name="due_date" required>
</div>
<div class="mb-3">
<label for="priority" class="form-label">优先级</label>
<select class="form-select" id="priority" name="priority" required>
<option value="P0">P0 (最高)</option>
<option value="P1">P1 (中等)</option>
<option value="P2">P2 (最低)</option>
</select>
</div>
<button type="submit" class="btn btn-primary">添加</button>
<a href="{{ url_for('index') }}" class="btn btn-secondary">取消</a>
</form>
{% endblock %}
38 changes: 38 additions & 0 deletions templates/base.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>备忘录</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
.priority-p0 { color: #dc3545; font-weight: bold; }
.priority-p1 { color: #ffc107; font-weight: bold; }
.priority-p2 { color: #28a745; font-weight: bold; }
.memo-item { margin-bottom: 1rem; padding: 1rem; border: 1px solid #e9ecef; border-radius: 0.5rem; }
.memo-item:hover { box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075); }
.completed { text-decoration: line-through; opacity: 0.7; }
</style>
</head>
<body>
<div class="container mt-4">
<h1 class="mb-4">备忘录</h1>

<!-- Flash消息 -->
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
{% for category, message in messages %}
<div class="alert alert-{{ 'danger' if category == 'error' else 'success' }} alert-dismissible fade show" role="alert">
{{ message }}
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
{% endfor %}
{% endif %}
{% endwith %}

{% block content %}{% endblock %}
</div>

<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
26 changes: 26 additions & 0 deletions templates/detail.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{% extends 'base.html' %}

{% block content %}
<h2>备忘录详情</h2>
<div class="card mt-4">
<div class="card-body">
<h5 class="card-title">{{ memo.title }}</h5>
<h6 class="card-subtitle mb-2 text-muted">
优先级: <span class="priority-{{ memo.priority.lower() }}">{{ memo.priority }}</span>
</h6>
<p class="card-text">
<strong>创建时间:</strong> {{ memo.created_at }}<br>
<strong>预计完成时间:</strong> {{ memo.due_date }}
</p>
<p class="card-text">{{ memo.details or '无详情' }}</p>
<div class="mt-4">
<a href="{{ url_for('edit', memo_id=memo.id) }}" class="btn btn-primary">编辑</a>
<a href="{{ url_for('toggle_completed', memo_id=memo.id) }}" class="btn btn-{{ 'warning' if memo.completed else 'success' }}">
{{ '标记未完成' if memo.completed else '标记完成' }}
</a>
<a href="{{ url_for('delete', memo_id=memo.id) }}" class="btn btn-danger" onclick="return confirm('确定要删除吗?')">删除</a>
<a href="{{ url_for('index') }}" class="btn btn-secondary">返回列表</a>
</div>
</div>
</div>
{% endblock %}
31 changes: 31 additions & 0 deletions templates/edit.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{% extends 'base.html' %}

{% block content %}
<h2>编辑备忘录</h2>
<form method="POST" class="mt-4">
<div class="mb-3">
<label for="title" class="form-label">标题</label>
<input type="text" class="form-control" id="title" name="title" value="{{ memo.title }}" required>
</div>
<div class="mb-3">
<label for="details" class="form-label">详情</label>
<textarea class="form-control" id="details" name="details" rows="3">{{ memo.details or '' }}</textarea>
</div>
<div class="mb-3">
<label for="due_date" class="form-label">预计完成时间</label>
<!-- 将日期时间格式转换为datetime-local所需的格式 (YYYY-MM-DDTHH:MM) -->
<input type="datetime-local" class="form-control" id="due_date" name="due_date"
value="{{ memo.due_date.replace(' ', 'T').split('.')[0] }}" required>
</div>
<div class="mb-3">
<label for="priority" class="form-label">优先级</label>
<select class="form-select" id="priority" name="priority" required>
<option value="P0" {% if memo.priority == 'P0' %}selected{% endif %}>P0 (最高)</option>
<option value="P1" {% if memo.priority == 'P1' %}selected{% endif %}>P1 (中等)</option>
<option value="P2" {% if memo.priority == 'P2' %}selected{% endif %}>P2 (最低)</option>
</select>
</div>
<button type="submit" class="btn btn-primary">保存</button>
<a href="{{ url_for('detail', memo_id=memo.id) }}" class="btn btn-secondary">取消</a>
</form>
{% endblock %}
Loading