浏览代码

Merge branch 'http_mock' of git.xiaojukeji.com:jacklijiajia/thoth-frontend into http_mock

qinzhipeng_v 5 年之前
父节点
当前提交
2a9db91fda
共有 5 个文件被更改,包括 693 次插入68 次删除
  1. 45 0
      src/api/teamBench.js
  2. 0 5
      src/router/index.js
  3. 142 63
      src/views/Platform/Workbench/TeamWorkbench.vue
  4. 457 0
      src/views/gantta/gantta.vue
  5. 49 0
      src/views/gantta/ganttaFunc.js

+ 45 - 0
src/api/teamBench.js

@@ -0,0 +1,45 @@
+import request from '@/utils/request'
+import { TeamManagement } from '@/apiConfig/api'
+// ================================== Interface ======================================
+
+// // 获取发版信息
+// export function releaseList() {
+//   return request({
+//     url: TeamManagement + '/config/showVersionEnum',
+//     method: 'get'
+//   })
+// }
+// 获取发版信息
+export function releaseList() {
+  return request({
+    url: TeamManagement + '/config/showAppClientEnum',
+    method: 'get'
+  })
+}
+
+// 获取排期
+export function scheduleList(data) {
+  return request({
+    url: TeamManagement + '/Schedule/scheduleByEname',
+    method: 'post',
+    data
+  })
+}
+
+// 获取发版排期
+export function releaseScheduleList(data) {
+  return request({
+    url: TeamManagement + '/VersionSchedule/listByVersionTypeWithTime',
+    method: 'post',
+    data
+  })
+}
+
+// // 获取发版排期
+// export function releaseScheduleList(params) {
+//   return request({
+//     url: TeamManagement + '/sVersionSchedule/listByVersionType',
+//     method: 'get',
+//     params
+//   })
+// }

+ 0 - 5
src/router/index.js

@@ -391,14 +391,9 @@ export const constantRoutes = [
         component: () => import('@/views/Platform/Workbench/PersonalWorkbench'),
         meta: { title: '个人工作台' }
       },
-      {
-        path: 'TeamWorkb1ench',
-        name: '团队工作台'
-      },
       {
         path: 'TeamWorkbench',
         name: '团队工作台',
-        hidden: true,
         component: () => import('@/views/Platform/Workbench/TeamWorkbench'),
         meta: { title: '团队工作台' }
       }

+ 142 - 63
src/views/Platform/Workbench/TeamWorkbench.vue

@@ -1,85 +1,164 @@
 <template>
-  <div class="bgColorSz">
-    <full-calendar :events="events" lang="zh" class="test-fc" first-day="1" locale="fr" style="width:100%" @changeMonth="changeMonth" @eventClick="eventClick" @dayClick="dayClick" @moreClick="moreClick"> />
-      <div id="calendar" style="height: 800px;" />
-    </full-calendar></div>
+  <div class="set-background">
+    <div class="block-head">
+      <el-select v-model="personalOrteam" filterable placeholder="请选择" @change="changeSelect">
+        <el-option
+          v-for="item in options"
+          :key="item.value"
+          :label="item.label"
+          :value="item.code"
+        />
+      </el-select>
+      <el-select v-model="release" class="special" clearable filterable placeholder="加入端发版信息" @clear="clearTrigger" @change="changeVersionSelect">
+        <el-option
+          v-for="item in optionsRelease"
+          :key="item.code"
+          :label="item.msg"
+          :value="item.code"
+        />
+      </el-select>
+      <el-checkbox v-model="checked" style="margin-left:20px" @change="handleChecked">仅展示跟版任务</el-checkbox>
+    </div>
+    <div class="block">
+      <div class="set-flex">
+        <div class="head-line" />
+        <div>团队{{ stringType }}工作台</div>
+      </div>
+      <gantt v-if="ganttData" :table-data="ganttData" :string-type="stringType" :versions="appVersion" />
+    </div>
+  </div>
 </template>
 <script>
+import dayjs from 'dayjs'
+import Gantt from '@/views/gantta/gantta'
+import { tableDataDeal, versionDeal } from '@/views/gantta/ganttaFunc'
+import { releaseList, scheduleList, releaseScheduleList } from '@/api/teamBench'
 
 export default {
-  name: 'TeamWorkbench',
   components: {
-    'full-calendar': require('vue-fullcalendar')
+    Gantt
   },
   data() {
     return {
-      events: [
-        {
-          title: '郑美双:前端计划',
-          start: '2019-12-01',
-          end: '2019-12-05',
-          cssClass: 'red',
-          YOUR_DATA: { shan: '你好' }
-        },
-        {
-          title: '郑美双:前端计划',
-          start: '2019-12-01',
-          end: '2019-12-23',
-          cssClass: 'red',
-          YOUR_DATA: {}
-        },
-        {
-          title: '秦志鹏:前端计划',
-          start: '2019-12-05',
-          end: '2019-12-07',
-          cssClass: ['family', 'career'],
-          YOUR_DATA: {}
-        },
-        {
-          title: '汝瑞: UI计划,流程管控项目第四版更新包',
-          start: '2019-12-12',
-          end: '2019-12-18',
-          cssClass: 'blue'
-        }
-      ]
+      options: [{
+        value: '按团队成员',
+        label: '按团队成员',
+        code: 2
+      }, {
+        value: '按团队任务',
+        label: '按团队任务',
+        code: 1
+      }],
+      stringType: '成员',
+      userInformation: localStorage.getItem('username'),
+      userNames: localStorage.getItem('realname'),
+      optionsRelease: [],
+      ganttData: null,
+      personalOrteam: 2,
+      release: '',
+      appVersion: {},
+      pTType: 2,
+      followApp: false,
+      checked: false
     }
   },
   created() {
+    this.defaultDisplay()
+    this.getList()
   },
   methods: {
-    // 选择月份
-    changeMonth(start, end, current) {
-      console.log('changeMonth', start.format(), end.format(), current.format())
+    defaultDisplay() {
+      const param = { ename: this.userInformation, type: this.pTType, followApp: this.followApp, startTime: dayjs().subtract(1, 'month'), endTime: dayjs().add(1, 'month') }
+      scheduleList(param).then(res => {
+        if (res.code === 200) {
+          this.ganttData = tableDataDeal(res.data)
+        }
+        // console.log(this.ganttData)
+      })
+    },
+    changeSelect(val) {
+      val === 2 && (this.pTType = 2)
+      val === 1 && (this.pTType = 1)
+      this.stringType = this.pTType === 2 ? '成员' : '任务'
+      this.defaultDisplay()
     },
-    // 点击事件
-    eventClick(event, jsEvent, pos) {
-      console.log('eventClick', event, jsEvent, pos)
+    changeVersionSelect(val) {
+      const param = { appType: val, startTime: dayjs().subtract(1, 'month'), endTime: dayjs().add(1, 'month') }
+      releaseScheduleList(param).then((res) => {
+        if (res.code === 200) {
+          this.appVersion = versionDeal(res.data, val, this.optionsRelease)
+        } else {
+          this.errFun(res.msg)
+        }
+      })
+    },
+    getList() {
+      releaseList().then(res => {
+        if (res.code === 200) {
+          this.optionsRelease = res.data.appClient || []
+        } else {
+          this.errFun(res.msg)
+        }
+      })
     },
-    // 点击当天
-    dayClick(day, jsEvent) {
-      console.log('dayClick', day, jsEvent)
+    clearTrigger() {
+      this.appVersion = {}
     },
-    // 查看更多
-    moreClick(day, events, jsEvent) {
-      console.log('moreCLick', day, events, jsEvent)
+    handleChecked(isChecked) {
+      this.followApp = isChecked
+      this.defaultDisplay()
+    },
+    successFun() {
+      this.$message({
+        message: '操作成功',
+        type: 'success'
+      })
+    },
+    errFun(errFun) {
+      this.$message.error(errFun)
     }
   }
 }
 </script>
-<style scoped>
-  .bgColorSz {
-    width: 100%;
-    height: 96vh;
-    background: #F2F3F6;
-    font-size: 0.9rem;
-    display: flex;
-    justify-content: center;
-    align-items: center;
-  }
-  .red {
-  background-color: red;
-}
-.blue {
-  background: blue;
-}
+<style lang="stylus" scoped>
+  .block-head >>> .el-input__inner
+    border 0px solid #DCDFE6
+    margin-right -70px
+    font-size 14px
+    color rgba(51,51,51,1)
+  .block-head .special >>> .el-input__inner
+    border 0px solid #DCDFE6
+    margin-right -30px
+    font-size 14px
+    color rgba(51,51,51,1)
+  .set-background
+    background-color #F2F3F6
+    display flex
+    flex-wrap wrap
+    justify-content center
+    min-width 900px
+    .block-head
+      background-color rgba(255,255,255,1)
+      box-shadow 0px 0px 11px 0px rgba(238,240,245,1)
+      border-radius 7px
+      width 96%
+      margin 20px 0
+      padding 15px
+      height 70px
+    .block
+      background-color rgba(255,255,255,1)
+      box-shadow 0px 0px 11px 0px rgba(238,240,245,1)
+      border-radius 7px
+      width 96%
+      margin-bottom 20px
+      padding 20px
+      min-height calc(100vh - 210px)
+      .set-flex
+        display flex
+        .head-line
+          width 4px
+          height 17px
+          background rgba(64,158,255,1)
+          border-radius 1px
+          margin 0 10px 20px 0
 </style>

+ 457 - 0
src/views/gantta/gantta.vue

@@ -0,0 +1,457 @@
+<template>
+  <el-table
+    :data="correctData"
+    style="width: 100%"
+    border
+    :header-cell-style="headerCellStyle"
+    :span-method="arraySpanMethod"
+    size="mini"
+  >
+    <el-table-column prop="task" :label="stringType" show-overflow-tooltip fixed width="250">
+      <template v-slot="scope">
+        <div class="set-flex">
+          <div class="vertical-line" :style="{'background-color':colorList[scope.$index % 5]}" />
+          <!-- <el-color-picker v-model="correctData[scope.$index].task.color" show-alpha></el-color-picker> -->
+          <el-tooltip class="item" :disabled="correctData[scope.$index].task.description.length <= 16" effect="light" :content="correctData[scope.$index].task.description" placement="top">
+            <div
+              class="specail"
+            > {{ correctData[scope.$index].task.description.length > 16 ? correctData[scope.$index].task.description.slice(0,16) + '...' : correctData[scope.$index].task.description }} </div>
+          </el-tooltip>
+        </div>
+      </template>
+    </el-table-column>
+    <el-table-column
+      v-for="(header,index) in headers"
+      :key="index"
+      :prop="header.version"
+      :label="header.version"
+    >
+      <el-table-column :prop="header.date" :label="header.date">
+        <el-table-column :prop="header.date" :label="header.day" width="130">
+          <template v-slot="scope">
+            <el-popover
+              placement="bottom"
+              width="250"
+              trigger="hover"
+            >
+              <div>{{ getContent(header.date,scope.row.schedules) ? getContent(header.date,scope.row.schedules).taskName : '' }}</div>
+              <div>事件 : {{ getContent(header.date,scope.row.schedules) ? getContent(header.date,scope.row.schedules).event : '' }}</div>
+              <div>排期 : {{ getContent(header.date,scope.row.schedules) ? getContent(header.date,scope.row.schedules).schedule : '' }}</div>
+              <div>参与人员 : {{ getContent(header.date,scope.row.schedules) ? getContent(header.date,scope.row.schedules).owners.join('、') : '' }}</div>
+              <div class="href-location">
+                <el-link :underline="false" type="primary" @click="jumpToTask(getContent(header.date,scope.row.schedules) ? getContent(header.date,scope.row.schedules).taskId : '')">前往任务主页<i class="el-icon-d-arrow-right" /></el-link>
+              </div>
+              <div
+                v-if="getContent(header.date,scope.row.schedules)"
+                slot="reference"
+                :style="{background: colorList[scope.$index % 5]}"
+                class="block"
+                @click="show(scope)"
+              >
+                <span> {{ getContent(header.date,scope.row.schedules).taskName + ' : &nbsp;' + getContent(header.date,scope.row.schedules).event + '&nbsp;&nbsp;&nbsp;' }}</span>
+                <span v-if="stringType === '任务'">{{ getContent(header.date,scope.row.schedules).owners.join('、') }}</span>
+                <!-- <span
+                  v-for="(owner,ownerIndex) in getContent(header.date,scope.row.schedules) ? getContent(header.date,scope.row.schedules).owners : []"
+                  :key="ownerIndex"
+                >{{owner}}</span> -->
+              </div>
+            </el-popover>
+          </template>
+        </el-table-column>
+      </el-table-column>
+    </el-table-column>
+  </el-table>
+</template>
+
+<script>
+import dayjs from 'dayjs'
+
+export default {
+  props: {
+    stringType: {
+      type: String,
+      default() {
+        return '成员'
+      }
+    },
+    tableData: {
+      type: Array,
+      default() {
+        return [
+          {
+            task: {
+              description: '任务1'
+            },
+            schedules: [
+              {
+                taskName: '任务1',
+                event: '测试用例编写测试',
+                schedule: '2010.12.05 - 2019.12.05',
+                startDate: '2019-12-15',
+                length: 5,
+                owners: ['刘青']
+              },
+              {
+                taskName: '任务1',
+                event: '测试用例编写测试',
+                schedule: '2010.12.05 - 2019.12.05',
+                startDate: '2019-12-09',
+                length: 3,
+                owners: ['显调', '志鹏']
+              }
+            ]
+          },
+          {
+            task: {
+              description: '任务2'
+            },
+            schedules: [
+              {
+                taskName: '任务2',
+                event: '测试用例编写测试',
+                schedule: '2010.12.05 - 2019.12.05',
+                startDate: '2019-12-10',
+                length: 2,
+                owners: ['负责人']
+              },
+              {
+                taskName: '任务2',
+                event: '测试用例编写测试',
+                schedule: '2010.12.05 - 2019.12.05',
+                startDate: '2019-12-13',
+                length: 3,
+                owners: ['嘉嘉', '赵杰']
+              },
+              {
+                taskName: '任务2',
+                event: '测试用例编写测试',
+                schedule: '2010.12.05 - 2019.12.05',
+                startDate: '2019-12-19',
+                length: 3,
+                owners: ['负责人', '负责人']
+              }
+            ]
+          },
+          {
+            task: {
+              description: '任务3'
+            },
+            schedules: [
+              {
+                taskName: '任务3',
+                event: '测试用例编写测试',
+                schedule: '2010.12.05 - 2019.12.05',
+                startDate: '2019-12-11',
+                length: 3,
+                owners: ['负责人', '负责人']
+              }
+            ]
+          },
+          {
+            task: {
+              description: '任务3'
+            },
+            schedules: [
+              {
+                taskName: '任务3',
+                event: '测试用例编写测试',
+                schedule: '2010.12.05 - 2019.12.05',
+                startDate: '2019-12-11',
+                length: 3,
+                owners: ['负责人', '负责人']
+              }
+            ]
+          },
+          {
+            task: {
+              description: '任务3'
+            },
+            schedules: [
+              {
+                taskName: '任务3',
+                event: '测试用例编写测试',
+                schedule: '2010.12.05 - 2019.12.05',
+                startDate: '2019-12-11',
+                length: 3,
+                owners: ['负责人', '负责人']
+              }
+            ]
+          },
+          {
+            task: {
+              description: '任务3'
+            },
+            schedules: [
+              {
+                taskName: '任务3',
+                event: '测试用例编写测试',
+                schedule: '2010.12.05 - 2019.12.05',
+                startDate: '2019-12-11',
+                length: 3,
+                owners: ['负责人', '负责人']
+              }
+            ]
+          },
+          {
+            task: {
+              description: '任务4'
+            },
+            schedules: [
+              {
+                taskName: '任务4',
+                event: '测试用例编写测试',
+                schedule: '2010.12.05 - 2019.12.05',
+                startDate: '2019-12-12',
+                length: 40,
+                owners: ['负责人', '负责人']
+              }
+            ]
+          }
+        ]
+      }
+    },
+    versions: {
+      type: Object,
+      default() {
+        return {
+          '2019-12-11': '1.0.0',
+          '2019-12-12': '1.0.0',
+          '2019-12-16': '1.2.0',
+          '2019-12-19': '1.5.0'
+        }
+      }
+    }
+  },
+  data() {
+    return {
+      colorList: ['rgba(255,82,0,0.5)', 'rgba(227,131,247,0.5)', 'rgba(68,190,255,0.5)', 'rgba(122,221,13,0.5)', 'rgba(245,108,108,0.5)'],
+      today: '',
+      headers: []
+    }
+  },
+  computed: {
+    correctData() {
+      const data = JSON.parse(JSON.stringify(this.tableData))
+      for (const i in data) {
+        if (data[i].schedules.length > 1) {
+          let dayCount = 0
+          for (let j = 1; j < data[i].schedules.length; j++) {
+            dayCount += data[i].schedules[j - 1].length - 1
+            data[i].schedules[j].startDate = this.dateMinusDays(
+              data[i].schedules[j].startDate,
+              dayCount
+            )
+          }
+        }
+      }
+      return data
+    }
+  },
+  watch: {
+    versions() {
+      this.headers = this.createheaders()
+    }
+  },
+  created() {
+    this.today = this.dateFmt('yyyy-MM-dd', new Date())
+    this.headers = this.createheaders()
+  },
+  methods: {
+    createheaders() {
+      let minDate
+      let maxDate
+      for (const i in this.tableData) {
+        for (const j in this.tableData[i].schedules) {
+          const start = new Date(this.tableData[i].schedules[j].startDate)
+          const end = new Date(
+            (start / 1000 +
+              (86400 * this.tableData[i].schedules[j].length - 1)) *
+              1000
+          )
+          if (!minDate || minDate.getTime() > start.getTime()) {
+            minDate = start
+          }
+          if (!maxDate || maxDate.getTime() < end.getTime()) {
+            maxDate = end
+          }
+        }
+      }
+      const arr = []
+      for (
+        let i = 0;
+        i <= (maxDate.getTime() - minDate.getTime()) / (24 * 60 * 60 * 1000);
+        i++
+      ) {
+        const header = {
+          version: '',
+          date: '',
+          day: ''
+        }
+        header.date = this.dateAddDays(minDate, i)
+        header.day = this.dateToDay(header.date)
+        if (typeof this.versions[header.date] !== 'undefined') {
+          header.version = this.versions[header.date]
+        }
+        arr.push(header)
+      }
+      // console.log(arr)
+      return arr
+    },
+    jumpToTask(e) {
+      this.$router.push({ name: '任务查看', query: { id: e }})
+    },
+    headerCellStyle({ row, column, rowIndex, columnIndex }) {
+      if (rowIndex === 0) {
+        return {
+          'text-align': 'center',
+          'background': 'transparent'
+          // 'border': '0px',
+          // 'color': '#000000'
+        }
+      } else if (column.property === this.today) {
+        return {
+          'text-align': 'center',
+          'background': 'transparent',
+          'color': '#F56C6C'
+        }
+      } else if (dayjs(column.property).day().toString() === '6' || dayjs(column.property).day().toString() === '0') {
+        return {
+          'text-align': 'center',
+          'background': 'transparent',
+          'color': '#D8D8D8'
+        }
+      } else {
+        return {
+          // 'color': '#000000',
+          'background': 'transparent',
+          'text-align': 'center'
+        }
+      }
+    },
+    arraySpanMethod({ row, column, rowIndex, columnIndex }) {
+      if (column.property === '任务') return
+      for (const i in row.schedules) {
+        if (column.property === row.schedules[i].startDate) {
+          return [1, row.schedules[i].length]
+        }
+      }
+    },
+    show(scope) {
+      console.log(scope)
+    },
+    getContent(date, schedules) {
+      for (const i in schedules) {
+        if (date === schedules[i].startDate) {
+          return schedules[i]
+        }
+      }
+    },
+    dateToDay(dataStr) {
+      var strdate = dataStr // 日期字符串
+      if (strdate === this.today) { return '今天' }
+      var isdate = new Date(strdate) // 把日期字符串转换成日期格式
+      let day = ''
+      switch (isdate.getDay()) {
+        case 1:
+          day = '周一'
+          break
+        case 2:
+          day = '周二'
+          break
+        case 3:
+          day = '周三'
+          break
+        case 4:
+          day = '周四'
+          break
+        case 5:
+          day = '周五'
+          break
+        case 6:
+          day = '周六'
+          break
+        case 0:
+          day = '周日'
+          break
+      }
+      return day
+    },
+    dateAddDays(dataStr, dayCount) {
+      var strdate = dataStr // 日期字符串
+      var isdate = new Date(strdate) // 把日期字符串转换成日期格式
+      isdate = new Date((isdate / 1000 + 86400 * dayCount) * 1000) // 日期加1天
+      var pdate = this.dateFmt('yyyy-MM-dd', isdate) // 把日期格式转换成字符串
+      return pdate
+    },
+    dateMinusDays(dataStr, dayCount) {
+      var strdate = dataStr // 日期字符串
+      var isdate = new Date(strdate) // 把日期字符串转换成日期格式
+      isdate = new Date((isdate / 1000 - 86400 * dayCount) * 1000) // 日期加1天
+      var pdate = this.dateFmt('yyyy-MM-dd', isdate) // 把日期格式转换成字符串
+      return pdate
+    },
+    dateFmt(fmt, date) {
+      // author: meizz
+      var o = {
+        'M+': date.getMonth() + 1, // 月份
+        'd+': date.getDate(), // 日
+        'h+': date.getHours(), // 小时
+        'm+': date.getMinutes(), // 分
+        's+': date.getSeconds(), // 秒
+        'q+': Math.floor((date.getMonth() + 3) / 3), // 季度
+        S: date.getMilliseconds() // 毫秒
+      }
+      if (/(y+)/.test(fmt)) {
+        fmt = fmt.replace(
+          RegExp.$1,
+          (date.getFullYear() + '').substr(4 - RegExp.$1.length)
+        )
+      }
+      for (var k in o) {
+        if (new RegExp('(' + k + ')').test(fmt)) {
+          fmt = fmt.replace(
+            RegExp.$1,
+            RegExp.$1.length === 1
+              ? o[k]
+              : ('00' + o[k]).substr(('' + o[k]).length)
+          )
+        }
+      }
+      return fmt
+    }
+  }
+}
+</script>
+
+<style lang="stylus" scoped>
+  .href-location >>> .el-link
+    margin-top 20px
+    opacity 0.8
+    font-weight 400
+  .set-flex
+    display flex
+    justify-content center
+    align-items center
+    .vertical-line
+      width 4px
+      height 16px
+      border-radius 4px
+    .specail
+      font-size 14px
+      margin 2px 0 0 8px
+      font-family MicrosoftYaHei
+      color rgba(51,59,74,1)
+      line-height 35px
+  .href-location
+    height 35px
+    text-align right
+  .block
+    width 100%
+    border-radius 4px
+    padding 8px 15px 6px 15px
+    overflow hidden //超出的文本隐藏
+    text-overflow ellipsis //溢出用省略号显示
+    white-space nowrap //溢出不换行
+    font-size 13px
+    font-weight 400
+</style>

+ 49 - 0
src/views/gantta/ganttaFunc.js

@@ -0,0 +1,49 @@
+import dayjs from 'dayjs'
+
+export function versionDeal(arr, versionCode, optionsRelease) {
+  const result = {}
+  for (let i = 0; i < arr.length; i++) {
+    let pauseTime = dayjs(arr[i].startTime).format('YYYY-MM-DD')
+    while (pauseTime <= dayjs(arr[i].endTime).format('YYYY-MM-DD')) {
+      result[pauseTime] = optionsRelease.filter(eachData => eachData.code === versionCode)[0].msg + arr[i].version + arr[i].name
+      pauseTime = dayjs(pauseTime).add(1, 'day').format('YYYY-MM-DD')
+    }
+  }
+  return result
+}
+
+export function tableDataDeal(obj) {
+  return Object.keys(obj).map(eachKey => ({
+    task: { description: eachKey },
+    schedules: bubble(obj[eachKey].map(eachData => ({
+      taskName: eachData.taskName,
+      event: eachData.name,
+      schedule: dayjs(eachData.startTime).format('YYYY.MM.DD') + ' - ' + dayjs(eachData.endTime).format('YYYY.MM.DD'),
+      startDate: dayjs(eachData.startTime).format('YYYY-MM-DD'),
+      length: (dayjs(eachData.endTime) - dayjs(eachData.startTime)) / 86400000 + 1,
+      owners: eachData.peopleObject.map(eachMember => eachMember.name),
+      taskId: eachData.taskId
+    })).filter(eachData => eachData.length !== 1))
+  }))
+}
+
+function bubble(arr) {
+  const res = Object.assign([], arr)
+  const max = res.length - 1
+  for (let j = 0; j < max; j++) {
+    // 声明一个变量,作为标志位
+    let done = true
+    for (let i = 0; i < max - j; i++) {
+      if (res[i].startDate > res[i + 1].startDate) {
+        var temp = res[i]
+        res[i] = res[i + 1]
+        res[i + 1] = temp
+        done = false
+      }
+    }
+    if (done) {
+      break
+    }
+  }
+  return res
+}