feat: 【消息】列表增加点击右键置顶该聊天功能

This commit is contained in:
韦荣超 2022-02-17 09:17:19 +08:00
parent ab4fbf0437
commit 04c59041e0
6 changed files with 175 additions and 4 deletions

View File

@ -8,6 +8,7 @@ use App\Models\User;
use App\Models\WebSocketDialog; use App\Models\WebSocketDialog;
use App\Models\WebSocketDialogMsg; use App\Models\WebSocketDialogMsg;
use App\Models\WebSocketDialogMsgRead; use App\Models\WebSocketDialogMsgRead;
use App\Models\WebSocketDialogUser;
use App\Module\Base; use App\Module\Base;
use Carbon\Carbon; use Carbon\Carbon;
use Request; use Request;
@ -39,9 +40,10 @@ class DialogController extends AbstractController
{ {
$user = User::auth(); $user = User::auth();
// //
$list = WebSocketDialog::select(['web_socket_dialogs.*']) $list = WebSocketDialog::select(['web_socket_dialogs.*','u.top'])
->join('web_socket_dialog_users as u', 'web_socket_dialogs.id', '=', 'u.dialog_id') ->join('web_socket_dialog_users as u', 'web_socket_dialogs.id', '=', 'u.dialog_id')
->where('u.userid', $user->userid) ->where('u.userid', $user->userid)
->orderByDesc('u.top')
->orderByDesc('web_socket_dialogs.last_at') ->orderByDesc('web_socket_dialogs.last_at')
->paginate(Base::getPaginate(200, 100)); ->paginate(Base::getPaginate(200, 100));
$list->transform(function (WebSocketDialog $item) use ($user) { $list->transform(function (WebSocketDialog $item) use ($user) {
@ -475,4 +477,36 @@ class DialogController extends AbstractController
$msg->deleteMsg(); $msg->deleteMsg();
return Base::retSuccess("success"); return Base::retSuccess("success");
} }
/**
* @api {get} api/dialog/top 12. 会话置顶
*
* @apiDescription 消息撤回限制24小时内需要token身份
* @apiVersion 1.0.0
* @apiGroup dialog
* @apiName top
*
* @apiParam {Number} dialog_id 会话ID
*
* @apiSuccess {Number} ret 返回状态码1正确、0错误
* @apiSuccess {String} msg 返回信息(错误描述)
* @apiSuccess {Object} data 返回数据
*/
public function top()
{
$user = User::auth();
$dialogId = intval(Request::input('dialog_id'));
$dialogUser = WebSocketDialogUser::whereUserid($user->userid)->whereDialogId($dialogId)->first();
if (!$dialogUser) {
return Base::retError("会话不存在");
}
WebSocketDialogUser::whereUserid($user->userid)
->update([
'top' => 0
]);
$dialogUser->top = 1;
$dialogUser->save();
return Base::retSuccess("success", $dialogId);
}
} }

View File

@ -8,6 +8,7 @@ namespace App\Models;
* @property int $id * @property int $id
* @property int|null $dialog_id 对话ID * @property int|null $dialog_id 对话ID
* @property int|null $userid 会员ID * @property int|null $userid 会员ID
* @property int|null $top 是否置顶0否1是
* @property \Illuminate\Support\Carbon|null $created_at * @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at * @property \Illuminate\Support\Carbon|null $updated_at
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser newModelQuery() * @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser newModelQuery()

View File

@ -0,0 +1,34 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class WebSocketDialogUsersAddTop extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('web_socket_dialog_users', function (Blueprint $table) {
if (!Schema::hasColumn('web_socket_dialog_users', 'top')) {
$table->tinyInteger('top')->nullable()->default(0)->after('userid')->comment('是否置顶0否1是');
}
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('web_socket_dialog_users', function (Blueprint $table) {
$table->dropColumn("top");
});
}
}

View File

@ -1,5 +1,5 @@
{ {
"name": "diagrams.net", "name": "",
"short_name": "Diagrams", "short_name": "Diagrams",
"description": "diagrams.net is a completely free diagram editor", "description": "diagrams.net is a completely free diagram editor",
"icons": [ "icons": [

View File

@ -24,13 +24,14 @@
class="messenger-list overlay-y" class="messenger-list overlay-y"
@on-scroll="listScroll" @on-scroll="listScroll"
static> static>
<ul v-if="tabActive==='dialog'" class="dialog"> <ul v-if="tabActive==='dialog'" class="dialog" ref="dialogWrapper">
<li <li
v-for="(dialog, key) in dialogList" v-for="(dialog, key) in dialogList"
:ref="`dialog_${dialog.id}`" :ref="`dialog_${dialog.id}`"
:key="key" :key="key"
:class="{active: dialog.id == dialogId}" :class="{active: dialog.id == dialogId}"
@click="openDialog(dialog, true)"> @click="openDialog(dialog, true)"
@contextmenu.prevent.stop="handleRightClick($event, dialog)">
<template v-if="dialog.type=='group'"> <template v-if="dialog.type=='group'">
<i v-if="dialog.group_type=='project'" class="taskfont icon-avatar project">&#xe6f9;</i> <i v-if="dialog.group_type=='project'" class="taskfont icon-avatar project">&#xe6f9;</i>
<i v-else-if="dialog.group_type=='task'" class="taskfont icon-avatar task" :class="{completed:$A.dialogCompleted(dialog)}">&#xe6f4;</i> <i v-else-if="dialog.group_type=='task'" class="taskfont icon-avatar task" :class="{completed:$A.dialogCompleted(dialog)}">&#xe6f4;</i>
@ -65,6 +66,22 @@
<li v-if="contactsLoad > 0" class="loading"><Loading/></li> <li v-if="contactsLoad > 0" class="loading"><Loading/></li>
<li v-else-if="!contactsHasMorePages" class="loaded">{{$L('共' + contactsList.length + '位联系人')}}</li> <li v-else-if="!contactsHasMorePages" class="loaded">{{$L('共' + contactsList.length + '位联系人')}}</li>
</ul> </ul>
<div class="top-operate" :style="topOperateStyles">
<Dropdown
trigger="custom"
:visible="topOperateVisible"
transfer-class-name="page-file-dropdown-menu"
@on-clickoutside="handleClickTopOperateOutside"
@on-visible-change="handleVisibleTopOperate"
transfer>
<DropdownMenu slot="list">
<template v-if="topOperateItem.id">
<DropdownItem @click.native="handleTopClick">{{ $L('置顶该聊天') }}
</DropdownItem>
</template>
</DropdownMenu>
</Dropdown>
</div>
</ScrollerY> </ScrollerY>
<div class="messenger-menu"> <div class="messenger-menu">
<Icon @click="tabActive='dialog'" :class="{active:tabActive==='dialog'}" type="ios-chatbubbles" /> <Icon @click="tabActive='dialog'" :class="{active:tabActive==='dialog'}" type="ios-chatbubbles" />
@ -114,6 +131,15 @@ export default {
contactsData: null, contactsData: null,
contactsCurrentPage: 1, contactsCurrentPage: 1,
contactsHasMorePages: false, contactsHasMorePages: false,
topOperateStyles: {
top: 0,
left: 0,
position: 'absolute'
},
topOperateVisible: false,
topOperateItem: {},
} }
}, },
@ -128,6 +154,9 @@ export default {
const {dialogActive, dialogKey} = this; const {dialogActive, dialogKey} = this;
if (dialogActive == '' && dialogKey == '') { if (dialogActive == '' && dialogKey == '') {
return this.cacheDialogs.filter(dialog => this.filterDialog(dialog)).sort((a, b) => { return this.cacheDialogs.filter(dialog => this.filterDialog(dialog)).sort((a, b) => {
if (a.top || b.top) {
return b.top - a.top;
}
return $A.Date(b.last_at) - $A.Date(a.last_at); return $A.Date(b.last_at) - $A.Date(a.last_at);
}); });
} }
@ -407,6 +436,45 @@ export default {
} }
} }
}) })
},
handleRightClick(event, item) {
this.topOperateItem = $A.isJson(item) ? item : {};
if (this.topOperateVisible) {
this.handleClickTopOperateOutside();
}
this.dialogId = this.topOperateItem.id;
this.scrollIntoActive(true);
this.$nextTick(() => {
const dialogWrap = this.$refs.dialogWrapper;
const dialogBounding = dialogWrap.getBoundingClientRect();
this.topOperateStyles = {
left: `${event.clientX - dialogBounding.left}px`,
top: `${event.clientY - dialogBounding.top + 100}px`
};
this.topOperateVisible = true;
})
},
handleClickTopOperateOutside() {
this.topOperateVisible = false;
},
handleVisibleTopOperate(visible) {
if (visible && this.topOperateItem.id) {
this.$set(this.topOperateItem, '_highlight', true);
}
},
handleTopClick() {
this.$store.dispatch("call", {
url: 'dialog/top',
data: {
dialog_id: this.topOperateItem.id,
},
}).then(() => {
this.$store.dispatch("getDialogs");
this.$Modal.remove();
}).catch(({msg}) => {
$A.modalError(msg, 301);
this.$Modal.remove();
});
} }
} }
} }

View File

@ -258,6 +258,23 @@
} }
} }
} }
.top-operate {
opacity: 0;
position: absolute;
top: 2px;
right: 2px;
transition: opacity 0.2s;
display: flex;
.ivu-icon {
font-size: 16px;
color: #aaaaaa;
transition: color 0.2s;
padding: 2px 5px;
&:hover {
color: $primary-text-color;
}
}
}
} }
.messenger-menu { .messenger-menu {
display: flex; display: flex;
@ -372,6 +389,23 @@
} }
} }
} }
.top-operate {
opacity: 0;
position: absolute;
top: 2px;
right: 2px;
transition: opacity 0.2s;
display: flex;
.ivu-icon {
font-size: 16px;
color: #aaaaaa;
transition: color 0.2s;
padding: 2px 5px;
&:hover {
color: $primary-text-color;
}
}
}
} }
} }
} }