草庐IT

03 开源任务管理系统:创建一个任务

MakeMoreTime 2023-03-28 原文

GitHub 地址:https://github.com/dom-bro/task-manager

虽说是一个任务管理系统,但简单地讲,其实就是任务的增删改查(CRUD)

其中最重要的又当属,即创建任务,此为数据之源,删改查都依赖于它所产生的数据。

交互设计

凭着程序员的直觉,最初做成了一个表单如下图,表单项也对应了数据库中的表的字段,简单直接。

后来经过同事的建议,对比了 towerteambitionworktile 这些成熟产品的交互设计。

tower 看板如下图所示

teambition 看板如下图所示

worktile 看板如下图所示

发现看板形式确实是比较适合任务的展现的。于是最终改版为如下任务卡片看板

任务的创建和展现全部放在一块看板上。交互路径更短,更易用。

数据库表结构设计

作为一个地地道道的前端,数据库知识依然来源于大学时期的残存。为了最小化学习成本,自然而然选择了 MongoDB。使用 MongoDB
可以简单地理解为操作 json 对象,写数据库也只是把一堆 json 对象存到了数据库里。

MongoDB 为每个主流编程语言都提供了相应的 driver,直接给 node 提供了一个 npm 包。

npm i mongodb

接下来就开始设计数据库里的第一张表,任务表。任务表的数据结构完全由一个任务的组成因素去映射。

想一想实际工作中的任务是怎样的

  • 任务标题

    显然必不可少,除了这个字段必选,其他都是可选项

  • 任务排期

    至关重要,是之后汇总周报,季报的依据。想必在座的各位都被催过排期吧

  • 需求文档

    链接也好,文字描述也好,凡是需求相关的通通放进来,好记性不如烂笔头。什么!没有需求文档!全靠嘴说脑记!珍惜生命,趁早放手吧。然鹅这只是辅助记录而已,对频繁需求变更这个老大难问题着实是无能为力哈哈

  • 相关人员

    产品,UI,后端,测试,各个岗位的对接人得清楚。

  • 项目分支

    项目再多,分支再乱,也别搞错哦。分支搞不对,加班两行泪。

好了,为了简单起见,先暂定这几个字段吧。其他字段可根据需要再增加。

目前任务的数据结构大致如下

{
  title: String, // 任务标题
  schedule: [String, String], // 任务排期,[开始时间,结束时间]
  doc: { // 相关文档
    pm: String, // 需求文档
    ui: String, // 设计文档
    api: String, // 接口文档
  },
  workmate: { // 相关人员
    pm: Object, // 产品
    ui: Object, // UI
    api: Object, // 后端
    qa: Object, // 测试
  },
  repos: [ // 项目分支
    {
      name: String, // 项目名称
      branch: String, // 分支名称
    }
  ],
  status: String, // 任务状态 未开始|开发中|已提测|已完成
}

后端实现

这里只需要一个创建的接口即可

在开发接口的过程中可能需要频繁重启服务来测试接口,所以在开始开发接口之前,隆重引入一个新轮子 nodemon,服务端进程就由它来守护,实现文件变更时重启服务器。

可以在根目录给 nodemon 一个配置文件 nodemon.json,简单配置下

{
  "watch": [
    "server.js"
  ]
}

这样在改变 server.js 的时候服务器就会自动重启

好了,接下来就开始写创建接口

由于是数据库写入,这显然是一个 POST 请求,koa 需要一个中间件来解析 post 请求出入的参数。

npm i koa-bodyparser

使用起来也极其简单,koa 中间件使用方式都一样

import bodyparser from 'koa-bodyparser'
app.use(bodyparser())

万事俱备,只欠写入数据库了

import { MongoClient, ObjectId } from 'mongodb'
// 连接数据库
const client = new MongoClient('mongodb://localhost:27017')

router.post('/task/upsert', async (ctx, next) => {
  // 要操作的数据库
  const db = client.db('task-manager')
  // 要操作的表,mongodb 中叫做集合
  const collection = db.collection('task')
  // post 请求的参数经 bodyparser 后放在 ctx.request.body 里
  const doc = ctx.request.body
  const { _id } = doc
  const result = await collection.updateOne(
    // _id 是 mongodb 默认主键名,ObjectId 可用于生成一个唯一 id
    { _id: _id || ObjectId() },
    { $set: doc },
    // upsert 表示存在则更新,不存在则插入
    { upsert: true }
  )
  // 接口返回
  ctx.body = {
    doc,
    result,
  }
})

这里只需要关注一个 api,mongodb 的 db.collection.updateOne(),用于数据的插入或更新。

前端实现

根据交互设计,任务的查看和创建都在同一个页面,即看板视图。

在 components 目录新建一个组件 NewTaskCard.vue

关键代码就是请求创建任务接口

// src/components/NewTaskCard.vue
async submitNewTask () {
  await axios.post('/task/upsert', this.task)
},

由于服务器域名和开发服务器域名不一致,所以需要在 main.js 里设置一下服务端的域名

// main.js
axios.defaults.baseURL = `${location.protocol}//${location.hostname}:${SERVER_PORT}`

为了简单起见,看板暂时先放在 src/pages/Home.vue

关键代码就是定义任务的状态

// src/pages/Home.vue
taskStatus: {
  draft: '未开始',
  dev: '开发中',
  qa: '已提测',
  done: '已完成',
},

最后

实现效果如下

正文结束。点击查看代码变更

闲言碎语

mongodb or mongoose

mongodb 包是 MongoDB 官方给 node.js 出的 driver,通过它就可以直接调用数据库的 api,就像直接在 shell 中使用数据库一样方便。

mongodb 相对传统 MySQL 这种数据库,最重要的区别就是没有了表的概念,取而代之使用集合,集合中的每一条数据甚至不需要结构相同。

例如 mongodb 的集合中可能存的是这样子的数据

[
  { a: 1, b: true },
  { a: 'DOM', c: [ { d: null } ]}
]

一句话,自由,随便存,只要是 json 就能往里存。

mongoose 则是为了重现表的概念,核心概念是 Schema 和 Model,Schema 用来定义数据结构,Model 用来定义表。这样使得集合中的数据结构严整统一,少有冗余,像一张 excel 表格一样。当然 mongoose 还提供了其它高级特性,但我还不太熟悉,这里不再赘述。

为了减少 mongoose 的概念和知识产生的额外学习成本,这里就选择直接自由自在的操作 mongodb 吧

有对 mongoose 了解的同学欢迎评论区补充相对 mongodb 的优势。

有关03 开源任务管理系统:创建一个任务的更多相关文章

  1. ruby - 其他文件中的 Rake 任务 - 2

    我试图在一个项目中使用rake,如果我把所有东西都放到Rakefile中,它会很大并且很难读取/找到东西,所以我试着将每个命名空间放在lib/rake中它自己的文件中,我添加了这个到我的rake文件的顶部:Dir['#{File.dirname(__FILE__)}/lib/rake/*.rake'].map{|f|requiref}它加载文件没问题,但没有任务。我现在只有一个.rake文件作为测试,名为“servers.rake”,它看起来像这样:namespace:serverdotask:testdoputs"test"endend所以当我运行rakeserver:testid时

  2. ruby - 如何在 Ruby 中顺序创建 PI - 2

    出于纯粹的兴趣,我很好奇如何按顺序创建PI,而不是在过程结果之后生成数字,而是让数字在过程本身生成时显示。如果是这种情况,那么数字可以自行产生,我可以对以前看到的数字实现垃圾收集,从而创建一个无限系列。结果只是在Pi系列之后每秒生成一个数字。这是我通过互联网筛选的结果:这是流行的计算机友好算法,类机器算法:defarccot(x,unity)xpow=unity/xn=1sign=1sum=0loopdoterm=xpow/nbreakifterm==0sum+=sign*(xpow/n)xpow/=x*xn+=2sign=-signendsumenddefcalc_pi(digits

  3. ruby - i18n Assets 管理/翻译 UI - 2

    我正在使用i18n从头开始​​构建一个多语言网络应用程序,虽然我自己可以处理一大堆yml文件,但我说的语言(非常)有限,最终我想寻求外部帮助帮助。我想知道这里是否有人在使用UI插件/gem(与django上的django-rosetta不同)来处理多个翻译器,其中一些翻译器不愿意或无法处理存储库中的100多个文件,处理语言数据。谢谢&问候,安德拉斯(如果您已经在ruby​​onrails-talk上遇到了这个问题,我们深表歉意) 最佳答案 有一个rails3branchofthetolkgem在github上。您可以通过在Gemfi

  4. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  5. ruby - 使用 Vim Rails,您可以创建一个新的迁移文件并一次性打开它吗? - 2

    使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta

  6. ruby-on-rails - Rails - 一个 View 中的多个模型 - 2

    我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何

  7. ruby-on-rails - 渲染另一个 Controller 的 View - 2

    我想要做的是有2个不同的Controller,client和test_client。客户端Controller已经构建,我想创建一个test_clientController,我可以使用它来玩弄客户端的UI并根据需要进行调整。我主要是想绕过我在客户端中内置的验证及其对加载数据的管理Controller的依赖。所以我希望test_clientController加载示例数据集,然后呈现客户端Controller的索引View,以便我可以调整客户端UI。就是这样。我在test_clients索引方法中试过这个:classTestClientdefindexrender:template=>

  8. ruby-on-rails - 无法使用 Rails 3.2 创建插件? - 2

    我对最新版本的Rails有疑问。我创建了一个新应用程序(railsnewMyProject),但我没有脚本/生成,只有脚本/rails,当我输入ruby./script/railsgeneratepluginmy_plugin"Couldnotfindgeneratorplugin.".你知道如何生成插件模板吗?没有这个命令可以创建插件吗?PS:我正在使用Rails3.2.1和ruby​​1.8.7[universal-darwin11.0] 最佳答案 随着Rails3.2.0的发布,插件生成器已经被移除。查看变更日志here.现在

  9. ruby - 如何使用 RSpec::Core::RakeTask 创建 RSpec Rake 任务? - 2

    如何使用RSpec::Core::RakeTask初始化RSpecRake任务?require'rspec/core/rake_task'RSpec::Core::RakeTask.newdo|t|#whatdoIputinhere?endInitialize函数记录在http://rubydoc.info/github/rspec/rspec-core/RSpec/Core/RakeTask#initialize-instance_method没有很好的记录;它只是说:-(RakeTask)initialize(*args,&task_block)AnewinstanceofRake

  10. ruby-on-rails - 如果 Object::try 被发送到一个 nil 对象,为什么它会起作用? - 2

    如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象

随机推荐