feat: 新增标注消息功能

This commit is contained in:
kuaifan 2022-06-30 15:56:09 +08:00
parent 83765c9d2d
commit 500ed3a4d7
11 changed files with 228 additions and 23 deletions

View File

@ -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. 会话置顶
*

View File

@ -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 "[未知的消息]";
}

View File

@ -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");
});
}
}

View File

@ -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

View File

@ -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)
},

View File

@ -87,6 +87,10 @@
<i class="taskfont">&#xe6eb;</i>
{{msgData.reply_num}}条回复
</div>
<!--标注-->
<div v-if="msgData.tag" class="tag">
<i class="taskfont">&#xe61e;</i>
</div>
<!--等待/时间/阅读-->
<Loading v-if="isLoading"/>
<template v-else>

View File

@ -174,6 +174,10 @@
<span>{{ $L('下载') }}</span>
</li>
</template>
<li @click="onOperate('tag')">
<i class="taskfont">&#xe61e;</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}`)
});
}
}
}

View File

@ -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;
}
}
}