perf: 优化撤回消息

This commit is contained in:
kuaifan 2022-01-29 12:55:44 +08:00
parent 3d04bd4444
commit 9999548bc2
8 changed files with 386 additions and 154 deletions

View File

@ -160,16 +160,28 @@ class DialogController extends AbstractController
} }
/** /**
* @api {get} api/dialog/msg/sendtext 05. 未读消息 * @api {get} api/dialog/msg/unread 05. 获取未读消息数量
* *
* @apiDescription 需要token身份 * @apiDescription 需要token身份
* @apiVersion 1.0.0 * @apiVersion 1.0.0
* @apiGroup dialog * @apiGroup dialog
* @apiName msg__sendtext * @apiName msg__unread
*
* @apiParam {Number} [dialog_id] 对话ID留空获取总未读消息数量
*
* @apiSuccess {Number} ret 返回状态码1正确、0错误
* @apiSuccess {String} msg 返回信息(错误描述)
* @apiSuccess {Object} data 返回数据
*/ */
public function msg__unread() public function msg__unread()
{ {
$unread = WebSocketDialogMsgRead::whereUserid(User::userid())->whereReadAt(null)->count(); $dialog_id = intval(Request::input('dialog_id'));
//
$builder = WebSocketDialogMsgRead::whereUserid(User::userid())->whereReadAt(null);
if ($dialog_id > 0) {
$builder->whereDialogId($dialog_id);
}
$unread = $builder->count();
return Base::retSuccess('success', [ return Base::retSuccess('success', [
'unread' => $unread, 'unread' => $unread,
]); ]);
@ -417,7 +429,7 @@ class DialogController extends AbstractController
/** /**
* @api {get} api/dialog/msg/withdraw 11. 聊天消息撤回 * @api {get} api/dialog/msg/withdraw 11. 聊天消息撤回
* *
* @apiDescription 需要token身份 * @apiDescription 消息撤回限制24小时内需要token身份
* @apiVersion 1.0.0 * @apiVersion 1.0.0
* @apiGroup dialog * @apiGroup dialog
* @apiName msg__withdraw * @apiName msg__withdraw

View File

@ -8,6 +8,7 @@ use App\Tasks\PushTask;
use App\Tasks\WebSocketDialogMsgTask; use App\Tasks\WebSocketDialogMsgTask;
use Carbon\Carbon; use Carbon\Carbon;
use Hhxsv5\LaravelS\Swoole\Task\Task; use Hhxsv5\LaravelS\Swoole\Task\Task;
use Illuminate\Database\Eloquent\SoftDeletes;
/** /**
* App\Models\WebSocketDialogMsg * App\Models\WebSocketDialogMsg
@ -21,11 +22,15 @@ use Hhxsv5\LaravelS\Swoole\Task\Task;
* @property int|null $send 发送数量 * @property int|null $send 发送数量
* @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
* @property \Illuminate\Support\Carbon|null $deleted_at
* @property-read int|mixed $percentage * @property-read int|mixed $percentage
* @property-read \App\Models\WebSocketDialog|null $webSocketDialog
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg newModelQuery() * @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg newQuery() * @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg newQuery()
* @method static \Illuminate\Database\Query\Builder|WebSocketDialogMsg onlyTrashed()
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg query() * @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg query()
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereCreatedAt($value) * @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereCreatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereDeletedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereDialogId($value) * @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereDialogId($value)
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereId($value) * @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereMsg($value) * @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereMsg($value)
@ -34,10 +39,14 @@ use Hhxsv5\LaravelS\Swoole\Task\Task;
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereType($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 whereUpdatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereUserid($value) * @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereUserid($value)
* @method static \Illuminate\Database\Query\Builder|WebSocketDialogMsg withTrashed()
* @method static \Illuminate\Database\Query\Builder|WebSocketDialogMsg withoutTrashed()
* @mixin \Eloquent * @mixin \Eloquent
*/ */
class WebSocketDialogMsg extends AbstractModel class WebSocketDialogMsg extends AbstractModel
{ {
use SoftDeletes;
protected $appends = [ protected $appends = [
'percentage', 'percentage',
]; ];
@ -46,6 +55,14 @@ class WebSocketDialogMsg extends AbstractModel
'updated_at', 'updated_at',
]; ];
/**
* @return \Illuminate\Database\Eloquent\Relations\HasOne
*/
public function webSocketDialog(): \Illuminate\Database\Eloquent\Relations\HasOne
{
return $this->hasOne(WebSocketDialog::class, 'id', 'dialog_id');
}
/** /**
* 阅读占比 * 阅读占比
* @return int|mixed * @return int|mixed
@ -130,27 +147,39 @@ class WebSocketDialogMsg extends AbstractModel
*/ */
public function deleteMsg() public function deleteMsg()
{ {
$send_dt = Carbon::parse($this->created_at)->addMinutes(5); $send_dt = Carbon::parse($this->created_at)->addDay();
if ($send_dt->lt(Carbon::now())) { if ($send_dt->lt(Carbon::now())) {
throw new ApiException('已超过5分钟此消息不能撤回'); throw new ApiException('已超过24小时此消息不能撤回');
}
$this->delete();
//
$dialog = WebSocketDialog::find($this->dialog_id);
if ($dialog) {
$userids = $dialog->dialogUser->pluck('userid')->toArray();
PushTask::push([
'userid' => $userids,
'msg' => [
'type' => 'dialog',
'mode' => 'delete',
'data' => [
'id' => $this->id,
'dialog_id' => $this->dialog_id
],
]
]);
} }
AbstractModel::transaction(function() {
$deleteRead = WebSocketDialogMsgRead::whereMsgId($this->id)->whereNull('read_at')->delete(); // 未阅读记录不需要软删除,直接删除即可
$this->delete();
//
$last_msg = null;
if ($this->webSocketDialog) {
$last_msg = WebSocketDialogMsg::whereDialogId($this->dialog_id)->orderByDesc('id')->first();
$this->webSocketDialog->last_at = $last_msg->created_at;
$this->webSocketDialog->save();
}
//
$dialog = WebSocketDialog::find($this->dialog_id);
if ($dialog) {
$userids = $dialog->dialogUser->pluck('userid')->toArray();
PushTask::push([
'userid' => $userids,
'msg' => [
'type' => 'dialog',
'mode' => 'delete',
'data' => [
'id' => $this->id,
'dialog_id' => $this->dialog_id,
'last_msg' => $last_msg,
'update_read' => $deleteRead ? 1 : 0
],
]
]);
}
});
} }
/** /**

View File

@ -0,0 +1,34 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class WebSocketDialogMsgsAddDeletes 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', 'deleted_at')) {
$table->softDeletes();
}
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('web_socket_dialog_msgs', function (Blueprint $table) {
$table->dropSoftDeletes();
});
}
}

View File

@ -1,41 +1,49 @@
<template> <template>
<div :class="`dialog-view ${msgData.type}`" :data-id="msgData.id"> <div :class="`dialog-view ${msgData.type}`" :data-id="msgData.id">
<!--文本--> <div class="dialog-head">
<div v-if="msgData.type === 'text'" class="dialog-content"> <!--详情-->
<pre class="no-dark-mode">{{textMsg(msgData.msg.text)}}</pre> <div class="dialog-content">
</div> <!--文本-->
<div v-if="msgData.type === 'text'" class="content-text">
<!--等待--> <pre class="no-dark-mode">{{textMsg(msgData.msg.text)}}</pre>
<div v-else-if="msgData.type === 'loading'" class="dialog-content loading"><Loading/></div> </div>
<!--文件-->
<!--文件--> <div v-else-if="msgData.type === 'file'" :class="`content-file ${msgData.msg.type}`">
<div v-else-if="msgData.type === 'file'" :class="['dialog-content', msgData.msg.type]"> <div class="dialog-file">
<div class="dialog-file"> <img v-if="msgData.msg.type === 'img'" class="file-img" :style="imageStyle(msgData.msg)" :src="msgData.msg.thumb" @click="viewFile"/>
<img v-if="msgData.msg.type === 'img'" class="file-img" :style="imageStyle(msgData.msg)" :src="msgData.msg.thumb" @click="viewFile"/> <div v-else class="file-box">
<div v-else class="file-box"> <img class="file-thumb" :src="msgData.msg.thumb"/>
<img class="file-thumb" :src="msgData.msg.thumb"/> <div class="file-info">
<div class="file-info"> <div class="file-name">{{msgData.msg.name}}</div>
<div class="file-name">{{msgData.msg.name}}</div> <div class="file-size">{{$A.bytesToSize(msgData.msg.size)}}</div>
<div class="file-size">{{$A.bytesToSize(msgData.msg.size)}}</div> </div>
</div>
</div> </div>
</div> </div>
<!--等待-->
<div v-else-if="msgData.type === 'loading'" class="content-loading">
<Loading/>
</div>
<!--未知-->
<div v-else class="content-unknown">{{$L("未知的消息类型")}}</div>
</div> </div>
<div class="dialog-file-menu">
<div class="file-menu-warp"></div> <!--菜单-->
<div class="file-menu-icon"> <div v-if="showMenu" class="dialog-menu">
<Icon @click="viewFile" type="md-eye" /> <div class="menu-icon">
<Icon @click="downFile" type="md-arrow-round-down" /> <Icon v-if="msgData.userid == userId" @click="withdraw" type="md-undo" :title="$L('撤回')"/>
<template v-if="msgData.type === 'file'">
<Icon @click="viewFile" type="md-eye" :title="$L('查看')"/>
<Icon @click="downFile" type="md-arrow-round-down" :title="$L('下载')"/>
</template>
</div> </div>
</div> </div>
</div> </div>
<!--未知-->
<div v-else class="dialog-content unknown">{{$L("未知的消息类型")}}</div>
<!--时间/阅读--> <!--时间/阅读-->
<div v-if="msgData.created_at" class="dialog-foot"> <div v-if="msgData.created_at" class="dialog-foot">
<div class="time">{{$A.formatTime(msgData.created_at)}}</div> <div class="time" :title="msgData.created_at">{{$A.formatTime(msgData.created_at)}}</div>
<Poptip <Poptip
v-if="msgData.send > 1 || dialogType == 'group'" v-if="msgData.send > 1 || dialogType == 'group'"
class="percent" class="percent"
@ -95,7 +103,7 @@ export default {
}, },
computed: { computed: {
...mapState(['userToken']), ...mapState(['userToken', 'userId']),
readList() { readList() {
return this.read_list.filter(({read_at}) => read_at) return this.read_list.filter(({read_at}) => read_at)
@ -103,6 +111,10 @@ export default {
unreadList() { unreadList() {
return this.read_list.filter(({read_at}) => !read_at) return this.read_list.filter(({read_at}) => !read_at)
},
showMenu() {
return this.msgData.userid == this.userId || this.msgData.type === 'file'
} }
}, },
@ -176,6 +188,29 @@ export default {
return {}; return {};
}, },
withdraw() {
$A.modalConfirm({
content: `确定撤回此信息吗?`,
okText: '撤回',
loading: true,
onOk: () => {
this.$store.dispatch("call", {
url: 'dialog/msg/withdraw',
data: {
msg_id: this.msgData.id
},
}).then(() => {
$A.messageSuccess("消息已撤回");
this.$store.dispatch("forgetDialogMsg", this.msgData.id);
this.$Modal.remove();
}).catch(({msg}) => {
$A.messageError(msg, 301);
this.$Modal.remove();
});
}
});
},
viewFile() { viewFile() {
if (this.$Electron) { if (this.$Electron) {
this.$Electron.ipcRenderer.send('windowRouter', { this.$Electron.ipcRenderer.send('windowRouter', {

View File

@ -2053,6 +2053,22 @@ export default {
case 'delete': case 'delete':
// 删除消息 // 删除消息
dispatch("forgetDialogMsg", data.id) dispatch("forgetDialogMsg", data.id)
//
let dialog = state.cacheDialogs.find(({id}) => id == data.dialog_id);
if (dialog) {
// 更新最后消息
dialog.last_at = data.last_msg && data.last_msg.created_at;
dialog.last_msg = data.last_msg;
if (data.update_read) {
// 更新未读数量
dispatch("call", {
url: 'dialog/msg/unread',
dialog_id: data.dialog_id
}).then(result => {
dialog.unread = result.data.unread
}).catch(() => {});
}
}
break; break;
case 'add': case 'add':
case 'chat': case 'chat':

View File

@ -140,8 +140,10 @@ body.dark-mode-reverse {
> li { > li {
.dialog-view { .dialog-view {
.dialog-content { .dialog-content {
color: #ffffff;
background-color: #e1e1e1; background-color: #e1e1e1;
.content-text {
color: #ffffff;
}
} }
} }
&.self { &.self {

View File

@ -8,6 +8,7 @@
flex-direction: column; flex-direction: column;
background-color: #ffffff; background-color: #ffffff;
z-index: 1; z-index: 1;
.dialog-title { .dialog-title {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -15,6 +16,7 @@
padding: 0 30px; padding: 0 30px;
height: 68px; height: 68px;
position: relative; position: relative;
&:before { &:before {
content: ""; content: "";
position: absolute; position: absolute;
@ -24,6 +26,7 @@
height: 1px; height: 1px;
background-color: #f4f5f5; background-color: #f4f5f5;
} }
&.completed { &.completed {
&:after { &:after {
content: "\f373"; content: "\f373";
@ -39,19 +42,23 @@
z-index: 1; z-index: 1;
} }
} }
.main-title { .main-title {
display: flex; display: flex;
align-items: center; align-items: center;
line-height: 22px; line-height: 22px;
max-width: 100%; max-width: 100%;
.ivu-tag { .ivu-tag {
flex-shrink: 0; flex-shrink: 0;
margin: 0 6px 0 0; margin: 0 6px 0 0;
padding: 0 5px; padding: 0 5px;
&.ivu-tag-success { &.ivu-tag-success {
padding: 0 6px; padding: 0 6px;
} }
} }
.ivu-icon { .ivu-icon {
font-size: 18px; font-size: 18px;
margin-right: 6px; margin-right: 6px;
@ -60,6 +67,7 @@
color: $primary-color; color: $primary-color;
} }
} }
> h2 { > h2 {
font-size: 17px; font-size: 17px;
font-weight: 600; font-weight: 600;
@ -67,6 +75,7 @@
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
} }
> em { > em {
font-style: normal; font-style: normal;
font-size: 17px; font-size: 17px;
@ -74,24 +83,29 @@
padding-left: 6px; padding-left: 6px;
} }
} }
.sub-title { .sub-title {
flex-shrink: 0; flex-shrink: 0;
font-size: 12px; font-size: 12px;
line-height: 20px; line-height: 20px;
color: #aaaaaa; color: #aaaaaa;
&.pointer { &.pointer {
cursor: pointer; cursor: pointer;
&:hover { &:hover {
color: #888888; color: #888888;
} }
} }
} }
} }
.dialog-scroller { .dialog-scroller {
position: relative; position: relative;
flex: 1; flex: 1;
padding: 0 32px; padding: 0 32px;
overflow: auto; overflow: auto;
.dialog-list { .dialog-list {
> ul { > ul {
> li { > li {
@ -100,9 +114,11 @@
align-items: flex-end; align-items: flex-end;
list-style: none; list-style: none;
margin-bottom: 16px; margin-bottom: 16px;
&:first-child { &:first-child {
margin-top: 16px; margin-top: 16px;
} }
.dialog-avatar { .dialog-avatar {
position: relative; position: relative;
margin-bottom: 20px; margin-bottom: 20px;
@ -110,36 +126,137 @@
width: 30px; width: 30px;
height: 30px; height: 30px;
} }
.dialog-view { .dialog-view {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: flex-start; align-items: flex-start;
margin: 0 0 0 8px; margin: 0 0 0 8px;
position: relative; position: relative;
&.text { &.text {
max-width: 70%; max-width: 70%;
} }
.dialog-content {
color: #333333; &:hover {
background-color: #F4F5F7; .dialog-head {
padding: 8px; .dialog-menu {
min-width: 32px; opacity: 1;
border-radius: 6px 6px 6px 0;
.dialog-file-menu {
opacity: 0;
transition: all 0.3s;
position: absolute;
left: 0;
bottom: -8px;
.file-menu-warp {
width: 100%;
height: 12px;
} }
.file-menu-icon { }
}
.dialog-head {
display: flex;
align-items: flex-start;
.dialog-content {
background-color: #F4F5F7;
padding: 8px;
min-width: 32px;
border-radius: 6px 6px 6px 0;
display: flex;
align-items: flex-start;
.content-text {
color: #333333;
> pre {
display: block;
margin: 0;
padding: 0;
line-height: 1.5;
white-space: pre-wrap;
word-wrap: break-word;
word-break: break-word;
}
}
.content-file {
&.file {
display: inline-block;
.file-box {
background-color: #ffffff;
display: flex;
align-items: center;
padding: 10px 14px;
border-radius: 3px;
width: 220px;
.file-thumb {
width: 36px;
}
.file-info {
margin-left: 12px;
display: flex;
flex-direction: column;
justify-content: center;
.file-name {
color: #333333;
font-size: 14px;
line-height: 18px;
word-break: break-all;
text-overflow: ellipsis;
overflow: hidden;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
.file-size {
padding-top: 4px;
color: #666666;
font-size: 14px;
}
}
}
}
&.img {
padding: 0;
display: flex;
max-width: 220px;
max-height: 220px;
border-radius: 6px;
background-color: transparent;
overflow: hidden;
.file-img {
display: flex;
cursor: pointer;
}
}
}
.content-loading {
display: flex;
.common-loading {
width: 20px;
height: 20px;
margin: 4px;
}
}
.content-unknown {
text-decoration: underline;
}
}
.dialog-menu {
opacity: 0;
margin-left: 6px;
transition: all 0.3s;
.menu-icon {
display: flex; display: flex;
align-items: center; align-items: center;
border-radius: 4px; border-radius: 4px;
border: 1px solid #ddd; border: 1px solid #ddd;
background-color: #ffffff;
> i { > i {
flex: 1; flex: 1;
display: inline-block; display: inline-block;
@ -147,105 +264,37 @@
color: #999; color: #999;
font-size: 13px; font-size: 13px;
cursor: pointer; cursor: pointer;
& + i {
border-left: 1px solid #ddd;
}
&:hover { &:hover {
color: #777; color: #777;
} }
&+i {
border-left: 1px solid #ddd;
}
} }
} }
} }
> pre {
display: block;
margin: 0;
padding: 0;
line-height: 1.5;
white-space: pre-wrap;
word-wrap: break-word;
word-break: break-word;
}
&:hover {
.dialog-file-menu {
opacity: 1;
}
}
&.loading {
display: flex;
.common-loading {
width: 20px;
height: 20px;
margin: 4px;
}
}
&.file {
display: inline-block;
.file-box {
background-color: #ffffff;
display: flex;
align-items: center;
padding: 10px 14px;
border-radius: 3px;
width: 220px;
.file-thumb {
width: 36px;
}
.file-info {
margin-left: 12px;
display: flex;
flex-direction: column;
justify-content: center;
.file-name {
color: #333333;
font-size: 14px;
line-height: 18px;
word-break: break-all;
text-overflow: ellipsis;
overflow: hidden;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
.file-size {
padding-top: 4px;
color: #666666;
font-size: 14px;
}
}
}
}
&.img {
padding: 0;
display: flex;
max-width: 220px;
max-height: 220px;
border-radius: 6px;
background-color: transparent;
overflow: hidden;
.file-img {
display: flex;
cursor: pointer;
}
}
&.unknown {
text-decoration: underline;
}
} }
.dialog-foot { .dialog-foot {
display: flex; display: flex;
align-items: center; align-items: center;
padding-top: 4px; padding-top: 4px;
height: 21px; height: 21px;
line-height: 1; line-height: 1;
.common-loading { .common-loading {
margin: 0 2px; margin: 0 2px;
width: 10px; width: 10px;
height: 10px; height: 10px;
} }
.time { .time {
color: #bbbbbb; color: #bbbbbb;
font-size: 12px; font-size: 12px;
} }
.done { .done {
display: none; display: none;
margin-left: 4px; margin-left: 4px;
@ -253,6 +302,7 @@
font-size: 12px; font-size: 12px;
color: $primary-color; color: $primary-color;
} }
.percent { .percent {
display: none; display: none;
margin-left: 4px; margin-left: 4px;
@ -260,6 +310,7 @@
} }
} }
} }
.dialog-action { .dialog-action {
align-self: flex-start; align-self: flex-start;
display: flex; display: flex;
@ -271,6 +322,7 @@
} }
} }
&.history { &.history {
cursor: pointer; cursor: pointer;
justify-content: center; justify-content: center;
@ -279,13 +331,16 @@
margin: 12px 0; margin: 12px 0;
opacity: 0.6; opacity: 0.6;
transition: opacity 0.2s; transition: opacity 0.2s;
&:hover { &:hover {
opacity: 1; opacity: 1;
} }
} }
&.history-tip { &.history-tip {
position: relative; position: relative;
padding-top: 60px; padding-top: 60px;
.history-text { .history-text {
font-style: normal; font-style: normal;
position: absolute; position: absolute;
@ -301,15 +356,18 @@
transform: translateX(-50%); transform: translateX(-50%);
} }
} }
&.loading { &.loading {
padding: 12px 0; padding: 12px 0;
justify-content: center; justify-content: center;
.common-loading { .common-loading {
margin: 0; margin: 0;
width: 18px; width: 18px;
height: 18px; height: 18px;
} }
} }
&.nothing { &.nothing {
position: absolute; position: absolute;
top: 50%; top: 50%;
@ -317,32 +375,54 @@
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
color: #999999; color: #999999;
} }
&.bottom { &.bottom {
height: 0; height: 0;
margin: 0; margin: 0;
padding: 0; padding: 0;
} }
&.self { &.self {
flex-direction: row-reverse; flex-direction: row-reverse;
.dialog-view { .dialog-view {
align-items: flex-end; align-items: flex-end;
margin: 0 8px 0 0; margin: 0 8px 0 0;
.dialog-content {
color: #ffffff; .dialog-head {
background-color: $primary-color; flex-direction: row-reverse;
border-radius: 6px 6px 0 6px;
&.file { .dialog-content {
background-color: #F4F5F7; background-color: $primary-color;
border-radius: 6px 6px 0 6px;
.content-text {
color: #ffffff;
}
.content-file {
&.file {
background-color: #F4F5F7;
}
&.img {
border-radius: 6px;
background-color: transparent;
}
}
} }
&.img {
border-radius: 6px; .dialog-menu {
background-color: transparent; margin-left: 0;
margin-right: 6px;
} }
} }
.dialog-foot { .dialog-foot {
.done { .done {
display: inline-block; display: inline-block;
} }
.percent { .percent {
display: inline-block; display: inline-block;
} }
@ -353,6 +433,7 @@
} }
} }
} }
.dialog-footer { .dialog-footer {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -360,6 +441,7 @@
padding: 0 28px; padding: 0 28px;
margin-bottom: 20px; margin-bottom: 20px;
position: relative; position: relative;
.dialog-newmsg { .dialog-newmsg {
display: none; display: none;
height: 30px; height: 30px;
@ -374,19 +456,23 @@
cursor: pointer; cursor: pointer;
z-index: 2;; z-index: 2;;
} }
.dialog-input { .dialog-input {
background-color: #F4F5F7; background-color: #F4F5F7;
padding: 10px 52px 10px 12px; padding: 10px 52px 10px 12px;
border-radius: 10px; border-radius: 10px;
.ivu-input { .ivu-input {
border: 0; border: 0;
resize: none; resize: none;
background-color: transparent; background-color: transparent;
&:focus { &:focus {
box-shadow: none; box-shadow: none;
} }
} }
} }
.dialog-send { .dialog-send {
position: absolute; position: absolute;
top: 0; top: 0;
@ -398,19 +484,23 @@
align-items: center; align-items: center;
justify-content: center; justify-content: center;
} }
.chat-upload { .chat-upload {
display: none; display: none;
width: 0; width: 0;
height: 0; height: 0;
overflow: hidden; overflow: hidden;
} }
&.newmsg { &.newmsg {
margin-top: -50px; margin-top: -50px;
.dialog-newmsg { .dialog-newmsg {
display: block; display: block;
} }
} }
} }
.drag-over { .drag-over {
position: absolute; position: absolute;
top: 0; top: 0;
@ -422,6 +512,7 @@
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
&:before { &:before {
content: ""; content: "";
position: absolute; position: absolute;
@ -432,6 +523,7 @@
border: 2px dashed #7b7b7b; border: 2px dashed #7b7b7b;
border-radius: 12px; border-radius: 12px;
} }
.drag-text { .drag-text {
padding: 12px; padding: 12px;
font-size: 18px; font-size: 18px;
@ -439,23 +531,29 @@
} }
} }
} }
.dialog-wrapper-read-poptip-content { .dialog-wrapper-read-poptip-content {
display: flex; display: flex;
position: relative; position: relative;
.read, .read,
.unread { .unread {
flex: 1; flex: 1;
max-height: 300px; max-height: 300px;
overflow: auto; overflow: auto;
> li { > li {
list-style: none; list-style: none;
margin-bottom: 12px; margin-bottom: 12px;
.common-avatar { .common-avatar {
width: 100%; width: 100%;
} }
&:last-child { &:last-child {
margin-bottom: 6px; margin-bottom: 6px;
} }
&.read-title { &.read-title {
> em { > em {
font-size: 18px; font-size: 18px;
@ -466,11 +564,13 @@
} }
} }
} }
.unread { .unread {
> li { > li {
padding-left: 16px; padding-left: 16px;
} }
} }
&:before { &:before {
content: ""; content: "";
position: absolute; position: absolute;
@ -484,10 +584,12 @@
.dialog-wrapper-paste { .dialog-wrapper-paste {
margin-top: -4px; margin-top: -4px;
img { img {
max-width: 100%; max-width: 100%;
max-height: 1000px; max-height: 1000px;
} }
> div, > div,
> img { > img {
display: flex; display: flex;
@ -502,6 +604,7 @@
.dialog-footer { .dialog-footer {
padding: 0 20px; padding: 0 20px;
margin-bottom: 16px; margin-bottom: 16px;
.dialog-send { .dialog-send {
right: 20px; right: 20px;
} }

View File

@ -6,7 +6,7 @@
min-height: 120px; min-height: 120px;
overflow: auto; overflow: auto;
.task-info { .task-info {
flex: 1; flex: 3;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
position: relative; position: relative;
@ -459,6 +459,7 @@
} }
} }
.task-dialog { .task-dialog {
flex: 2;
flex-shrink: 0; flex-shrink: 0;
display: flex; display: flex;
flex-direction: column; flex-direction: column;