LoginSignup
30
29

More than 5 years have passed since last update.

VueとElectronでタスク管理アプリを作りはじめた

Last updated at Posted at 2016-12-18

動機

いままで様々なタスク管理アプリを使ってきましたが、いまはTogglをメインに使っています。

しかしTogglは、どちらかと言うとタイムトラッキングアプリであって、ほんとうの意味でのタスク管理には向いていません。

個人的には、「カンバン」方式のタスク管理と、各タスクの所要時間を統一的に管理したいのですが、なかなかいいものが見つかりません。

KanbanFlowも試しましたが、個人で使うには重厚で、ちょっと馴染みませんでした。

そこで、VueとElectronで自作しようと考えました。

準備

electron-vue で一発です。

詳細は http://qiita.com/SatoTakumi/items/fd79672d7eb8a9b4a0bb さんが説明されてれいます。

初めてElectronを使いましたが、どこにも詰まることなく導入できたのは驚きです。

Electron側からOSのAPIをいくつか利用できるので、例えば「現在アクティブなWindow」とか「マウスの位置」などを取得することで、Togglのような「非アクティブを検知してタスク消化を促す」仕組みも簡単に実装できそうです。

Componentの構造

Componentはシンプルに以下のように分割しています。

task-time-tracker.4li6c.2016-12-19.午前0時-15-06.png

親Component

親Componentである App.vue はシンプルに、子Componentを回しているだけです。

要素のドラッグを実現するために vue-dragula を利用しています。
このドラッグイベントをキャッチするために、グローバルはイベントバス Vue.vueDragula.eventBus を利用して「どこにドラッグされたか」を受け取り、 mutation を叩いています。

App.vue
<template>
  <div id="app-main">
    <div id="app-left">
      <div>
        ToDo
        <button id="new-task" @click="newTask">New Task</button>
      </div>
      <div class="task-card-container" v-dragula="todoTasks" bag="bag" data-status="todo">
        <todo-task :task="task" v-for="task in todoTasks" :key="task.id"></todo-task>
      </div>
    </div>
    <div id="app-center">
      <div>Doing</div>
      <div class="task-card-container" v-dragula="doingTasks" bag="bag" data-status="doing">
        <doing-task :task="task" v-for="task in doingTasks" :key="task.id"></doing-task>
      </div>
    </div>
    <div id="app-right">
      <div>Done</div>
      <div class="task-card-container" v-dragula="doneTasks" bag="bag" data-status="done">
        <done-task :task="task" v-for="task in doneTasks" :key="task.id"></done-task>
      </div>
    </div>
  </div>
</template>

<script>
...
    mounted () {
      Vue.vueDragula.eventBus.$on('drop', ([bag, dropElm, target, source]) => {
        console.log(target.children)
        const index = Array.prototype.indexOf.call(target.children, dropElm)
        const taskId = dropElm.dataset.taskId
        const nextStatus = target.dataset.status

        this.$store.commit(t.UPDATE_TASK_STATUS, {taskId, nextStatus, index})
      })
    }
...
</script>

子Component

子Componentは、タスク名と経過時間を表示するだけなので、こちらもシンプルです。

DoingTask.vue
<template>
  <div class="task-card" :data-task-id="task.id">
    <div class="task-left">{{task.name}}</div>
    <div class="task-right">{{duration}}</div>
  </div>
</template>

<script>
  import moment from 'moment'
  import utils from '../utils'

  export default {
    props: ['task'],
    data () {
      return {
        duration: utils.formatHour(this.task.duration + (moment().unix() - this.task.start))
      }
    },
    mounted () {
      setInterval(() => {
        this.duration = utils.formatHour(this.task.duration + (moment().unix() - this.task.start))
      }, 1000 / 60)
    }
  }
</script>

一点、秒数を表示する部分を毎秒更新したかったので、this.durationcomputed ではなく、dataにしてsetIntervalで更新しています。

Store

Storeのデータ構造は tasks の配列になっています。

store.js
const state = {
  tasks: [
    {
      id: 1234,
      status: 'done',
      name: 'task a',
      duration: 60 * 60 * 3,
      position: 1,
      history: [
        {
          start: moment('2016-12-01 06:00:00').unix(),
          end: moment('2016-12-01 09:00:00').unix()
        },
        {
          start: moment('2016-12-01 08:00:00').unix(),
          end: moment('2016-12-01 10:00:00').unix()
        }
      ]
    },
...

まとめ

今回のコードはこちらにあります。
https://github.com/tadyjp/hello-electron-vue

Vueを使うと結構簡単にアプリが作れることがわかりました。
OSの機能を利用したリッチなアプリケーションを作る時に、「Vue+Electron」はお手軽な選択肢になるのではないかと思います。

年明けくらいには、実際に配れるアプリにしたいなと考えてます。続報あったらまたお知らせします。

2017/01/26追記

全く進んでいないorz

30
29
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
30
29