feat: 添加待办完成状态的支持

This commit is contained in:
kuaifan 2025-08-01 12:26:58 +08:00
parent e792ab7b4d
commit 5fb1bd4175
5 changed files with 55 additions and 28 deletions

View File

@ -545,6 +545,7 @@ class DialogController extends AbstractController
// //
if ($list->isNotEmpty()) { if ($list->isNotEmpty()) {
$list->transform(function (WebSocketDialogMsg $item) { $list->transform(function (WebSocketDialogMsg $item) {
$item->todo_done = $item->isTodoDone();
$item->next_id = 0; $item->next_id = 0;
$item->prev_id = 0; $item->prev_id = 0;
return $item; return $item;
@ -2387,6 +2388,7 @@ class DialogController extends AbstractController
$msg->webSocketDialog?->pushMsg('update', [ $msg->webSocketDialog?->pushMsg('update', [
'id' => $msg->id, 'id' => $msg->id,
'todo' => $msg->todo, 'todo' => $msg->todo,
'todo_done' => $msg->isTodoDone(true),
'dialog_id' => $msg->dialog_id, 'dialog_id' => $msg->dialog_id,
]); ]);
} }

View File

@ -2,6 +2,7 @@
namespace App\Models; namespace App\Models;
use Cache;
use Carbon\Carbon; use Carbon\Carbon;
use App\Module\Base; use App\Module\Base;
use App\Module\Doo; use App\Module\Doo;
@ -315,6 +316,24 @@ class WebSocketDialogMsg extends AbstractModel
return Base::retSuccess('success', $resData); return Base::retSuccess('success', $resData);
} }
/**
* 是否完成所有待办
* @param bool $noCache 是否禁止缓存
* @return int 1=已完成 0=未完成
*/
public function isTodoDone(?bool $noCache = false): int
{
if ($noCache) {
Cache::forget('todo_done_' . $this->id);
}
if ($this->todo <= 0) {
return 1;
}
return (int) Cache::remember('todo_done_' . $this->id, Carbon::now()->addDays(), function () {
return WebSocketDialogMsgTodo::whereMsgId($this->id)->whereDoneAt(null)->exists() ? 0 : 1;
});
}
/** /**
* 标注、取消标注 * 标注、取消标注
* @param int $sender 标注的会员ID * @param int $sender 标注的会员ID
@ -367,23 +386,15 @@ class WebSocketDialogMsg extends AbstractModel
if (in_array($this->type, ['tag', 'todo', 'notice'])) { if (in_array($this->type, ['tag', 'todo', 'notice'])) {
return Base::retError('此消息不支持设待办'); return Base::retError('此消息不支持设待办');
} }
$dialog = WebSocketDialog::find($this->dialog_id);
$current = WebSocketDialogMsgTodo::whereMsgId($this->id)->pluck('userid')->toArray(); $current = WebSocketDialogMsgTodo::whereMsgId($this->id)->pluck('userid')->toArray();
$cancel = array_diff($current, $userids); $cancel = array_diff($current, $userids);
$setup = array_diff($userids, $current); $setup = array_diff($userids, $current);
// //
$this->todo = $setup || count($current) > count($cancel) ? $sender : 0; $this->todo = $setup || count($current) > count($cancel) ? $sender : 0;
$this->save(); $this->save();
$upData = [
'id' => $this->id,
'todo' => $this->todo,
'dialog_id' => $this->dialog_id,
];
$dialog = WebSocketDialog::find($this->dialog_id);
// //
$retData = [ $addData = [];
'add' => [],
'update' => $upData
];
if ($cancel) { if ($cancel) {
$res = self::sendMsg(null, $this->dialog_id, 'todo', [ $res = self::sendMsg(null, $this->dialog_id, 'todo', [
'action' => 'remove', 'action' => 'remove',
@ -395,7 +406,7 @@ class WebSocketDialogMsg extends AbstractModel
] ]
], $sender); ], $sender);
if (Base::isSuccess($res)) { if (Base::isSuccess($res)) {
$retData['add'][] = $res['data']; $addData[] = $res['data'];
WebSocketDialogMsgTodo::whereMsgId($this->id)->whereIn('userid', $cancel)->delete(); WebSocketDialogMsgTodo::whereMsgId($this->id)->whereIn('userid', $cancel)->delete();
} }
} }
@ -410,7 +421,7 @@ class WebSocketDialogMsg extends AbstractModel
] ]
], $sender); ], $sender);
if (Base::isSuccess($res)) { if (Base::isSuccess($res)) {
$retData['add'][] = $res['data']; $addData[] = $res['data'];
$useridList = $dialog->dialogUser->pluck('userid')->toArray(); $useridList = $dialog->dialogUser->pluck('userid')->toArray();
foreach ($setup as $userid) { foreach ($setup as $userid) {
if (!in_array($userid, $useridList)) { if (!in_array($userid, $useridList)) {
@ -425,8 +436,18 @@ class WebSocketDialogMsg extends AbstractModel
} }
} }
// //
$upData = [
'id' => $this->id,
'todo' => $this->todo,
'todo_done' => $this->isTodoDone(true),
'dialog_id' => $this->dialog_id,
];
$dialog->pushMsg('update', $upData); $dialog->pushMsg('update', $upData);
return Base::retSuccess($this->todo ? '设置成功' : '取消成功', $retData); //
return Base::retSuccess($this->todo ? '设置成功' : '取消成功', [
'add' => $addData,
'update' => $upData,
]);
} }
/** /**
@ -1337,7 +1358,6 @@ class WebSocketDialogMsg extends AbstractModel
}); });
} }
/** /**
* 将被@的人加入群 * 将被@的人加入群
* @param WebSocketDialog $dialog 对话 * @param WebSocketDialog $dialog 对话

View File

@ -14,15 +14,17 @@
"{{$A.getMsgSimpleDesc(source.msg.data)}}" "{{$A.getMsgSimpleDesc(source.msg.data)}}"
</div> </div>
<div v-else-if="source.type === 'todo'" class="dialog-todo" @click="onViewTodo"> <div v-else-if="source.type === 'todo'" class="dialog-todo" @click="onViewTodo">
<div class="todo-user"><UserAvatar :userid="source.userid" :show-name="true" :show-icon="false"/></div> <div class="no-dark-content">
{{$L(source.msg.action === 'remove' ? '取消待办' : (source.msg.action === 'done' ? '完成' : '设待办'))}} <div class="todo-user"><UserAvatar :userid="source.userid" :show-name="true" :show-icon="false"/></div>
"{{$A.getMsgSimpleDesc(source.msg.data)}}" {{$L(source.msg.action === 'remove' ? '取消待办' : (source.msg.action === 'done' ? '完成' : '设待办'))}}
<div v-if="formatTodoUser(source.msg.data).length > 0" class="todo-users"> "{{$A.getMsgSimpleDesc(source.msg.data)}}"
<span>{{$L('给')}}</span> <div v-if="formatTodoUser(source.msg.data).length > 0" class="todo-users">
<template v-for="(item, index) in formatTodoUser(source.msg.data)"> <span>{{$L('给')}}</span>
<div v-if="index < 3" class="todo-user"><UserAvatar :userid="item" :show-name="true" :show-icon="false"/></div> <template v-for="(item, index) in formatTodoUser(source.msg.data)">
<div v-else-if="index == 3" class="todo-user">+{{formatTodoUser(source.msg.data).length - 3}}</div> <div v-if="index < 3" class="todo-user"><UserAvatar :userid="item" :show-name="true" :show-icon="false"/></div>
</template> <div v-else-if="index == 3" class="todo-user">+{{formatTodoUser(source.msg.data).length - 3}}</div>
</template>
</div>
</div> </div>
</div> </div>
<div v-else-if="source.type === 'notice'" class="dialog-notice"> <div v-else-if="source.type === 'notice'" class="dialog-notice">

View File

@ -80,7 +80,7 @@
<i class="taskfont">&#xe61e;</i> <i class="taskfont">&#xe61e;</i>
</div> </div>
<!--待办--> <!--待办-->
<div v-if="msgData.todo" class="todo" @click="openTodo"> <div v-if="msgData.todo" class="todo" :class="{'todo_done': msgData.todo_done}" @click="openTodo">
<EPopover <EPopover
v-model="todoShow" v-model="todoShow"
ref="todo" ref="todo"
@ -361,14 +361,14 @@ export default {
contentClass() { contentClass() {
const {type, msg} = this.msgData; const {type, msg} = this.msgData;
const classArray = []; const classArray = [];
if (this.operateEnter || this.pointerMouse) { if (this.operateEnter || this.pointerMouse) {
classArray.push('user-select-auto') classArray.push('user-select-auto')
} }
if (type === 'text' && msg?.text) { if (type === 'text' && msg?.text) {
const text = msg.text; const text = msg.text;
if (REGEX_CACHE.emoticon.test(text)) { if (REGEX_CACHE.emoticon.test(text)) {
classArray.push('an-emoticon') classArray.push('an-emoticon')
} else if (REGEX_CACHE.threeEmoji.test(text)) { } else if (REGEX_CACHE.threeEmoji.test(text)) {
@ -379,7 +379,7 @@ export default {
classArray.push('an-emoji') classArray.push('an-emoji')
} }
} }
return classArray; return classArray;
} }
}, },

View File

@ -1668,6 +1668,9 @@
.todo { .todo {
position: relative; position: relative;
cursor: pointer; cursor: pointer;
&.todo_done {
color: $primary-color;
}
.common-loading { .common-loading {
margin: 0 3px 0 0; margin: 0 3px 0 0;
} }