本文目录导读:

我来帮您解答如何在PHP中创建看板(Kanban Board)。
PHP看板创建方式
纯PHP后端 + 前端HTML/CSS/JavaScript
<?php
// task_board.php
class KanbanBoard {
private $tasks = [
'todo' => [],
'in_progress' => [],
'done' => []
];
public function addTask($column, $task) {
if (isset($this->tasks[$column])) {
$this->tasks[$column][] = $task;
}
}
public function moveTask($from, $to, $taskIndex) {
if (isset($this->tasks[$from][$taskIndex])) {
$task = $this->tasks[$from][$taskIndex];
unset($this->tasks[$from][$taskIndex]);
$this->tasks[$to][] = $task;
}
}
public function getBoard() {
return $this->tasks;
}
}
$board = new KanbanBoard();
$board->addTask('todo', '开发登录功能');
$board->addTask('todo', '设计数据库');
$board->addTask('in_progress', '编写API文档');
?>
使用PHP框架+Laravel
// 使用Laravel框架
// web.php 路由
Route::get('/kanban', [KanbanController::class, 'index']);
Route::post('/kanban/task', [KanbanController::class, 'store']);
Route::put('/kanban/task/{id}/move', [KanbanController::class, 'move']);
// KanbanController.php
class KanbanController extends Controller {
public function index() {
$tasks = Task::all()->groupBy('status');
return view('kanban.index', compact('tasks'));
}
public function store(Request $request) {
$task = Task::create([
'title' => $request->title,
'status' => 'todo',
'order' => Task::where('status', 'todo')->count() + 1
]);
return response()->json($task);
}
}
完整的前后端示例
<!-- kanban.html -->
<!DOCTYPE html>
<html>
<head>PHP Kanban Board</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css">
<style>
.kanban-column {
min-height: 400px;
background: #f4f5f7;
border-radius: 3px;
padding: 10px;
}
.task-card {
background: white;
padding: 10px;
margin: 5px 0;
border-radius: 3px;
cursor: pointer;
box-shadow: 0 1px 0 rgba(9,30,66,.25);
}
</style>
</head>
<body>
<div class="container mt-5">
<h2>PHP Kanban Board</h2>
<div class="row">
<div class="col-md-4">
<div class="kanban-column" data-column="todo">
<h5>待办 (Todo)</h5>
<div id="todo-tasks">
<?php foreach($board['todo'] as $task): ?>
<div class="task-card" draggable="true">
<?php echo $task; ?>
</div>
<?php endforeach; ?>
</div>
</div>
</div>
<div class="col-md-4">
<div class="kanban-column" data-column="in_progress">
<h5>进行中 (In Progress)</h5>
<div id="in_progress-tasks">
<?php foreach($board['in_progress'] as $task): ?>
<div class="task-card" draggable="true">
<?php echo $task; ?>
</div>
<?php endforeach; ?>
</div>
</div>
</div>
<div class="col-md-4">
<div class="kanban-column" data-column="done">
<h5>已完成 (Done)</h5>
<div id="done-tasks">
<?php foreach($board['done'] as $task): ?>
<div class="task-card" draggable="true">
<?php echo $task; ?>
</div>
<?php endforeach; ?>
</div>
</div>
</div>
</div>
<div class="mt-3">
<input type="text" id="new-task" placeholder="输入新任务" class="form-control w-25 d-inline">
<button onclick="addTask()" class="btn btn-primary">添加任务</button>
</div>
</div>
<script>
// 拖拽功能
document.addEventListener('dragstart', function(e) {
if (e.target.classList.contains('task-card')) {
e.dataTransfer.setData('text/plain', e.target.textContent);
e.dataTransfer.setData('source-column', e.target.parentElement.id);
}
});
document.querySelectorAll('.kanban-column').forEach(column => {
column.addEventListener('dragover', function(e) {
e.preventDefault();
});
column.addEventListener('drop', function(e) {
e.preventDefault();
const taskText = e.dataTransfer.getData('text/plain');
const sourceColumn = e.dataTransfer.getData('source-column');
const targetColumn = this.dataset.column;
// PHP Ajax请求更新任务状态
updateTaskStatus(taskText, sourceColumn, targetColumn);
const taskElement = document.createElement('div');
taskElement.className = 'task-card';
taskElement.draggable = true;
taskElement.textContent = taskText;
this.querySelector('div').appendChild(taskElement);
});
});
function addTask() {
const task = document.getElementById('new-task').value;
if (task.trim() !== '') {
// 发送Ajax请求到PHP后端保存任务
fetch('save_task.php', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: 'task=' + encodeURIComponent(task) + '&column=todo'
})
.then(response => response.text())
.then(data => {
const taskElement = document.createElement('div');
taskElement.className = 'task-card';
taskElement.draggable = true;
taskElement.textContent = task;
document.getElementById('todo-tasks').appendChild(taskElement);
document.getElementById('new-task').value = '';
});
}
}
function updateTaskStatus(task, from, to) {
fetch('update_task.php', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: 'task=' + encodeURIComponent(task) +
'&from=' + from +
'&to=' + to
});
}
</script>
</body>
</html>
PHP后端API示例
<?php
// save_task.php
header('Content-Type: application/json');
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$task = $_POST['task'] ?? '';
$column = $_POST['column'] ?? 'todo';
// 存储到数据库
$db = new PDO('mysql:host=localhost;dbname=kanban', 'root', '');
$stmt = $db->prepare("INSERT INTO tasks (title, status) VALUES (?, ?)");
$stmt->execute([$task, $column]);
echo json_encode(['success' => true, 'id' => $db->lastInsertId()]);
}
?>
数据库表结构
CREATE TABLE tasks (
id INT AUTO_INCREMENT PRIMARY KEY,VARCHAR(255) NOT NULL,
status ENUM('todo', 'in_progress', 'done') DEFAULT 'todo',
priority INT DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
推荐工具和库
- Packagist包:
jorelanbo/kanban- PHP看板库 - 前端库: SortableJS + PHP后端
- 全栈方案: Laravel + Vue.js + Dragula
简单实现例子
// 最简单的看板存储方式
$tasks = [
'todo' => ['任务1', '任务2'],
'in_progress' => ['任务3'],
'done' => ['任务4']
];
// 保存到文件
file_put_contents('tasks.json', json_encode($tasks));
// 读取
$tasks = json_decode(file_get_contents('tasks.json'), true);
需要具体的哪一种实现方式,我可以提供更详细的代码示例。