mirror of
https://github.com/kuaifan/dootask.git
synced 2026-02-28 12:50:48 +00:00
feat: 新增标注消息功能
This commit is contained in:
parent
83765c9d2d
commit
500ed3a4d7
@ -851,7 +851,7 @@ class DialogController extends AbstractController
|
||||
* @apiDescription 需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup dialog
|
||||
* @apiName msg__forward
|
||||
* @apiName msg__emoji
|
||||
*
|
||||
* @apiParam {Number} msg_id 消息ID
|
||||
* @apiParam {String} symbol 回复或取消的emoji表情
|
||||
@ -881,6 +881,35 @@ class DialogController extends AbstractController
|
||||
return $msg->emojiMsg($symbol, $user->userid);
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/dialog/msg/tag 18. 标注/取消标注
|
||||
*
|
||||
* @apiDescription 需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup dialog
|
||||
* @apiName msg__tag
|
||||
*
|
||||
* @apiParam {Number} msg_id 消息ID
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
* @apiSuccess {Object} data 返回数据
|
||||
*/
|
||||
public function msg__tag()
|
||||
{
|
||||
$user = 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);
|
||||
//
|
||||
return $msg->toggleTagMsg($user->userid);
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/dialog/top 19. 会话置顶
|
||||
*
|
||||
|
||||
@ -23,6 +23,7 @@ use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
* @property string|null $key 搜索关键词
|
||||
* @property int|null $read 已阅数量
|
||||
* @property int|null $send 发送数量
|
||||
* @property int|null $tag 标注会员ID
|
||||
* @property int|null $reply_num 有多少条回复
|
||||
* @property int|null $reply_id 回复ID
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
@ -47,6 +48,7 @@ use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereReplyId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereReplyNum($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereSend($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereTag($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereType($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereUpdatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereUserid($value)
|
||||
@ -247,6 +249,44 @@ class WebSocketDialogMsg extends AbstractModel
|
||||
return Base::retSuccess('sucess', $resData);
|
||||
}
|
||||
|
||||
/**
|
||||
* 标注、取消标注
|
||||
* @param int $sender 标注的会员ID
|
||||
* @return mixed
|
||||
*/
|
||||
public function toggleTagMsg($sender)
|
||||
{
|
||||
if ($this->type === 'tag') {
|
||||
return Base::retError('此消息不支持标注');
|
||||
}
|
||||
$this->tag = $this->tag ? 0 : $sender;
|
||||
$this->save();
|
||||
$resData = [
|
||||
'id' => $this->id,
|
||||
'tag' => $this->tag,
|
||||
];
|
||||
//
|
||||
$dialog = WebSocketDialog::find($this->dialog_id);
|
||||
$dialog?->pushMsg('update', $resData);
|
||||
//
|
||||
$data = [
|
||||
'update' => $resData
|
||||
];
|
||||
$res = self::sendMsg($this->dialog_id, 0, 'tag', [
|
||||
'action' => $this->tag ? 'add' : 'remove',
|
||||
'data' => [
|
||||
'id' => $this->id,
|
||||
'type' => $this->type,
|
||||
'msg' => $this->msg,
|
||||
]
|
||||
], $sender);
|
||||
if (Base::isSuccess($res)) {
|
||||
$data['add'] = $res['data'];
|
||||
}
|
||||
//
|
||||
return Base::retSuccess('sucess', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转发消息
|
||||
* @param $userids
|
||||
@ -323,22 +363,32 @@ class WebSocketDialogMsg extends AbstractModel
|
||||
/**
|
||||
* 预览消息
|
||||
* @param bool $preserveHtml 保留html格式
|
||||
* @param null|array $data
|
||||
* @return string
|
||||
*/
|
||||
public function previewMsg($preserveHtml = false)
|
||||
public function previewMsg($preserveHtml = false, $data = null)
|
||||
{
|
||||
switch ($this->type) {
|
||||
if ($data === null) {
|
||||
$data = [
|
||||
'type' => $this->type,
|
||||
'msg' => $this->msg,
|
||||
];
|
||||
}
|
||||
switch ($data['type']) {
|
||||
case 'text':
|
||||
return $this->previewTextMsg($this->msg['text'], $preserveHtml);
|
||||
return $this->previewTextMsg($data['msg']['text'], $preserveHtml);
|
||||
case 'record':
|
||||
return "[语音]";
|
||||
case 'meeting':
|
||||
return "[会议] ${$this->msg['name']}";
|
||||
return "[会议] ${$data['msg']['name']}";
|
||||
case 'file':
|
||||
if ($this->msg['type'] == 'img') {
|
||||
if ($data['msg']['type'] == 'img') {
|
||||
return "[图片]";
|
||||
}
|
||||
return "[文件] {$this->msg['name']}";
|
||||
return "[文件] {$data['msg']['name']}";
|
||||
case 'tag':
|
||||
$action = $data['msg']['action'] === 'remove' ? '取消标注' : '标注';
|
||||
return "[{$action}] {$this->previewMsg(false, $data['msg']['data'])}";
|
||||
default:
|
||||
return "[未知的消息]";
|
||||
}
|
||||
|
||||
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddWebSocketDialogMsgsTag extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('web_socket_dialog_msgs', function (Blueprint $table) {
|
||||
if (!Schema::hasColumn('web_socket_dialog_msgs', 'tag')) {
|
||||
$table->bigInteger('tag')->nullable()->default(0)->after('send')->comment('标注会员ID');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('web_socket_dialog_msgs', function (Blueprint $table) {
|
||||
$table->dropColumn("tag");
|
||||
});
|
||||
}
|
||||
}
|
||||
6
resources/assets/js/functions/utils.js
vendored
6
resources/assets/js/functions/utils.js
vendored
@ -1,4 +1,4 @@
|
||||
module.exports = {
|
||||
const assetsFunctionUtils = {
|
||||
/**
|
||||
* 消息格式化处理
|
||||
* @param text
|
||||
@ -95,6 +95,8 @@ module.exports = {
|
||||
return `[${$A.L('图片')}]`
|
||||
}
|
||||
return `[${$A.L('文件')}] ${data.msg.name}`
|
||||
case 'tag':
|
||||
return `[${$A.L(data.msg.action === 'remove' ? '取消标注' : '标注')}] ${assetsFunctionUtils.msgSimpleDesc(data.msg.data)}`
|
||||
default:
|
||||
return `[${$A.L('未知的消息')}]`
|
||||
}
|
||||
@ -135,3 +137,5 @@ module.exports = {
|
||||
}, false);
|
||||
},
|
||||
}
|
||||
|
||||
module.exports = assetsFunctionUtils
|
||||
|
||||
@ -1,27 +1,35 @@
|
||||
<template>
|
||||
<div :class="classArray">
|
||||
<div class="dialog-avatar">
|
||||
<UserAvatar :userid="source.userid" :tooltipDisabled="source.userid == userId" :size="30"/>
|
||||
<div v-if="source.type === 'tag'" class="dialog-tag" @click="onViewTag">
|
||||
<div class="tag-user"><UserAvatar :userid="source.userid" :tooltipDisabled="source.userid == userId" :show-name="true" :show-icon="false"/></div>
|
||||
{{$L(source.msg.action === 'remove' ? '取消标注' : '标注了')}}
|
||||
"{{formatMsgDesc(source.msg.data)}}"
|
||||
</div>
|
||||
<DialogView
|
||||
:msg-data="source"
|
||||
:dialog-type="dialogData.type"
|
||||
:hide-percentage="hidePercentage"
|
||||
:hide-reply="hideReply"
|
||||
:operate-visible="operateVisible"
|
||||
:operate-action="operateVisible && source.id === operateItem.id"
|
||||
@on-longpress="onLongpress"
|
||||
@on-view-reply="onViewReply"
|
||||
@on-view-text="onViewText"
|
||||
@on-view-file="onViewFile"
|
||||
@on-reply-list="onReplyList"
|
||||
@on-emoji="onEmoji"/>
|
||||
<template v-else>
|
||||
<div class="dialog-avatar">
|
||||
<UserAvatar :userid="source.userid" :tooltipDisabled="source.userid == userId" :size="30"/>
|
||||
</div>
|
||||
<DialogView
|
||||
:msg-data="source"
|
||||
:dialog-type="dialogData.type"
|
||||
:hide-percentage="hidePercentage"
|
||||
:hide-reply="hideReply"
|
||||
:operate-visible="operateVisible"
|
||||
:operate-action="operateVisible && source.id === operateItem.id"
|
||||
@on-longpress="onLongpress"
|
||||
@on-view-reply="onViewReply"
|
||||
@on-view-text="onViewText"
|
||||
@on-view-file="onViewFile"
|
||||
@on-reply-list="onReplyList"
|
||||
@on-emoji="onEmoji"/>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapState} from "vuex";
|
||||
import DialogView from "./DialogView";
|
||||
import {msgSimpleDesc} from "../../../functions/utils";
|
||||
|
||||
export default {
|
||||
name: "DialogItem",
|
||||
@ -81,6 +89,17 @@ export default {
|
||||
},
|
||||
|
||||
methods: {
|
||||
formatMsgDesc(data) {
|
||||
return msgSimpleDesc(data)
|
||||
},
|
||||
|
||||
onViewTag() {
|
||||
this.onViewReply({
|
||||
msg_id: this.source.id,
|
||||
reply_id: this.source.msg.data.id
|
||||
})
|
||||
},
|
||||
|
||||
onLongpress(e) {
|
||||
this.dispatch("on-longpress", e)
|
||||
},
|
||||
|
||||
@ -87,6 +87,10 @@
|
||||
<i class="taskfont"></i>
|
||||
{{msgData.reply_num}}条回复
|
||||
</div>
|
||||
<!--标注-->
|
||||
<div v-if="msgData.tag" class="tag">
|
||||
<i class="taskfont"></i>
|
||||
</div>
|
||||
<!--等待/时间/阅读-->
|
||||
<Loading v-if="isLoading"/>
|
||||
<template v-else>
|
||||
|
||||
@ -174,6 +174,10 @@
|
||||
<span>{{ $L('下载') }}</span>
|
||||
</li>
|
||||
</template>
|
||||
<li @click="onOperate('tag')">
|
||||
<i class="taskfont"></i>
|
||||
<span>{{ $L(operateItem.tag ? '取消标注' : '标注') }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</DropdownItem>
|
||||
<DropdownItem name="emoji" class="dropdown-emoji">
|
||||
@ -1202,6 +1206,10 @@ export default {
|
||||
case "emoji":
|
||||
this.onEmoji(value)
|
||||
break;
|
||||
|
||||
case "tag":
|
||||
this.onTag()
|
||||
break;
|
||||
}
|
||||
})
|
||||
},
|
||||
@ -1393,6 +1401,34 @@ export default {
|
||||
}).finally(_ => {
|
||||
this.$store.dispatch("cancelLoad", `msg-${data.msg_id}`)
|
||||
});
|
||||
},
|
||||
|
||||
onTag() {
|
||||
if (this.operateVisible) {
|
||||
return
|
||||
}
|
||||
const data = {
|
||||
msg_id: this.operateItem.id,
|
||||
}
|
||||
//
|
||||
this.$store.dispatch("setLoad", {
|
||||
key: `msg-${data.msg_id}`,
|
||||
delay: 600
|
||||
})
|
||||
this.$store.dispatch("call", {
|
||||
url: 'dialog/msg/tag',
|
||||
data,
|
||||
}).then(({data}) => {
|
||||
this.$store.dispatch("saveDialogMsg", data.update);
|
||||
if (data.add) {
|
||||
this.$store.dispatch("saveDialogMsg", data.add);
|
||||
this.$store.dispatch("updateDialogLastMsg", data.add);
|
||||
}
|
||||
}).catch(({msg}) => {
|
||||
$A.messageError(msg);
|
||||
}).finally(_ => {
|
||||
this.$store.dispatch("cancelLoad", `msg-${data.msg_id}`)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -226,6 +226,20 @@
|
||||
list-style: none;
|
||||
padding-bottom: 16px;
|
||||
|
||||
.dialog-tag {
|
||||
max-width: 80%;
|
||||
margin: 0 auto;
|
||||
padding: 4px 8px;
|
||||
border-radius: 8px;
|
||||
background-color: #efefef;
|
||||
word-wrap: break-word;
|
||||
cursor: pointer;
|
||||
|
||||
.tag-user {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
.dialog-avatar {
|
||||
position: relative;
|
||||
margin-bottom: 20px;
|
||||
@ -678,6 +692,15 @@
|
||||
}
|
||||
}
|
||||
|
||||
.tag {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-right: 6px;
|
||||
> i {
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
.time {
|
||||
color: #bbbbbb;
|
||||
font-size: 12px;
|
||||
@ -1091,7 +1114,13 @@
|
||||
font-size: 20px;
|
||||
}
|
||||
> span {
|
||||
padding: 0 1px;
|
||||
font-size: 12px;
|
||||
max-width: 100%;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user