看全文 ↓
写技术方案
说说要解决什么需求、用什么语言和技术栈,AI帮你把运行环境、技术选型这些细节都考虑到,写出一份经得起评审的技术方案。
有人这样说「写技术方案」
能替你选的都选好了。不想动,直接点下面「直接生成技术方案」,点一下就开始做;想改,就点一下要的那个。
已替你选好想改就点一下
更多选项(一般不用动)
只有你知道的不填就先空着,成品里留【待填】
还想怎么改可以不选
高级选项一般不用动 · 这件事通常 1 分钟左右做好
示例成品全文按上面这组示例选项真跑出来的

任务管理系统技术方案
技术栈:Python 标准库 + 原生 HTML/CSS/JavaScript
运行环境:浏览器(Chrome / Firefox / Edge)
日期:2026年10月6日
一、需求说明
实现一个任务管理系统,在浏览器中完成以下操作:
- • 添加新任务
- • 查看任务列表
- • 标记任务完成 / 取消完成
- • 删除任务
数据通过 Python 后端读写,前端不依赖任何框架。
二、技术架构
后端:Python 标准库 http.server + json(零依赖,无需 pip install)
前端:原生 HTML + CSS + JavaScript,通过 fetch 调用后端 API
数据存储:JSON 文件(tasks.json)
通信方式:RESTful API,JSON 格式
三、项目结构
task_manager/
├── server.py # 后端主程序(纯标准库)
├── tasks.json # 数据文件(自动创建)
└── static/
├── index.html # 页面
├── style.css # 样式
└── app.js # 前端逻辑
四、完整代码
4.1 后端(server.py)
import http.server
import json
import os
import urllib.parse
DATA_FILE = 'tasks.json'
PORT = 8080
# ---------- 数据读写 ----------
def load_tasks():
"""从 JSON 文件读取任务列表"""
if not os.path.exists(DATA_FILE):
return []
with open(DATA_FILE, 'r', encoding='utf-8') as f:
return json.load(f)
def save_tasks(tasks):
"""写入 JSON 文件"""
with open(DATA_FILE, 'w', encoding='utf-8') as f:
json.dump(tasks, f, ensure_ascii=False, indent=2)
# ---------- 请求处理 ----------
class Handler(http.server.BaseHTTPRequestHandler):
def _send_json(self, data, status=200):
"""统一返回 JSON 响应"""
body = json.dumps(data, ensure_ascii=False).encode('utf-8')
self.send_response(status)
self.send_header('Content-Type', 'application/json; charset=utf-8')
self.send_header('Content-Length', str(len(body)))
self.end_headers()
self.wfile.write(body)
def _read_body(self):
"""读取请求体"""
length = int(self.headers.get('Content-Length', 0))
raw = self.rfile.read(length)
return json.loads(raw) if raw else {}
def _serve_static(self, path):
"""提供静态文件"""
file_path = os.path.join('static', path)
if not os.path.exists(file_path):
self.send_error(404)
return
ext = path.rsplit('.', 1)[-1]
mime = {'html': 'text/html', 'css': 'text/css',
'js': 'application/javascript'}.get(ext, 'text/plain')
with open(file_path, 'rb') as f:
content = f.read()
self.send_response(200)
self.send_header('Content-Type', f'{mime}; charset=utf-8')
self.send_header('Content-Length', str(len(content)))
self.end_headers()
self.wfile.write(content)
# --- 路由 ---
def do_GET(self):
if self.path == '/' or self.path == '/index.html':
self._serve_static('index.html')
elif self.path.startswith('/static/'):
self._serve_static(self.path[8:])
elif self.path == '/api/tasks':
self._send_json(load_tasks())
else:
self.send_error(404)
def do_POST(self):
if self.path == '/api/tasks':
data = self._read_body()
title = data.get('title', '').strip()
if not title:
self._send_json({'error': '标题不能为空'}, 400)
return
tasks = load_tasks()
new_id = max([t['id'] for t in tasks], default=0) + 1
task = {'id': new_id, 'title': title, 'completed': False}
tasks.append(task)
save_tasks(tasks)
self._send_json(task, 201)
else:
self.send_error(404)
def do_PUT(self):
# 路径形如 /api/tasks/3
if self.path.startswith('/api/tasks/'):
task_id = int(self.path.split('/')[-1])
data = self._read_body()
tasks = load_tasks()
for t in tasks:
if t['id'] == task_id:
t['completed'] = data.get('completed', t['completed'])
save_tasks(tasks)
self._send_json(t)
return
self._send_json({'error': '任务不存在'}, 404)
else:
self.send_error(404)
def do_DELETE(self):
if self.path.startswith('/api/tasks/'):
task_id = int(self.path.split('/')[-1])
tasks = [t for t in load_tasks() if t['id'] != task_id]
save_tasks(tasks)
self._send_json({'message': '已删除'})
else:
self.send_error(404)
# 关闭默认日志,保持输出干净
def log_message(self, format, *args):
pass
if __name__ == '__main__':
os.makedirs('static', exist_ok=True)
server = http.server.HTTPServer(('', PORT), Handler)
print(f'服务已启动:http://localhost:{PORT}')
server.serve_forever()4.2 前端页面(static/index.html)
<!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 rel="stylesheet" href="/static/style.css">
</head>
<body>
<div class="container">
<h1>任务管理</h1>
<div class="input-section">
<input type="text" id="taskInput" placeholder="输入任务标题">
<button onclick="addTask()">添加</button>
</div>
<ul id="taskList"></ul>
</div>
<script src="/static/app.js"></script>
</body>
</html>4.3 样式(static/style.css)
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: -apple-system, "Segoe UI", sans-serif;
background: #f5f5f5;
padding: 20px;
}
.container {
max-width: 600px;
margin: 0 auto;
background: white;
padding: 30px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
h1 { color: #333; margin-bottom: 20px; }
.input-section {
display: flex;
gap: 10px;
margin-bottom: 20px;
}
input {
flex: 1;
padding: 10px;
border: 1px solid #ddd;
border-radius: 4px;
}
button {
padding: 10px 20px;
background: #007bff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
button:hover { background: #0056b3; }
ul { list-style: none; }
li {
display: flex;
align-items: center;
padding: 12px;
border-bottom: 1px solid #eee;
gap: 10px;
}
li.done span { text-decoration: line-through; opacity: 0.5; }
li span { flex: 1; cursor: pointer; }
.del-btn {
padding: 4px 10px;
background: #dc3545;
font-size: 12px;
}
.del-btn:hover { background: #c82333; }4.4 前端逻辑(static/app.js)
// 加载并渲染任务列表
async function loadTasks() {
const res = await fetch('/api/tasks');
const tasks = await res.json();
const list = document.getElementById('taskList');
list.innerHTML = '';
tasks.forEach(task => {
const li = document.createElement('li');
if (task.completed) li.classList.add('done');
const cb = document.createElement('input');
cb.type = 'checkbox';
cb.checked = task.completed;
cb.onchange = () => toggleTask(task.id, cb.checked);
const span = document.createElement('span');
span.textContent = task.title;
span.onclick = () => {
cb.checked = !cb.checked;
toggleTask(task.id, cb.checked);
};
const del = document.createElement('button');
del.textContent = '删除';
del.className = 'del-btn';
del.onclick = () => deleteTask(task.id);
li.append(cb, span, del);
list.appendChild(li);
});
}
// 添加任务
async function addTask() {
const input = document.getElementById('taskInput');
const title = input.value.trim();
if (!title) return alert('请输入任务标题');
await fetch('/api/tasks', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({title})
});
input.value = '';
loadTasks();
}
// 切换完成状态
async function toggleTask(id, completed) {
await fetch(`/api/tasks/${id}`, {
method: 'PUT',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({completed})
});
loadTasks();
}
// 删除任务
async function deleteTask(id) {
if (!confirm('确定删除?')) return;
await fetch(`/api/tasks/${id}`, {method: 'DELETE'});
loadTasks();
}
// 回车也能添加
document.addEventListener('DOMContentLoaded', () => {
document.getElementById('taskInput')
.addEventListener('keydown', e => {
if (e.key === 'Enter') addTask();
});
loadTasks();
});五、使用说明
5.1 目录准备
创建 task_manager 文件夹,把 server.py 放进去,再建 static 子目录,放入 index.html、style.css、app.js 三个文件。
5.2 启动服务
cd task_manager
python3 server.py
终端输出「服务已启动:http://localhost:8080」后,打开浏览器访问这个地址即可。
5.3 依赖
零依赖。只用 Python 标准库,不需要 pip install 任何东西。Python 3.6 以上即可。
5.4 操作方式
- 输入框填写标题,点"添加"或按回车创建任务
- 点复选框或任务文字切换完成状态
- 点"删除"移除任务(会弹出确认)
六、常见坑
- 1. 端口被占用
8080 端口如果已经被其他程序占用,启动会报错。改 server.py 里的 PORT 变量换个端口(比如 8081),或者用 lsof -ti:8080 | xargs kill 释放端口。
- 2. JSON 文件并发写入
多个请求同时写 tasks.json 时可能丢数据。http.server 是单线程的,正常操作不会出问题;但如果未来换成多线程或使用人数增多,需要加文件锁或改用 SQLite。
- 3. 静态文件路径
前端引用 CSS 和 JS 用的是 /static/xxx 绝对路径。如果 server.py 不在项目根目录运行,静态文件会 404。确保从 task_manager 目录执行 python3 server.py。
- 4. 中文编码
读写 JSON 文件时 encoding="utf-8" 不能省,否则 Windows 下默认 GBK 编码会乱码。响应头里的 charset=utf-8 同理。
七、改进建议
- 存储升级为 SQLite
JSON 文件适合演示和少量数据。任务量上去后换成 Python 内置的 sqlite3 模块(也是标准库,不需要额外安装),支持并发读写、条件查询,数据也更安全。改动集中在 load_tasks / save_tasks 两个函数,API 层不用动。
- 增加用户认证
当前所有浏览器共享同一份任务列表。加登录功能后,每个任务关联 user_id,数据互相隔离。可以用 http.server 里读 Cookie + hashlib 做简单的会话管理,密码用 bcrypt 或 hashlib.pbkdf2_hmac 存储,不要明文。