个人项目的一些记录4 - 聊天式日记模块

163 阅读5分钟

日记模块整体要实现的效果:

日记问题部分

后端

  • 1. 添加日记问题 11/19
  • 2. 删除日记问题 11/19
  • 3. 列出日记问题 11/19
  • 4. 日记列出添加按创建顺序排序 11/19

前端

  • 1. 添加日记问题 11/19
  • 2. 删除日记问题 11/19
  • 3. 修改日记问题 11/19

日记聊天窗口部分

前端

  • 1. 前端聊天对话的显示重新整理思路 11/19
  • 思路:用一个dialogs对象来存储用户和电脑的对话。基本长这样。页面mounted之后先去获取用户问题,然后开始生成对话。
let dialogs = [
    {
        fromComputer: true, // 代表信息是来自电脑,会被渲染到对话框左边
        content: 'hello'
    },

    {
        content: 'hi!'
    }
]

(先不考虑数据库存储)

设置一个stage数据用来记录当前对话的阶段。每次生成的对话放入数组dialogs。

  • stage为-1代表对话正要开始。每次用户回复完信息后stage+1。
  • stage为-1时,如果发现用户没有日记问题, 则生成电脑对话“请先编辑好问题”。如果有问题, 则生成对话“今天是xxxx(日期),请输入并发送任意内容以开始今天的日记书写”。stage为0时,电脑发送第一个问题....当已没有问题,或者stage变成9时(用户已答完9个问题),电脑提示“今天日记书写完毕”。

这部分关键代码如下:

      mounted() {
        // 获取日记问题
        this.getAllInUseQues()
      },      
       
       //获取日记问题
       async  getAllInUseQues(){
         const res = await DiaryService.listInUseQues(this.user.id)
         if(res.success){
           this.questions = res.content
           // 获取成功后开始生成对话
           this.generateDialog()
         }else{
           this.$toast.error('获取日记问题失败')
         }
       },
        generateDialog(){
           let msg = ''
           if(this.currentDialogStage === -1){ // 尚未开始今日对话
               // 没有问题时提示后return
               if(this.questions.length === 0){
                 msg='暂时还没有日记问题,请先点击编辑问题按钮添加问题'
                 this.addDialog(msg,true)
                 this.disableUserInput()
                 return
               }
               msg = `请输入任意内容并发送以开始今天(${this.dateToday})的日记书写。当日日记完成前请不要关闭或切换页面。`
               this.addDialog(msg,true)
               this.enableUserInput()
           }
           else {
             // 显示机器正在输入的动画效果,然后发送问题
             this.showLoading()
             // 9个问题还未结束并且还有剩余问题时继续对话
             if(this.questions[this.currentDialogStage] && this.currentDialogStage < 9){ 
               msg = this.questions[this.currentDialogStage].description
            }else{
              // 显示书写完毕
              msg = '今日日记已书写完毕'
              this.todayCompleted = true 
            }
            // 给电脑端的对话一些延时,显得更自然一点
            setTimeout(() => this.showComputerReply(msg)
             ,300)
           }
         },
         
         // 将电脑端对话加入到dialogs中,因为前面已经添加了一个content为空的表示loading状态的对象
         // 所以这里需要改变前一个数组元素的内容
         showComputerReply(msg){
           this.dialogs[this.dialogs.length-1] = {
                  fromComputer: true,
                  content: msg,
                  isLoadingMsg: false
                }
            this.enableUserInput()
         },
         
         // 显示电脑端正在loading的效果
         showLoading(){
           this.addDialog('',true,true)
         },

          addDialog(content, fromComputer,isLoadingMsg){ // isLoadingMsg表示是否是电脑端正在载入的效果显示
             this.dialogs.push({
               fromComputer,
               content,
               isLoadingMsg
             })
             // 在对话更新并渲染后将滚动条滑至底端
             this.$nextTick(() => {
                this.scrollToEnd()
             })
         },

关于loading的效果显示,loading由三个span组成,分别为其设置延时动画效果

    .loading__dot
      display: inline-block
      width: .3rem
      height: .3rem
      border-radius: 50%
      background: #5D5D5D
      animation: 2s blink infinite
      &--1
        animation-delay: 500ms
        margin-left: 10px
      &--2
        animation-delay: 1000ms
      &--3
        margin-right: 10px
        
    @keyframes blink
      50%
        background: transparent
  • 2. 实现后端存储。 用一个answer表才存储用户的回答、用户id、问题id等。用户回顾当日日记时读取answer表。

存储数据的时机我觉得有两种选择:

  • (1)用户每发送一条回答就在后端存储,这样的好处是:即便用户当天日记问题没全部答完,他依然能回顾当天答过的部分。而且如果用户中途出现问题未能全部答完,也不会导致用户需要全部重答。
  • (2)直到用户回答完所有问题,数据才传输到后端。这样的好处是:api发送请求少,而且代码复杂度更低。但是缺点很明显,假设用户只回答了一半,数据不会被保存到数据库。

最终还是决定使用第二种,但是会提示用户:直到提示日记书写完毕,日记才会被保存到服务器,中途不要切换网页。

另外还需要考虑的一个问题是时间问题。

  • 假设用户11:59分开始写日记,第二天00:08分写完,此时这条日记算是哪一天的? 以应用使用经验来看,它会算做是第二天的。但如果我们用的上面的方法(1),似乎时间上会有些乱。

  • 后台日记时间是按用户本地时间y-m-d存储还是按照毫秒数存储?如果按照毫秒数存储,假设用户在11:59分完成当天日记,又在12:02分完成第二天日记,在这种情况下,在某些时区,两者似乎会被归为一天,会导致某一天会出现多份日记。但另一方面,我计划是在一开始就提示用户『开始x月x日的写作』,所以按照本地开始日期来存储更好。

    • 2.1 在前端存储一个diary request相关的数组,在聊天过程中不断更新。
    • 2.2 当用户最后一条回答发送后,机器显示提交数据中,然后才显示今日日记书写完毕
  • 3. 读取某天日记

  • 4. 解决读取日记界面排版错乱问题

  • 5. 日记点击后modal框的处理。

后端

  • 1.思考如何存储日记数据。

  • api传递参数:日期、用户id、 以及一个list,这个list里的数据对应数据表DiaryQuestion

  • 数据表:DiaryQuestion主要字段有:answer内容,question id, date, order(代表用户回答时的顺序)。这样我们可以直接根据date来读取到当天的question和answer,并且按照order排序。(即使question被删除也不影响)

  • 2.写出addDiary对应的controller、 service等。

  • 3.写出readDiary对应的controller、 service等。

  • 4. 删除某一条日记

  • 5. 实现存储数据

  • 记录:这次又遇到了一次 SQL Error: 1064, SQLState: 42000 ,问题出在字段名使用了保留字。