blog-vue-kanban

by sakihet

HTML

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.6.0/css/bulma.min.css">
<script src="https://unpkg.com/vue@2.5.2/dist/vue.js"></script>
<section class="section" id="board">
  <div class="container">
    <input type="text" v-model="newTaskName" />
    <select v-model="newTaskAssignee">
      <option value="🐱">🐱</option>
      <option value="🐶">🐶</option>
      <option value="🐹">🐹</option>
    </select>
    <input type="number" v-model="newTaskMandays" />
    <button @click="addTask">追加</button>
    <hr>
    <div class=columns>
      <div class="column status-1">
        <div class="tags has-addons">
          <span class="tag">未対応</span>
          <span class="tag is-dark">{{ tasksOpen.length }}</span>
        </div>
        <transition-group name="fade">
          <task-card :task="task" v-for="task in tasksOpen" :key="task.name"></task-card>
        </transition-group>
      </div>
      <div class="column status-2">
        <div class="tags has-addons">
          <span class="tag">処理中</span>
          <span class="tag is-dark">{{ tasksDoing.length }}</span>
        </div>
        <transition-group name="fade">
          <task-card :task="task" v-for="task in tasksDoing" :key="task.name"></task-card>
        </transition-group>
      </div>
      <div class="column status-3">
        <div class="tags has-addons">
          <span class="tag">完了</span>
          <span class="tag is-dark">{{ tasksClosed.length }}</span>
        </div>
        <transition-group name="fade">
          <task-card :task="task" v-for="task in tasksClosed" :key="task.name"></task-card>
        </transition-group>
      </div>
    </div>
  </div>
</section>

CSS

.status-1 {
  background-color: #ed8077;
}
.status-2 {
  background-color: #4488c5;
}
.status-3 {
  background-color: #5eb5a6;
}
.card {
  margin-bottom: 5px;
}
.card-footer-item {
  padding-top: 0px;
  padding-bottom: 0px;
}
.fade-enter-active, .fade-leave-active {
  transition: opacity 0.7s
}
.fade-enter, .fade-leave-to {
  opacity: 0
}

JavaScript

var filters = {
	open: function (tasks) {
  	return tasks.filter(function (task) {
    	return task.status === 1
    })
  },
	doing: function (tasks) {
  	return tasks.filter(function (task) {
    	return task.status === 2
    })
  },
  closed: function (tasks) {
  	return tasks.filter(function (task) {
    	return task.status === 3
    })
  }
}

Vue.component('task-card', {
	props: ['task'],
  template: `<div class="card">
            <div class="card-content">
              {{ task.name }}
            </div>
            <footer class="card-footer">
              <div class="card-footer-item">
                {{ task.assignee }}
              </div>
              <div class="card-footer-item">
                {{ task.mandays }} 人日
              </div>
            </footer>
            <footer class="card-footer">
              <a class="card-footer-item" @click="decrementStatus(task)">◀︎</a>
              <a class="card-footer-item" @click="incrementStatus(task)">▶︎</a>
            </footer>
          </div>`,
  methods: {
    incrementStatus: function (task) {
      if(1 <= task.status && task.status <= 2) {
      	task.status++
      }
    },
    decrementStatus: function (task) {
      if(2 <= task.status && task.status <= 3) {
      	task.status--
      }
    }
  }
})

new Vue({
	el: '#board',
  data: {
    tasks: [
    	{ name: 'task 1', status: 1, assignee: '🐱', mandays: 3 },
      { name: 'task 2', status: 1, assignee: '🐶', mandays: 2 },
      { name: 'task 3', status: 2, assignee: '🐱', mandays: 1 },
      { name: 'task 4', status: 3, assignee: '🐹', mandays: 1 }
    ],
    newTaskName: '',
    newTaskAssignee: null,
    newTaskMandays: 0
  },
  computed: {
    tasksOpen: function () {
      return filters.open(this.tasks)
    },
    tasksDoing: function () {
      return filters.doing(this.tasks)
    },
    tasksClosed: function () {
      return filters.closed(this.tasks)
    }
  },
  methods: {
  	addTask () {
    	this.tasks.push({ name:...