日记模块整体要实现的效果:
日记问题部分
后端
- 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,问题出在字段名使用了保留字。