【前端】简易化看板

发布于:2024-07-02 ⋅ 阅读:(19) ⋅ 点赞:(0)

【前端】简易化看板

在这里插入图片描述
在这里插入图片描述

项目简介

看板分为三个模块,分别是待办,正在做,已做完三个部分。每个事件采取"卡片"式设计,支持任务间拖拽,删除等操作。

代码

import React, { useState } from 'react';
import { Card, CardContent } from '@/components/ui/card';
import { Input } from '@/components/ui/input';
import { Button } from '@/components/ui/button';

const KanbanBoard = () => {
  const [tasks, setTasks] = useState({
    todo: [
      { id: '1', title: '设计新的登录页面' },
      { id: '2', title: '优化数据库查询' }
    ],
    doing: [
      { id: '3', title: '实现用户认证功能' },
      { id: '4', title: '编写单元测试' }
    ],
    done: [
      { id: '5', title: '更新API文档' },
      { id: '6', title: '修复登录bug' }
    ]
  });

  const [newTasks, setNewTasks] = useState({
    todo: '',
    doing: '',
    done: ''
  });

  const onDragStart = (e, id, sourceColumn) => {
    e.dataTransfer.setData('text/plain', JSON.stringify({ id, sourceColumn }));
  };

  const onDragOver = (e) => {
    e.preventDefault();
  };

  const onDrop = (e, targetColumn) => {
    e.preventDefault();
    const { id, sourceColumn } = JSON.parse(e.dataTransfer.getData('text'));
    if (sourceColumn === targetColumn) return;

    const updatedTasks = { ...tasks };
    const taskToMove = updatedTasks[sourceColumn].find(task => task.id === id);
    updatedTasks[sourceColumn] = updatedTasks[sourceColumn].filter(task => task.id !== id);
    updatedTasks[targetColumn].push(taskToMove);
    setTasks(updatedTasks);
  };

  const addTask = (column) => {
    if (newTasks[column].trim()) {
      const updatedTasks = { ...tasks };
      updatedTasks[column] = [...tasks[column], { 
        id: Date.now().toString(), 
        title: newTasks[column]
      }];
      setTasks(updatedTasks);
      setNewTasks({...newTasks, [column]: ''});
    }
  };

  const deleteTask = (columnId, taskId) => {
    const updatedTasks = { ...tasks };
    updatedTasks[columnId] = tasks[columnId].filter(task => task.id !== taskId);
    setTasks(updatedTasks);
  };

  const renderTask = (task, columnId) => (
    <Card 
      key={task.id}
      draggable
      onDragStart={(e) => onDragStart(e, task.id, columnId)}
      className="mb-2 shadow-sm hover:shadow-md transition-shadow duration-200"
    >
      <CardContent className="p-3 flex justify-between items-center">
        <p className="text-sm font-medium text-gray-700 truncate flex-grow mr-2">{task.title}</p>
        <Button 
          onClick={() => deleteTask(columnId, task.id)}
          className="text-gray-400 hover:text-red-500 transition-colors duration-200 flex-shrink-0"
          variant="ghost"
          size="sm"
        >
          ×
        </Button>
      </CardContent>
    </Card>
  );

  const renderColumn = (title, columnId) => (
    <div 
      className="flex-1 min-w-[250px] bg-gray-50 rounded-lg p-4 border border-gray-200"
      onDragOver={onDragOver}
      onDrop={(e) => onDrop(e, columnId)}
    >
      <h2 className="text-lg font-semibold mb-4 text-gray-700">{title}</h2>
      <div className="space-y-2">
        {tasks[columnId].map(task => renderTask(task, columnId))}
      </div>
      <div className="mt-4">
        <Input
          type="text"
          value={newTasks[columnId]}
          onChange={(e) => setNewTasks({...newTasks, [columnId]: e.target.value})}
          placeholder={`添加任务到 ${title}`}
          className="mb-2"
        />
        <Button onClick={() => addTask(columnId)} className="w-full bg-blue-500 hover:bg-blue-600 text-white">
          添加任务
        </Button>
      </div>
    </div>
  );

  return (
    <div className="container mx-auto p-6 bg-white">
      <header className="text-center mb-8">
        <h1 className="text-3xl font-bold text-gray-800">SeeBoard</h1>
      </header>
      <div className="flex flex-wrap gap-6">
        {renderColumn('待办', 'todo')}
        {renderColumn('进行中', 'doing')}
        {renderColumn('已完成', 'done')}
      </div>
    </div>
  );
};

export default KanbanBoard;

效果图

在这里插入图片描述
在这里插入图片描述