perf: 支持查看待办完成情况

This commit is contained in:
kuaifan 2022-07-07 20:26:24 +08:00
parent 8ca6b53224
commit 6e186e9186
4 changed files with 144 additions and 25 deletions

View File

@ -1042,6 +1042,36 @@ class DialogController extends AbstractController
return $msg->toggleTodoMsg($user->userid); return $msg->toggleTodoMsg($user->userid);
} }
/**
* @api {get} api/dialog/msg/todolist 14. 获取消息待办情况
*
* @apiDescription 需要token身份
* @apiVersion 1.0.0
* @apiGroup dialog
* @apiName msg__todolist
*
* @apiParam {Number} msg_id 消息ID
*
* @apiSuccess {Number} ret 返回状态码1正确、0错误
* @apiSuccess {String} msg 返回信息(错误描述)
* @apiSuccess {Object} data 返回数据
*/
public function msg__todolist()
{
User::auth();
//
$msg_id = intval(Request::input('msg_id'));
//
$msg = WebSocketDialogMsg::whereId($msg_id)->first();
if (empty($msg)) {
return Base::retError("消息不存在或已被删除");
}
WebSocketDialog::checkDialog($msg->dialog_id);
//
$todo = WebSocketDialogMsgTodo::whereMsgId($msg_id)->get();
return Base::retSuccess('success', $todo ?: []);
}
/** /**
* @api {get} api/dialog/msg/done 23. 完成待办 * @api {get} api/dialog/msg/done 23. 完成待办
* *

View File

@ -24,6 +24,7 @@
:hide-reply="hideReply" :hide-reply="hideReply"
:operate-visible="operateVisible" :operate-visible="operateVisible"
:operate-action="operateVisible && source.id === operateItem.id" :operate-action="operateVisible && source.id === operateItem.id"
:is-right-msg="isRightMsg"
@on-longpress="onLongpress" @on-longpress="onLongpress"
@on-view-reply="onViewReply" @on-view-reply="onViewReply"
@on-view-text="onViewText" @on-view-text="onViewText"
@ -88,10 +89,14 @@ export default {
computed: { computed: {
...mapState(['userId']), ...mapState(['userId']),
isRightMsg() {
return !this.isReply && this.source.userid == this.userId
},
classArray() { classArray() {
return { return {
'dialog-item': true, 'dialog-item': true,
'self': !this.isReply && this.source.userid == this.userId, 'self': this.isRightMsg,
} }
} }
}, },

View File

@ -92,8 +92,30 @@
<i class="taskfont">&#xe61e;</i> <i class="taskfont">&#xe61e;</i>
</div> </div>
<!--待办--> <!--待办-->
<div v-if="msgData.todo" class="todo"> <div v-if="msgData.todo" class="todo" @click="openTodo">
<i class="taskfont">&#xe7b7;</i> <EPopover
v-model="todoShow"
ref="todo"
popper-class="dialog-wrapper-read-poptip"
:placement="isRightMsg ? 'bottom-end' : 'bottom-start'">
<div class="read-poptip-content">
<ul class="read scrollbar-overlay">
<li class="read-title"><em>{{ todoDoneList.length }}</em>{{ $L('完成') }}</li>
<li v-for="item in todoDoneList">
<UserAvatar :userid="item.userid" :size="26" showName tooltipDisabled/>
</li>
</ul>
<ul class="unread scrollbar-overlay">
<li class="read-title"><em>{{ todoUndoneList.length }}</em>{{ $L('待办') }}</li>
<li v-for="item in todoUndoneList">
<UserAvatar :userid="item.userid" :size="26" showName tooltipDisabled/>
</li>
</ul>
</div>
<div slot="reference" class="popover-reference"></div>
</EPopover>
<Loading v-if="todoLoad > 0"/>
<i v-else class="taskfont">&#xe7b7;</i>
</div> </div>
<!--编辑--> <!--编辑-->
<div v-if="msgData.modify" class="modify"> <div v-if="msgData.modify" class="modify">
@ -109,27 +131,27 @@
<template v-if="!hidePercentage"> <template v-if="!hidePercentage">
<div v-if="msgData.send > 1 || dialogType === 'group'" class="percent" @click="openReadPercentage"> <div v-if="msgData.send > 1 || dialogType === 'group'" class="percent" @click="openReadPercentage">
<EPopover <EPopover
v-model="popperShow" v-model="percentageShow"
ref="percent" ref="percent"
popper-class="dialog-wrapper-read-poptip" popper-class="dialog-wrapper-read-poptip"
placement="left-end"> :placement="isRightMsg ? 'bottom-end' : 'bottom-start'">
<div class="read-poptip-content"> <div class="read-poptip-content">
<ul class="read scrollbar-overlay"> <ul class="read scrollbar-overlay">
<li class="read-title"><em>{{ readList.length }}</em>{{ $L('已读') }}</li> <li class="read-title"><em>{{ readList.length }}</em>{{ $L('已读') }}</li>
<li v-for="item in readList"> <li v-for="item in readList">
<UserAvatar :userid="item.userid" :size="26" showName/> <UserAvatar :userid="item.userid" :size="26" showName tooltipDisabled/>
</li> </li>
</ul> </ul>
<ul class="unread scrollbar-overlay"> <ul class="unread scrollbar-overlay">
<li class="read-title"><em>{{ unreadList.length }}</em>{{ $L('未读') }}</li> <li class="read-title"><em>{{ unreadList.length }}</em>{{ $L('未读') }}</li>
<li v-for="item in unreadList"> <li v-for="item in unreadList">
<UserAvatar :userid="item.userid" :size="26" showName/> <UserAvatar :userid="item.userid" :size="26" showName tooltipDisabled/>
</li> </li>
</ul> </ul>
</div> </div>
<div slot="reference"></div> <div slot="reference" class="popover-reference"></div>
</EPopover> </EPopover>
<Loading v-if="popperLoad > 0"/> <Loading v-if="percentageLoad > 0"/>
<WCircle v-else :percent="msgData.percentage" :size="14"/> <WCircle v-else :percent="msgData.percentage" :size="14"/>
</div> </div>
<Icon v-else-if="msgData.percentage === 100" class="done" type="md-done-all"/> <Icon v-else-if="msgData.percentage === 100" class="done" type="md-done-all"/>
@ -177,15 +199,24 @@ export default {
type: Boolean, type: Boolean,
default: false default: false
}, },
isRightMsg: {
type: Boolean,
default: false
},
}, },
data() { data() {
return { return {
popperLoad: 0,
popperShow: false,
timeShow: false, timeShow: false,
operateEnter: false, operateEnter: false,
allList: [],
percentageLoad: 0,
percentageShow: false,
percentageList: [],
todoLoad: 0,
todoShow: false,
todoList: [],
} }
}, },
@ -223,11 +254,19 @@ export default {
}, },
readList() { readList() {
return this.allList.filter(({read_at}) => read_at) return this.percentageList.filter(({read_at}) => read_at)
}, },
unreadList() { unreadList() {
return this.allList.filter(({read_at}) => !read_at) return this.percentageList.filter(({read_at}) => !read_at)
},
todoDoneList() {
return this.todoList.filter(({done_at}) => done_at)
},
todoUndoneList() {
return this.todoList.filter(({done_at}) => !done_at)
}, },
headClass() { headClass() {
@ -266,9 +305,7 @@ export default {
operateAction(val) { operateAction(val) {
this.operateEnter = false; this.operateEnter = false;
if (val) { if (val) {
setTimeout(_ => { setTimeout(_ => this.operateEnter = true, 500)
this.operateEnter = true;
}, 500)
} }
} }
}, },
@ -278,28 +315,54 @@ export default {
this.$emit("on-longpress", {event, el, msgData: this.msgData}) this.$emit("on-longpress", {event, el, msgData: this.msgData})
}, },
openTodo() {
if (this.todoLoad > 0) {
return;
}
if (this.todoShow) {
this.todoShow = false;
return;
}
this.todoLoad++;
this.$store.dispatch("call", {
url: 'dialog/msg/todolist',
data: {
msg_id: this.msgData.id,
},
}).then(({data}) => {
this.todoList = data;
}).catch(() => {
this.todoList = [];
}).finally(_ => {
setTimeout(() => {
this.todoLoad--;
this.todoShow = true
}, 100)
});
},
openReadPercentage() { openReadPercentage() {
if (this.popperLoad > 0) { if (this.percentageLoad > 0) {
return; return;
} }
if (this.popperShow) { if (this.percentageShow) {
this.popperShow = false; this.percentageShow = false;
return; return;
} }
this.popperLoad++; this.percentageLoad++;
this.$store.dispatch("call", { this.$store.dispatch("call", {
url: 'dialog/msg/readlist', url: 'dialog/msg/readlist',
data: { data: {
msg_id: this.msgData.id, msg_id: this.msgData.id,
}, },
}).then(({data}) => { }).then(({data}) => {
this.allList = data; this.percentageList = data;
}).catch(() => { }).catch(() => {
this.allList = []; this.percentageList = [];
}).finally(_ => { }).finally(_ => {
setTimeout(() => { setTimeout(() => {
this.popperLoad--; this.percentageLoad--;
this.popperShow = true this.percentageShow = true
}, 100) }, 100)
}); });
}, },

View File

@ -764,6 +764,15 @@
height: 10px; height: 10px;
} }
.popover-reference {
position: absolute;
left: 65%;
bottom: 0;
width: 0;
height: 100%;
pointer-events: none;
}
.tag, .tag,
.todo, .todo,
.reply, .reply,
@ -776,6 +785,17 @@
} }
} }
.todo {
position: relative;
cursor: pointer;
.common-loading {
margin: 0 3px 0 0;
}
> i {
color: $primary-color;
}
}
.reply { .reply {
font-size: 12px; font-size: 12px;
color: $primary-color; color: $primary-color;
@ -802,6 +822,7 @@
display: none; display: none;
margin-left: 4px; margin-left: 4px;
align-items: center; align-items: center;
position: relative;
cursor: pointer; cursor: pointer;
} }
} }