粥里有勺糖

vuePress-theme-reco 粥里有勺糖    2018 - 2023
粥里有勺糖 粥里有勺糖

Choose mode

  • dark
  • auto
  • light
关于我
备战春秋
  • 心得总结
  • 校招考点汇总
  • 面经汇总
  • 复习自查
技术笔记
  • 技术教程
  • 模板工程
  • 源码学习
  • 技术概念
  • 个人作品
  • 学习笔记
计算机基础
  • 算法与数据结构
  • 操作系统
  • 计算机网络
  • 设计模式
  • 剑指offer
大前端
  • javascript
  • vue
  • html
  • css
  • 🌏浏览器专题
  • Web性能优化
  • regexp
  • node
面试
  • 问解
  • javascript
  • css
  • 手撕代码
  • 性能优化
  • 综合问题
  • 面经汇总
  • 小程序
手撕代码
  • 数据结构与算法
  • javascript
  • css
个人站点
  • GitHub (opens new window)
  • 博客园 (opens new window)
  • 掘金 (opens new window)
线上作品
  • 轻取(文件收集) (opens new window)
  • 个人图床 (opens new window)
  • 考勤小程序 (opens new window)
  • 时光恋人 (opens new window)
  • 在线简历生成 (opens new window)
留言板
Github (opens new window)
author-avatar

粥里有勺糖

285

文章

40

标签

关于我
备战春秋
  • 心得总结
  • 校招考点汇总
  • 面经汇总
  • 复习自查
技术笔记
  • 技术教程
  • 模板工程
  • 源码学习
  • 技术概念
  • 个人作品
  • 学习笔记
计算机基础
  • 算法与数据结构
  • 操作系统
  • 计算机网络
  • 设计模式
  • 剑指offer
大前端
  • javascript
  • vue
  • html
  • css
  • 🌏浏览器专题
  • Web性能优化
  • regexp
  • node
面试
  • 问解
  • javascript
  • css
  • 手撕代码
  • 性能优化
  • 综合问题
  • 面经汇总
  • 小程序
手撕代码
  • 数据结构与算法
  • javascript
  • css
个人站点
  • GitHub (opens new window)
  • 博客园 (opens new window)
  • 掘金 (opens new window)
线上作品
  • 轻取(文件收集) (opens new window)
  • 个人图床 (opens new window)
  • 考勤小程序 (opens new window)
  • 时光恋人 (opens new window)
  • 在线简历生成 (opens new window)
留言板
Github (opens new window)
  • wheel

    • 个人作品
    • 时间管理CLI工具
      • 做一个CLI版的时间管理工具(一)
      • 做一个CLI版的时间管理工具(十)
      • 做一个CLI版的时间管理工具(11)
      • 做一个CLI版的时间管理工具(12)
      • 做一个CLI版的时间管理工具(13)
      • 做一个CLI版的时间管理工具(14)
      • 做一个CLI版的时间管理工具(15)
      • 做一个CLI版的时间管理工具(二)
      • 做一个CLI版的时间管理工具(三)
      • 做一个CLI版的时间管理工具(四)
      • 做一个CLI版的时间管理工具(五)
      • 做一个CLI版的时间管理工具(六)
      • 做一个CLI版的时间管理工具(七)
      • 做一个CLI版的时间管理工具(八)
      • 做一个CLI版的时间管理工具(九)
    • 组装个支持记笔记的CodePen
    • ESCheck工具原理解析及增强实现
    • 一款检测代码中TODO的eslint插件
    • 实现一个Web UI检测(视觉走查)工具ing
    • 从0-1实现文件下载CLI工具
    • 内联JS处理(ES语法降级&内容压缩)
    • Node CLI工具原理解析
    • 我打造的在线简历生成应用
    • 助你轻松编写与分享snippet的VsCode插件
    • SourceMap解析CLI工具实现
    • 一个通过NPM包共(分)享代码块的解决方案
    • 实践:给女朋友个性化定制应用-体重记录(一)
    • 实践:给女朋友个性化定制应用-体重记录(二)
    • 实践:给女朋友个性化定制应用-体重记录(三)

做一个CL版的时间管理工具(五)

vuePress-theme-reco 粥里有勺糖    2018 - 2023

做一个CL版的时间管理工具(五)

粥里有勺糖 2021-08-06 技术笔记个人作品CLI工具

# 做一个CLI版的时间管理工具(五)

# 前言

上一篇文章主要阐述了两个指令的开发:

  • 初始化项目模板指令:timec init <projectName>
  • 初始化记录模板指令:timec create <filename>

本节将主要介绍:自动生成一段时间内的报告

期望效果的指令为:timec -or --range <startTime>_<endTime> <filename1> <filename1> .....

# 本期效果

图片

# 功能开发

# 一定时间范围内的报告生成

可用于周报,日报,月报的统计数据生成,方便自己复盘一周所做的事情

# 指令注册

注意:省略了前几篇里已经出现过的指令逻辑

轻车熟路,使用option方法注册新的可选参数:

  • -r:代表要输出报告
  • -R:代表要输出的事件范围
// 导出
commander.arguments('<filenames...>') // 多个文件/目录
    .option('-o, --output', 'Export analysis results')
    .option('-r, --report', 'Export the result as a md report')
    .option('-R, --range [startDate_endDate]', 'A time period')
    // .action
1
2
3
4
5
6

再添加简单的判断逻辑:

  • -r对应的是report属性,为true表明启用了这个option
  • -R对应range属性,其值为string类型
    • 开始与结束时间使用下划线_分割
  • 主要关注getJSONByRange与outPutReport这两个方法的实现
  • 内容的读取逻辑(content),在前几篇的文章已经详细介绍过了,这里就不再赘述
    .action((filenames, cmdObj) => {
        const { output,report } = cmdObj
        // 导出
        if (output) {
            let outFileName = 'res'

            if(report){
                const {range} = cmdObj
                if(range){
                    const [startTime,endTime] = range.split('_')
                    // createFile(getFilePath(cwd, `report-${outFileName}.md`),outPutReport(getJSONByRange(content,startTime,endTime)),false)
                    // 方便观察调用结构,展开如下
                    const outPutPath = getFilePath(cwd, `report-${outFileName}.md`)
                    const json = getJSONByRange(content,startTime,endTime)
                    const data = outPutReport(json)
                    createFile(outPutPath,data,false)
                }
            }
        }
    })
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 范围内的json获取

这个逻辑相对简单:

  1. 先调用getJSON方法将传入的内容转为json对象
    • 其中每一项数据的title为yyyy-mm-dd的日期
  2. 先调用sort方法对数据按时间从小到大排序
  3. 在使用filter方法对数据按照传入的起止时间进行过滤筛选
  4. 最后便产生了所需要的结果
function getJSONByRange(fileContent, startTime, endTime) {
    let jsonSchema = getJSON(fileContent)
    // 从小到大排
    jsonSchema = jsonSchema.sort((a, b) => {
        const d1 = new Date(a.title)
        const d2 = new Date(b.title)
        return d1 - d2
    }).filter(v => {
        const d = new Date(v.title)
        const s = new Date(startTime)
        const e = new Date(endTime)
        return d >= s && d <= e
    })
    return jsonSchema
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# JSON转报告内容

期望的报告内容格式如下

# 开始时间 - 结束时间
**总耗时** xxx

## 任务名
>耗时:yyyy
* 事件1
* 事件2
* 事件3

## 任务名
>耗时:yyyy
* 事件1
* 事件2
* 事件3
1
2
3
4
5
6
7
8
9
10
11
12
13
14

结构定下来后,咱们开始对json数据进行操刀

JSON数据结构如下(复习一下)

[
  {
    "title": "2021-08-03",
    "tasks": [
      {
        "title": "任务1",
        "things": [
          {
            "time": "0.2",
            "content": "a组件"
          },
          {
            "time": "0.3",
            "content": "b组件"
          }
        ]
      },
    ]
  },
] 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

首先使用一个数组存放每一行的数据的结果(最终md的每一行)

const res = []

// 记录总耗时
let sumTime = 0
1
2
3
4

开始结束时间分别为json对象的第一项和最后一项的title

const startDate = jsonSchema[0].title
const endDate = jsonSchema[jsonSchema.length-1].title
// 时间
res.push(`# ${startDate} 至 ${endDate}`)
1
2
3
4

确定时间之后,就是任务的归类

后面大部分操作都是使用Array.prototype.reduce,不熟悉的同学可以MDN查询一下

先将所有任务收进同一个数组里:

  • 遍历然后用concat链接这些数组
// 过滤出所有的tasks
const allTasks = jsonSchema.reduce((pre,current)=>{
    return pre.concat(current.tasks)
},[])
1
2
3
4

合并相同任务(task)的事务(things)

合并前

[
  {
    "title": "任务1",
    "things": [
      {
        "time": "0.2",
        "content": "a组件"
      },
    ]
  },
    {
    "title": "任务1",
    "things": [
      {
        "time": "0.3",
        "content": "b组件"
      }
    ]
  },
]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

合并后

[
  {
    "title": "任务1",
    "things": [
      {
        "time": "0.2",
        "content": "a组件"
      },
      {
        "time": "0.3",
        "content": "b组件"
      }
    ]
  }
]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

确定好前后的结构后,逻辑代码就容易书写了:

  • 如果pre为空数组则直接存入
  • 遍历已经存入的内容,判断是否存在相同的任务
    • 不存在,则加入pre
    • 存在,则将其things加入pre.things
// 合并相同的任务
const tasks = allTasks.reduce((pre,current)=>{
    if(pre.length===0){
        pre.push(current)
        return pre
    }
    let sameTask = pre.find(v=>v.title===current.title)
    if(!sameTask){
        pre.push(current)
        return pre
    }
    sameTask.things.push(...current.things)
    return pre
},[])
1
2
3
4
5
6
7
8
9
10
11
12
13
14

结构整理完毕,接着就是内容的生成了:

  • 使用for...of 遍历每一个任务
  • 内部使用Array.prototype.map遍历事务
    • 遍历的同时将任务时间计算出来
  • 一个任务遍历完,先添加任务耗时,再添加事务列表
  • 最后,将所有任务使用的总时间利用数组的splice方法,将其插入结果第二项

到此,生成范围报告的逻辑就完成了

for (const taskItem of tasks) {
    res.push('')
    res.push(`## ${taskItem.title}`)
    let taskTime = 0
    let things = taskItem.things.map(thing=>{
        const {time,content} = thing
        taskTime += (+time)
        return `* ${content}`
    })
    res.push(`>耗时:${taskTime.toFixed(2)}`)
    res.push(...things)
    sumTime += taskTime
}
res.splice(1,0,`**总耗时** ${sumTime.toFixed(2)}`)
1
2
3
4
5
6
7
8
9
10
11
12
13
14

本部分的完整代码地址 (opens new window)

# 其它

由于每天空闲时间有限,本文就先到这

如果读者还感觉意犹未尽,敬请期待后续更新,或先关注一下仓库 (opens new window)

欢迎评论区提需求,交流探讨

本系列会不断的更新迭代,直至产品初代完成

  • 仓库地址 (opens new window)
Edit this page (opens new window)
Last Updated: 2022/5/15 12:46:34