• 作者:老汪软件技巧
  • 发表时间:2024-10-09 21:01
  • 浏览量:

起因

一直以来都有每天写总结的习惯(错误日志,改的到挺少),每天会记录反思并对反思的内容做了一个分类比如跟任务,情绪有关的反思就划分到**任务管理,情绪管理。**但是记录的日志划分到了每一天,回头重新看的时候太麻烦,希望相同类型的日志能够按照时间汇总到一起方便浏览查看。

思路

使用的笔记软件是语雀提供了对应的开放API, 大致思路是编写日志的时候,按照设定规则去编写,在去获取对应的文章数据解析文章结构生成目标结构的文本数据在调用接口创建新的doc。

具体实现

获取到勾选的所有文章数据,去提取对应的分类信息并转换成对象结构并按标题分组,在对每个分组的反思根据时间和设定的规则排序,最后在合并所有分组,并调用创建doc接口!

async function mergeDoc() {
    
    if (targetDoc.value.filter((item) => !item.children.length).length !== 1 
    || awaitMergeDocs.value.length === 0) {
        return ElMessage.error("文档选择不正确");
    }
    isLoading.value = true;
    // 得到所有的文章数据
    const docs = await getSelectedDocs(toValue(awaitMergeDocs));
   
    // 将文章转换为分类对象 
    const cryObj = docs.flatMap((doc) => matchSummary(doc))
    //根据最早最晚得到标题
    const title =  getMergeTitle(cryObj)
    
    //将分类对象进行分组 
    const cryGroup = generateGroup(cryObj)
    
    //对分类对象进行排序
    Object.keys(cryGroup).forEach((k) => cryGroup[k] = sortTime(cryGroup[k]))
   
    let newDocStr = mergeSummary(cryGroup)
 
    await createSummary(`/repos/${selectBook.value}/docs/${targetDoc.value[0].id}`, {
        slug: targetDoc.value[0].id,
        title: title,
        body: newDocStr
    })
    ElMessage.success("合并成功!")
    isLoading.value = false;
}

文本转换成分类对象

先调用handleRethinks去提取出doc里面的rethink字符串,在调用summaryGroup将rethink下的二级标题以及内容转换为对象。

// 匹配一级标题日期
const matchRegex = {
  matchTime: /^#\s\d{4}年\d{1,2}月.*?日/gm,  //提取时间
}
let docInfo = null;
// 入口函数 返回提取的本篇文章的总结对象, 一般调用至少调用三十次,
export default function main(data) {
  // 保存文章对象
  docInfo = data
  let summaryText =  data.body; //得到md文件格式
  // 表示是单元
  let isStage = data.title.includes("单元");
  const dates = summaryText.match(matchRegex.matchTime) ?? [];
  // 提取的rethinks
  let rethinks = handelRethinks(summaryText,isStage);
  const stageSummary = rethinks.flatMap((item, index) =>
    summaryGroupAdapter(isStage, item, dates[index]));
  return stageSummary;
}
function summaryGroupAdapter(isStage,str,time){
  //!不是总结
  return summaryGroup(str, time, !isStage ? "\n# rethink" : "\n## rethink");
}
//!2. 将总结转换为分类对象
function summaryGroup(str, time, startStr = "\n## rethink") {
  let source = str.replace(startStr, "")
  //!总结的分类就是三级标题
  return source.split("###").filter((item) => item !== "\n" && item).map((item) => {
    let index = item.indexOf("\n");
    return {
      group: item.slice(0, index),//标题结尾有一个换行
      content: item.slice(index).replace(`\n`,`\n   `).replace(`\n\n`,`\n\n   `),
      time:startStr ===  "\n## rethink" ? time : `# ${docInfo.title}`
    }
  })
}
// 截取反思字符串
function handelRethinks(text, isStage) {
  return isStage ? sliceRethinks(text) 
    : sliceRethinks(text, "\n# rethink", "\n# idea");
}
// 截取反思字符串 包括标题
function sliceRethinks(str, startStr = "\n## rethink", endStr = "\n## idea") {
  let results = [];
  let sourceStr = str;
  while (sourceStr.search(startStr) !== -1) {
    let startIndex = sourceStr.search(startStr);
    let endIndex = sourceStr.search(endStr);
    // 
    let rethinks = sourceStr.slice(startIndex, endIndex);
    results.push(rethinks);
    sourceStr = sourceStr.slice(endIndex + endStr.length)
  }
  return results;
}

分组并排序

先对整个数组反思对象进行分组,在调用sortTime进行排序内部先对合法的字符串进行升序,在对不合法的字符串按照一定规则**排序,**最后在合并在一起。

// 阶段总结格式化
let stageFormat = {
    "第一阶段": 0,
    "第二阶段": 1,
    "第三阶段": 2,
    "第四阶段": 3,
    "第五阶段": 4,
    "第六阶段": 5,
    "第七阶段": 6,
    "第八阶段": 7,
    "第九阶段": 8,
    "第十阶段": 9,
    "第十一阶段": 10,
    "第十二阶段": 11,
    "第十三阶段": 12,
    "第十四阶段": 13,
    "第十五阶段": 14
}
// 对数据进行分组
export function generateGroup(cates) {
    return cates.reduce((pre, item) => {
        if (pre[item.group]) {
            pre[item.group].push(item)
        } else {
            pre[item.group] = [item]
        }
        return pre;
    }, {})
}
// 定义一个函数来转换日期格式为时间戳
export function convertDateToTimestamp(dateStr) {
    //exec匹配换成match匹配
    const dateParts = dateStr.match(/\d+/g).map(Number);
    return new Date(dateParts[0], dateParts[1] - 1, dateParts[2]).getTime();
}
// 针对数据排序的工具函数
export function sortTime(cgyData) {
    let verifyDate = /^#\s\d{4}年\d{1,2}月\d{1,2}日/gm
    let correctFormatData = cgyData.filter((cry) => cry.time.search(verifyDate) !== -1);
    let unCorrectFormatData = cgyData.filter((cry) => cry.time.search(verifyDate) === -1);
    // 按照时间进行排序
    correctFormatData.sort((a, b) => {
        let aTimeStr = extractTimeStr(a.time);
        let bTimeStr = extractTimeStr(b.time);
        return convertDateToTimestamp(aTimeStr) - convertDateToTimestamp(bTimeStr)
    })
    // 处理不规范的排序
    unCorrectFormatData = sortUnCorrectFormat(unCorrectFormatData)
    return correctFormatData.concat(unCorrectFormatData)
}
// 处理不规范格式
function sortUnCorrectFormat(cryList) {
    let newArr = new Array(cryList.length).fill(0);
    let staged = [] //暂存标题不合法数据
    cryList.forEach((cry) => {
        let time = cry.time.slice(-4);
        let stageTitle = stageFormat[time];
        if (stageTitle!== undefined) {
            newArr[stageTitle] = cry;
        } else {
            staged.push(cry);
        }
    })
    return newArr.filter((item) => item !== 0).concat(staged)
}
function sortArrayByTime(cgyData) {
//! 去掉全局和多行匹配
    let verifyDate = /^#\s\d{4}年\d{1,2}月\d{1,2}日/
    let correctFormatData = cgyData.filter((cry) => cry.time.search(verifyDate) !== -1);
    correctFormatData.sort((a, b) => {
        //!抽取复用代码
        let aTimeStr =  extractTimeStr(a.time);
        let bTimeStr =  extractTimeStr(b.time);
        return convertDateToTimestamp(aTimeStr) - convertDateToTimestamp(bTimeStr)
    });
    return correctFormatData;
}
//!抽取的单行代码
function extractTimeStr(timeStr) {
    return timeStr.split(" ").pop();
}
// 得到文章的标题
export function getMergeTitle(arr) {
    let correctFormatData = sortArrayByTime(arr)
    let firstElm = correctFormatData[0];
    let lastElm = correctFormatData[correctFormatData.length - 1];
    if (correctFormatData.length === 1) {  //只有一个值
        return extractTimeStr(firstElm.time)    
    }
    return `${extractTimeStr(firstElm.time)} - ${extractTimeStr(lastElm.time)}`;
}

合并对应文档

最后根据将排序后的数据合并在一起,得到**汇总字符串,**根据合并后端字符串创建doc。

// 合并字符串
export function mergeSummary(groupObj) {
    let summary = ""
    Object.keys(groupObj).forEach((key) => {
        let sayCate = ""
        sayCate = groupObj[key].map((item) => `#${item.time}${item.content}`).join("")
        summary += `# ${key}\n${sayCate}`; //设置上key
    })
    return summary
}

结果

在实现了对应的ui界面逻辑(具体代码),并托管到netlify上,不得不说netlify真的强大还支持代理。

总结

拆分代码真的很重要,刚开始不注意写成一坨,后面具体拆分了一下函数以及组件。无论是扩展性,还是可读性都提高了很多!