您好,登录后才能下订单哦!
在现代Web开发中,甘特图是项目管理的重要工具之一。dhtmlxGantt是一个功能强大的JavaScript库,用于创建交互式甘特图。结合ASP.NET Core的Web API,可以构建一个强大的项目管理工具。本文将详细介绍如何使用ASP.NET Core和dhtmlxGantt实施Web API。
dhtmlxGantt是一个用于创建甘特图的JavaScript库,支持任务管理、资源分配、时间线视图等功能。它提供了丰富的API和插件,可以轻松集成到现有的Web应用中。
ASP.NET Core是一个跨平台的高性能Web框架,用于构建现代Web应用和API。它支持依赖注入、中间件、路由等特性,是构建Web API的理想选择。
首先,使用Visual Studio或命令行工具创建一个新的ASP.NET Core Web API项目。
dotnet new webapi -n GanttApi
cd GanttApi
在项目中安装dhtmlxGantt库。可以通过npm或直接下载库文件。
npm install dhtmlx-gantt
将dhtmlxGantt的CSS和JavaScript文件添加到wwwroot
目录中。
定义一个任务模型,用于表示甘特图中的任务。
public class Task
{
public int Id { get; set; }
public string Text { get; set; }
public DateTime StartDate { get; set; }
public int Duration { get; set; }
public decimal Progress { get; set; }
public int? ParentId { get; set; }
}
定义一个链接模型,用于表示任务之间的依赖关系。
public class Link
{
public int Id { get; set; }
public int SourceTaskId { get; set; }
public int TargetTaskId { get; set; }
public string Type { get; set; }
}
使用Entity Framework Core作为ORM工具,配置数据库上下文。
public class GanttContext : DbContext
{
public GanttContext(DbContextOptions<GanttContext> options) : base(options) { }
public DbSet<Task> Tasks { get; set; }
public DbSet<Link> Links { get; set; }
}
在Startup.cs
中配置数据库连接。
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<GanttContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddControllers();
}
创建并应用数据库迁移。
dotnet ef migrations add InitialCreate
dotnet ef database update
创建一个任务控制器,用于处理任务的CRUD操作。
[ApiController]
[Route("api/[controller]")]
public class TasksController : ControllerBase
{
private readonly GanttContext _context;
public TasksController(GanttContext context)
{
_context = context;
}
[HttpGet]
public async Task<ActionResult<IEnumerable<Task>>> GetTasks()
{
return await _context.Tasks.ToListAsync();
}
[HttpGet("{id}")]
public async Task<ActionResult<Task>> GetTask(int id)
{
var task = await _context.Tasks.FindAsync(id);
if (task == null)
{
return NotFound();
}
return task;
}
[HttpPost]
public async Task<ActionResult<Task>> PostTask(Task task)
{
_context.Tasks.Add(task);
await _context.SaveChangesAsync();
return CreatedAtAction("GetTask", new { id = task.Id }, task);
}
[HttpPut("{id}")]
public async Task<IActionResult> PutTask(int id, Task task)
{
if (id != task.Id)
{
return BadRequest();
}
_context.Entry(task).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!TaskExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return NoContent();
}
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteTask(int id)
{
var task = await _context.Tasks.FindAsync(id);
if (task == null)
{
return NotFound();
}
_context.Tasks.Remove(task);
await _context.SaveChangesAsync();
return NoContent();
}
private bool TaskExists(int id)
{
return _context.Tasks.Any(e => e.Id == id);
}
}
创建一个链接控制器,用于处理链接的CRUD操作。
[ApiController]
[Route("api/[controller]")]
public class LinksController : ControllerBase
{
private readonly GanttContext _context;
public LinksController(GanttContext context)
{
_context = context;
}
[HttpGet]
public async Task<ActionResult<IEnumerable<Link>>> GetLinks()
{
return await _context.Links.ToListAsync();
}
[HttpGet("{id}")]
public async Task<ActionResult<Link>> GetLink(int id)
{
var link = await _context.Links.FindAsync(id);
if (link == null)
{
return NotFound();
}
return link;
}
[HttpPost]
public async Task<ActionResult<Link>> PostLink(Link link)
{
_context.Links.Add(link);
await _context.SaveChangesAsync();
return CreatedAtAction("GetLink", new { id = link.Id }, link);
}
[HttpPut("{id}")]
public async Task<IActionResult> PutLink(int id, Link link)
{
if (id != link.Id)
{
return BadRequest();
}
_context.Entry(link).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!LinkExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return NoContent();
}
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteLink(int id)
{
var link = await _context.Links.FindAsync(id);
if (link == null)
{
return NotFound();
}
_context.Links.Remove(link);
await _context.SaveChangesAsync();
return NoContent();
}
private bool LinkExists(int id)
{
return _context.Links.Any(e => e.Id == id);
}
}
在wwwroot
目录中创建一个HTML文件,用于显示甘特图。
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="~/dhtmlxgantt.css">
</head>
<body>
<div id="gantt_here" style='width:100%; height:100vh;'></div>
<script src="~/dhtmlxgantt.js"></script>
<script src="~/app.js"></script>
</body>
</html>
在app.js
中初始化dhtmlxGantt,并配置数据加载与保存。
”`javascript gantt.init(“gantt_here”);
gantt.config.date_format = “%Y-%m-%d %H:%i”;
gantt.config.xml_date = “%Y-%m-%d %H:%i”;
gantt.config.autofit = true;
gantt.config.readonly = false;
gantt.config.order_branch = true;
gantt.config.order_branch_free = true;
gantt.config.fit_tasks = true;
gantt.config.scale_unit = “day”;
gantt.config.step = 1;
gantt.config.date_scale = “%d %M”;
gantt.config.subscales = [ { unit: “month”, step: 1, date: “%F, %Y” } ];
gantt.config.columns = [ { name: “text”, label: “Task name”, width: “*”, tree: true }, { name: “start_date”, label: “Start time”, align: “center”, width: 100 }, { name: “duration”, label: “Duration”, align: “center”, width: 70 }, { name: “add”, label: “”, width: 44 } ];
gantt.config.lightbox.sections = [ { name: “description”, height: 70, map_to: “text”, type: “textarea”, focus: true }, { name: “time”, height: 72, type: “duration”, map_to: “auto” } ];
gantt.templates.task_class = function (start, end, task) { if (task.progress < 1) { return “late”; } return “”; };
gantt.templates.task_text = function (start, end, task) { return task.text + “ (” + task.progress * 100 + “%)”; };
gantt.templates.task_row_class = function (start, end, task) { if (task.progress < 1) { return “late”; } return “”; };
gantt.templates.grid_row_class = function (start, end, task) { if (task.progress < 1) { return “late”; } return “”; };
gantt.templates.grid_folder = function (item) { return “
” + item.text; };gantt.templates.grid_file = function (item) { return “
” + item.text; };gantt.templates.grid_indent = function (item) { return “
”; };gantt.templates.grid_blank = function (item) { return “
”; };gantt.templates.grid_open = function (item) { return “
”; };gantt.templates.grid_close = function (item) { return “
”; };gantt.templates.grid_empty = function (item) { return “
”; };gantt.templates.grid_cell_class = function (item, date) { if (date.getDay() == 0 || date.getDay() == 6) { return “weekend”; } return “”; };
gantt.templates.grid_row_class = function (start, end, task) { if (task.progress < 1) { return “late”; } return “”; };
gantt.templates.grid_folder = function (item) { return “
” + item.text; };gantt.templates.grid_file = function (item) { return “
” + item.text; };gantt.templates.grid_indent = function (item) { return “
”; };gantt.templates.grid_blank = function (item) { return “
”; };gantt.templates.grid_open = function (item) { return “
”; };gantt.templates.grid_close = function (item) { return “
”; };gantt.templates.grid_empty = function (item) { return “
”; };gantt.templates.grid_cell_class = function (item, date) { if (date.getDay() == 0 || date.getDay() == 6) { return “weekend”; } return “”; };
gantt.templates.grid_row_class = function (start, end, task) { if (task.progress < 1) { return “late”; } return “”; };
gantt.templates.grid_folder = function (item) { return “
” + item.text; };gantt.templates.grid_file = function (item) { return “
” + item.text; };gantt.templates.grid_indent = function (item) { return “
”; };gantt.templates.grid_blank = function (item) { return “
”; };gantt.templates.grid_open = function (item) { return “
”; };gantt.templates.grid_close = function (item) { return “
”; };gantt.templates.grid_empty = function (item) { return “
”; };gantt.templates.grid_cell_class = function (item, date) { if (date.getDay() == 0 || date.getDay() == 6) { return “weekend”; } return “”; };
gantt.templates.grid_row_class = function (start, end, task) { if (task.progress < 1) { return “late”; } return “”; };
gantt.templates.grid_folder = function (item) { return “
” + item.text; };gantt.templates.grid_file = function (item) { return “
” + item.text; };gantt.templates.grid_indent = function (item) { return “
”; };gantt.templates.grid_blank = function (item) { return “
”; };gantt.templates.grid_open = function (item) { return “
”; };gantt.templates.grid_close = function (item) { return “
”; };gantt.templates.grid_empty = function (item) { return “
”; };gantt.templates.grid_cell_class = function (item, date) { if (date.getDay() == 0 || date.getDay() == 6) { return “weekend”; } return “”; };
gantt.templates.grid_row_class = function (start, end, task) { if (task.progress < 1) { return “late”; } return “”; };
gantt.templates.grid_folder = function (item) { return “
” + item.text; };gantt.templates.grid_file = function (item) { return “
” + item.text; };gantt.templates.grid_indent = function (item) { return “
”; };gantt.templates.grid_blank = function (item) { return “
”; };gantt.templates.grid_open = function (item) { return “
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。