示例成品 写技术方案 示例成品 看全文 ↓

写技术方案

说说要解决什么需求、用什么语言和技术栈,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 同理。

七、改进建议

  1. 存储升级为 SQLite

JSON 文件适合演示和少量数据。任务量上去后换成 Python 内置的 sqlite3 模块(也是标准库,不需要额外安装),支持并发读写、条件查询,数据也更安全。改动集中在 load_tasks / save_tasks 两个函数,API 层不用动。

  1. 增加用户认证

当前所有浏览器共享同一份任务列表。加登录功能后,每个任务关联 user_id,数据互相隔离。可以用 http.server 里读 Cookie + hashlib 做简单的会话管理,密码用 bcrypt 或 hashlib.pbkdf2_hmac 存储,不要明文。

同类还能办

全部 ›
首页