feat: 【消息】列表增加点击右键置顶该聊天功能
This commit is contained in:
parent
ab4fbf0437
commit
04c59041e0
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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()
|
||||||
|
@ -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");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -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": [
|
||||||
|
@ -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"></i>
|
<i v-if="dialog.group_type=='project'" class="taskfont icon-avatar project"></i>
|
||||||
<i v-else-if="dialog.group_type=='task'" class="taskfont icon-avatar task" :class="{completed:$A.dialogCompleted(dialog)}"></i>
|
<i v-else-if="dialog.group_type=='task'" class="taskfont icon-avatar task" :class="{completed:$A.dialogCompleted(dialog)}"></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();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
34
resources/assets/sass/pages/page-messenger.scss
vendored
34
resources/assets/sass/pages/page-messenger.scss
vendored
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user