perf: 支持修改消息待办

This commit is contained in:
kuaifan 2024-05-11 10:45:31 +09:00
parent 80fe978454
commit 2bda6bf668
6 changed files with 169 additions and 74 deletions

View File

@ -1765,7 +1765,9 @@ class DialogController extends AbstractController
* @apiParam {String} type 设待办对象
* - all: 会话全部成员(默认)
* - user: 会话指定成员
* @apiParam {Array} userids 会员ID组type=user有效格式: [userid1, userid2, userid3]
* @apiParam {Array} userids 会员ID组
* - type=user 有效,格式: [userid1, userid2, userid3]
* - 可通过 type=user userids:[] 一起使用来清除所有人的待办
*
* @apiSuccess {Number} ret 返回状态码1正确、0错误
* @apiSuccess {String} msg 返回信息(错误描述)
@ -1773,26 +1775,24 @@ class DialogController extends AbstractController
*/
public function msg__todo()
{
Base::checkClientVersion('0.37.18');
$user = User::auth();
//
$msg_id = intval(Request::input("msg_id"));
$type = trim(Request::input("type", "all"));
$userids = Request::input('userids');
//
if ($type === 'user') {
if (empty($userids)) {
return Base::retError("选择指定成员");
}
} else {
$userids = [];
}
//
$msg = WebSocketDialogMsg::whereId($msg_id)->first();
if (empty($msg)) {
return Base::retError("消息不存在或已被删除");
}
WebSocketDialog::checkDialog($msg->dialog_id);
$dialog = WebSocketDialog::checkDialog($msg->dialog_id);
//
if ($type === 'all') {
$userids = $dialog->dialogUser->pluck('userid')->toArray();
} else {
$userids = is_array($userids) ? $userids : [];
}
return $msg->toggleTodoMsg($user->userid, $userids);
}

View File

@ -320,41 +320,54 @@ class WebSocketDialogMsg extends AbstractModel
if (in_array($this->type, ['tag', 'todo', 'notice'])) {
return Base::retError('此消息不支持设待办');
}
if ($this->todo && $this->todo != $sender) {
return Base::retError('仅支持设此待办人员【' . User::userid2nickname($this->todo) . '】取消');
}
$before = $this->todo;
$this->todo = $before ? 0 : $sender;
$current = WebSocketDialogMsgTodo::whereMsgId($this->id)->pluck('userid')->toArray();
$cancel = array_diff($current, $userids);
$setup = array_diff($userids, $current);
//
$this->todo = $setup || count($current) > count($cancel) ? $sender : 0;
$this->save();
$resData = [
$upData = [
'id' => $this->id,
'todo' => $this->todo,
'dialog_id' => $this->dialog_id,
];
$dialog = WebSocketDialog::find($this->dialog_id);
$dialog->pushMsg('update', $upData);
//
$data = [
'update' => $resData
$retData = [
'add' => [],
'update' => $upData
];
$res = self::sendMsg(null, $this->dialog_id, 'todo', [
'action' => $this->todo ? 'add' : 'remove',
'data' => [
'id' => $this->id,
'type' => $this->type,
'msg' => $this->quoteTextMsg(),
'userids' => implode(",", $userids),
]
], $sender);
if (Base::isSuccess($res)) {
$data['add'] = $res['data'];
$dialog = WebSocketDialog::find($this->dialog_id);
$dialog->pushMsg('update', array_merge($resData, ['dialog_id' => $this->dialog_id]));
//
if ($this->todo) {
if ($cancel) {
$res = self::sendMsg(null, $this->dialog_id, 'todo', [
'action' => 'remove',
'data' => [
'id' => $this->id,
'type' => $this->type,
'msg' => $this->quoteTextMsg(),
'userids' => implode(",", $cancel),
]
], $sender);
if (Base::isSuccess($res)) {
$retData['add'][] = $res['data'];
WebSocketDialogMsgTodo::whereMsgId($this->id)->whereIn('userid', $cancel)->delete();
}
}
if ($setup) {
$res = self::sendMsg(null, $this->dialog_id, 'todo', [
'action' => 'add',
'data' => [
'id' => $this->id,
'type' => $this->type,
'msg' => $this->quoteTextMsg(),
'userids' => implode(",", $setup),
]
], $sender);
if (Base::isSuccess($res)) {
$retData['add'][] = $res['data'];
$useridList = $dialog->dialogUser->pluck('userid')->toArray();
foreach ($useridList as $userid) {
if ($userids && !in_array($userid, $userids)) {
continue;
}
if (empty($userid)) {
foreach ($setup as $userid) {
if (!in_array($userid, $useridList)) {
continue;
}
WebSocketDialogMsgTodo::createInstance([
@ -363,15 +376,10 @@ class WebSocketDialogMsg extends AbstractModel
'userid' => $userid,
])->saveOrIgnore();
}
} else {
WebSocketDialogMsgTodo::whereMsgId($this->id)->delete();
}
} else {
$this->todo = $before;
$this->save();
}
//
return Base::retSuccess($this->todo ? '设置成功' : '取消成功', $data);
return Base::retSuccess($this->todo ? '设置成功' : '取消成功', $retData);
}
/**

View File

@ -53,6 +53,7 @@
@on-reply-list="onReplyList"
@on-error="onError"
@on-emoji="onEmoji"
@on-other="onOther"
@on-show-emoji-user="onShowEmojiUser"/>
</template>
</div>
@ -258,6 +259,10 @@ export default {
this.dispatch("on-emoji", data)
},
onOther(data) {
this.dispatch("on-other", data)
},
onShowEmojiUser(data) {
this.dispatch("on-show-emoji-user", data)
},

View File

@ -196,7 +196,10 @@
:placement="isRightMsg ? 'bottom-end' : 'bottom-start'">
<div class="read-poptip-content">
<Scrollbar class-name="read">
<div class="read-title"><em>{{ todoDoneList.length }}</em>{{ $L('完成') }}</div>
<div class="read-title">
<em>{{ todoDoneList.length }}</em>
{{ $L('完成') }}
</div>
<ul>
<li v-for="item in todoDoneList">
<UserAvatar :userid="item.userid" :size="26" showName/>
@ -204,7 +207,12 @@
</ul>
</Scrollbar>
<Scrollbar class-name="unread">
<div class="read-title"><em>{{ todoUndoneList.length }}</em>{{ $L('待办') }}</div>
<div class="read-title">
<em>{{ todoUndoneList.length }}</em>
{{ $L('待办') }}
<span class="space"></span>
<Button type="primary" size="small" @click="handleTodoAdd">{{ $L('添加') }}</Button>
</div>
<ul>
<li v-for="item in todoUndoneList">
<UserAvatar :userid="item.userid" :size="26" showName/>
@ -240,7 +248,10 @@
:placement="isRightMsg ? 'bottom-end' : 'bottom-start'">
<div class="read-poptip-content">
<Scrollbar class-name="read">
<div class="read-title"><em>{{ readList.length }}</em>{{ $L('已读') }}</div>
<div class="read-title">
<em>{{ readList.length }}</em>
{{ $L('已读') }}
</div>
<ul>
<li v-for="item in readList">
<UserAvatar :userid="item.userid" :size="26" showName/>
@ -248,7 +259,10 @@
</ul>
</Scrollbar>
<Scrollbar class-name="unread">
<div class="read-title"><em>{{ unreadList.length }}</em>{{ $L('未读') }}</div>
<div class="read-title">
<em>{{ unreadList.length }}</em>
{{ $L('未读') }}
</div>
<ul>
<li v-for="item in unreadList">
<UserAvatar :userid="item.userid" :size="26" showName/>
@ -488,6 +502,17 @@ export default {
});
},
handleTodoAdd() {
this.$refs.todo.doClose();
this.$emit("on-other", {
event: 'todoAdd',
data: {
msg_id: this.msgData.id,
userids: this.todoList.map(({userid}) => userid)
}
})
},
openReadPercentage() {
if (this.percentageLoad > 0) {
return;

View File

@ -200,6 +200,7 @@
@on-reply-list="onReplyList"
@on-error="onError"
@on-emoji="onEmoji"
@on-other="onOther"
@on-show-emoji-user="onShowEmojiUser">
<template #header v-if="!isChildComponent">
<div class="dialog-item head-box">
@ -486,6 +487,7 @@
@on-view-file="onViewFile"
@on-down-file="onDownFile"
@on-emoji="onEmoji"
@on-other="onOther"
simpleView/>
</Scrollbar>
</div>
@ -554,6 +556,15 @@
<Button type="primary" :loading="todoSettingLoad > 0" @click="onTodo('submit')">{{$L('确定')}}</Button>
</div>
</Modal>
<UserSelect
v-if="todoSpecifyShow"
ref="todoSpecifySelect"
v-model="todoSpecifyData.userids"
:dialog-id="dialogId"
:title="$L('选择指定成员')"
module
border
:before-submit="onTodoSpecify"/>
<!--群设置-->
<DrawerOverlay
@ -629,6 +640,7 @@
@on-view-file="onViewFile"
@on-down-file="onDownFile"
@on-emoji="onEmoji"
@on-other="onOther"
simpleView/>
<Button class="original-button" icon="md-exit" type="text" :loading="todoViewPosLoad" @click="onPosTodo">{{ $L("回到原文") }}</Button>
</template>
@ -806,6 +818,11 @@ export default {
userids: [],
quick_value: [],
},
todoSpecifyShow: false,
todoSpecifyData: {
type: 'user',
userids: [],
},
todoViewLoad: false,
todoViewPosLoad: false,
@ -3395,6 +3412,19 @@ export default {
this.respondShow = true
},
onOther({event, data}) {
if (this.operateVisible) {
return
}
if (event === 'todoAdd') {
this.todoSpecifyData = Object.assign(this.todoSpecifyData, data)
this.todoSpecifyShow = true
this.$nextTick(_ => {
this.$refs.todoSpecifySelect.onSelection()
})
}
},
onTag() {
if (this.operateVisible) {
return
@ -3460,45 +3490,61 @@ export default {
this.todoSettingLoad--
})
} else {
const quickList = {}
quickList[this.userId] = this.userId
const userid = this.dialogData.dialog_user?.userid
if (userid && userid != this.userId && !this.dialogData.bot) {
quickList[userid] = userid
}
if (this.operateItem.type === 'text') {
const atReg = /<span class="mention user" data-id="(\d+)">([^<]+)<\/span>/g
const atList = this.operateItem.msg.text.match(atReg)
if (atList) {
atList.forEach(item => {
const userid = parseInt(item.replace(atReg, '$1'))
if (userid && userid != this.userId) {
quickList[userid] = userid
}
})
}
}
this.todoSettingData = {
type: 'all',
userids: [],
msg_id: this.operateItem.id,
quick_value: [],
quick_list: Object.values(quickList),
}
if (this.operateItem.todo) {
$A.modalConfirm({
content: "你确定取消待办吗?",
cancelText: '取消',
okText: '确定',
loading: true,
onOk: () => this.onTodoSubmit(this.todoSettingData)
onOk: () => this.onTodoSubmit({
type: 'user',
userids: [],
msg_id: this.operateItem.id,
})
});
} else {
const quickList = {}
quickList[this.userId] = this.userId
const userid = this.dialogData.dialog_user?.userid
if (userid && userid != this.userId && !this.dialogData.bot) {
quickList[userid] = userid
}
if (this.operateItem.type === 'text') {
const atReg = /<span class="mention user" data-id="(\d+)">([^<]+)<\/span>/g
const atList = this.operateItem.msg.text.match(atReg)
if (atList) {
atList.forEach(item => {
const userid = parseInt(item.replace(atReg, '$1'))
if (userid && userid != this.userId) {
quickList[userid] = userid
}
})
}
}
this.todoSettingData = {
type: 'all',
userids: [],
msg_id: this.operateItem.id,
quick_value: [],
quick_list: Object.values(quickList),
}
this.todoSettingShow = true
}
}
},
onTodoSpecify() {
return new Promise((resolve, reject) => {
this.onTodoSubmit(this.todoSpecifyData).then(msg => {
$A.messageSuccess(msg)
resolve()
}).catch(e => {
$A.messageError(e)
reject()
})
});
},
onTodoSubmit(data) {
return new Promise((resolve, reject) => {
this.$store.dispatch("setLoad", {
@ -3506,6 +3552,7 @@ export default {
delay: 600
})
this.$store.dispatch("call", {
method: 'post',
url: 'dialog/msg/todo',
data,
}).then(({data, msg}) => {

View File

@ -2068,12 +2068,22 @@ body:not(.window-touch) {
top: 0;
z-index: 10;
background: #ffffff;
display: flex;
align-items: center;
> em {
font-size: 18px;
font-weight: 600;
font-style: normal;
padding-right: 6px;
}
> span.space {
flex: 1;
height: 1px;
}
> button {
transform: scale(0.96);
transform-origin: right center;
}
}
ul > li {