perf: 优化撤回消息
This commit is contained in:
parent
3d04bd4444
commit
9999548bc2
@ -160,16 +160,28 @@ class DialogController extends AbstractController
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/dialog/msg/sendtext 05. 未读消息
|
||||
* @api {get} api/dialog/msg/unread 05. 获取未读消息数量
|
||||
*
|
||||
* @apiDescription 需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
* @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()
|
||||
{
|
||||
$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', [
|
||||
'unread' => $unread,
|
||||
]);
|
||||
@ -417,7 +429,7 @@ class DialogController extends AbstractController
|
||||
/**
|
||||
* @api {get} api/dialog/msg/withdraw 11. 聊天消息撤回
|
||||
*
|
||||
* @apiDescription 需要token身份
|
||||
* @apiDescription 消息撤回限制24小时内,需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup dialog
|
||||
* @apiName msg__withdraw
|
||||
|
@ -8,6 +8,7 @@ use App\Tasks\PushTask;
|
||||
use App\Tasks\WebSocketDialogMsgTask;
|
||||
use Carbon\Carbon;
|
||||
use Hhxsv5\LaravelS\Swoole\Task\Task;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
/**
|
||||
* App\Models\WebSocketDialogMsg
|
||||
@ -21,11 +22,15 @@ use Hhxsv5\LaravelS\Swoole\Task\Task;
|
||||
* @property int|null $send 发送数量
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @property \Illuminate\Support\Carbon|null $deleted_at
|
||||
* @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 newQuery()
|
||||
* @method static \Illuminate\Database\Query\Builder|WebSocketDialogMsg onlyTrashed()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg query()
|
||||
* @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 whereId($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 whereUpdatedAt($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
|
||||
*/
|
||||
class WebSocketDialogMsg extends AbstractModel
|
||||
{
|
||||
use SoftDeletes;
|
||||
|
||||
protected $appends = [
|
||||
'percentage',
|
||||
];
|
||||
@ -46,6 +55,14 @@ class WebSocketDialogMsg extends AbstractModel
|
||||
'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
|
||||
@ -130,27 +147,39 @@ class WebSocketDialogMsg extends AbstractModel
|
||||
*/
|
||||
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())) {
|
||||
throw new ApiException('已超过5分钟,此消息不能撤回');
|
||||
}
|
||||
$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
|
||||
],
|
||||
]
|
||||
]);
|
||||
throw new ApiException('已超过24小时,此消息不能撤回');
|
||||
}
|
||||
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
|
||||
],
|
||||
]
|
||||
]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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();
|
||||
});
|
||||
}
|
||||
}
|
@ -1,41 +1,49 @@
|
||||
<template>
|
||||
<div :class="`dialog-view ${msgData.type}`" :data-id="msgData.id">
|
||||
|
||||
<!--文本-->
|
||||
<div v-if="msgData.type === 'text'" class="dialog-content">
|
||||
<pre class="no-dark-mode">{{textMsg(msgData.msg.text)}}</pre>
|
||||
</div>
|
||||
|
||||
<!--等待-->
|
||||
<div v-else-if="msgData.type === 'loading'" class="dialog-content loading"><Loading/></div>
|
||||
|
||||
<!--文件-->
|
||||
<div v-else-if="msgData.type === 'file'" :class="['dialog-content', msgData.msg.type]">
|
||||
<div class="dialog-file">
|
||||
<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">
|
||||
<img class="file-thumb" :src="msgData.msg.thumb"/>
|
||||
<div class="file-info">
|
||||
<div class="file-name">{{msgData.msg.name}}</div>
|
||||
<div class="file-size">{{$A.bytesToSize(msgData.msg.size)}}</div>
|
||||
<div class="dialog-head">
|
||||
<!--详情-->
|
||||
<div class="dialog-content">
|
||||
<!--文本-->
|
||||
<div v-if="msgData.type === 'text'" class="content-text">
|
||||
<pre class="no-dark-mode">{{textMsg(msgData.msg.text)}}</pre>
|
||||
</div>
|
||||
<!--文件-->
|
||||
<div v-else-if="msgData.type === 'file'" :class="`content-file ${msgData.msg.type}`">
|
||||
<div class="dialog-file">
|
||||
<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">
|
||||
<img class="file-thumb" :src="msgData.msg.thumb"/>
|
||||
<div class="file-info">
|
||||
<div class="file-name">{{msgData.msg.name}}</div>
|
||||
<div class="file-size">{{$A.bytesToSize(msgData.msg.size)}}</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 class="dialog-file-menu">
|
||||
<div class="file-menu-warp"></div>
|
||||
<div class="file-menu-icon">
|
||||
<Icon @click="viewFile" type="md-eye" />
|
||||
<Icon @click="downFile" type="md-arrow-round-down" />
|
||||
|
||||
<!--菜单-->
|
||||
<div v-if="showMenu" class="dialog-menu">
|
||||
<div class="menu-icon">
|
||||
<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 v-else class="dialog-content unknown">{{$L("未知的消息类型")}}</div>
|
||||
|
||||
<!--时间/阅读-->
|
||||
<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
|
||||
v-if="msgData.send > 1 || dialogType == 'group'"
|
||||
class="percent"
|
||||
@ -95,7 +103,7 @@ export default {
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['userToken']),
|
||||
...mapState(['userToken', 'userId']),
|
||||
|
||||
readList() {
|
||||
return this.read_list.filter(({read_at}) => read_at)
|
||||
@ -103,6 +111,10 @@ export default {
|
||||
|
||||
unreadList() {
|
||||
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 {};
|
||||
},
|
||||
|
||||
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() {
|
||||
if (this.$Electron) {
|
||||
this.$Electron.ipcRenderer.send('windowRouter', {
|
||||
|
16
resources/assets/js/store/actions.js
vendored
16
resources/assets/js/store/actions.js
vendored
@ -2053,6 +2053,22 @@ export default {
|
||||
case 'delete':
|
||||
// 删除消息
|
||||
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;
|
||||
case 'add':
|
||||
case 'chat':
|
||||
|
4
resources/assets/sass/dark.scss
vendored
4
resources/assets/sass/dark.scss
vendored
@ -140,8 +140,10 @@ body.dark-mode-reverse {
|
||||
> li {
|
||||
.dialog-view {
|
||||
.dialog-content {
|
||||
color: #ffffff;
|
||||
background-color: #e1e1e1;
|
||||
.content-text {
|
||||
color: #ffffff;
|
||||
}
|
||||
}
|
||||
}
|
||||
&.self {
|
||||
|
@ -8,6 +8,7 @@
|
||||
flex-direction: column;
|
||||
background-color: #ffffff;
|
||||
z-index: 1;
|
||||
|
||||
.dialog-title {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@ -15,6 +16,7 @@
|
||||
padding: 0 30px;
|
||||
height: 68px;
|
||||
position: relative;
|
||||
|
||||
&:before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
@ -24,6 +26,7 @@
|
||||
height: 1px;
|
||||
background-color: #f4f5f5;
|
||||
}
|
||||
|
||||
&.completed {
|
||||
&:after {
|
||||
content: "\f373";
|
||||
@ -39,19 +42,23 @@
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.main-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
line-height: 22px;
|
||||
max-width: 100%;
|
||||
|
||||
.ivu-tag {
|
||||
flex-shrink: 0;
|
||||
margin: 0 6px 0 0;
|
||||
padding: 0 5px;
|
||||
|
||||
&.ivu-tag-success {
|
||||
padding: 0 6px;
|
||||
}
|
||||
}
|
||||
|
||||
.ivu-icon {
|
||||
font-size: 18px;
|
||||
margin-right: 6px;
|
||||
@ -60,6 +67,7 @@
|
||||
color: $primary-color;
|
||||
}
|
||||
}
|
||||
|
||||
> h2 {
|
||||
font-size: 17px;
|
||||
font-weight: 600;
|
||||
@ -67,6 +75,7 @@
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
> em {
|
||||
font-style: normal;
|
||||
font-size: 17px;
|
||||
@ -74,24 +83,29 @@
|
||||
padding-left: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
.sub-title {
|
||||
flex-shrink: 0;
|
||||
font-size: 12px;
|
||||
line-height: 20px;
|
||||
color: #aaaaaa;
|
||||
|
||||
&.pointer {
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: #888888;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dialog-scroller {
|
||||
position: relative;
|
||||
flex: 1;
|
||||
padding: 0 32px;
|
||||
overflow: auto;
|
||||
|
||||
.dialog-list {
|
||||
> ul {
|
||||
> li {
|
||||
@ -100,9 +114,11 @@
|
||||
align-items: flex-end;
|
||||
list-style: none;
|
||||
margin-bottom: 16px;
|
||||
|
||||
&:first-child {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.dialog-avatar {
|
||||
position: relative;
|
||||
margin-bottom: 20px;
|
||||
@ -110,36 +126,137 @@
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
.dialog-view {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
margin: 0 0 0 8px;
|
||||
position: relative;
|
||||
|
||||
&.text {
|
||||
max-width: 70%;
|
||||
}
|
||||
.dialog-content {
|
||||
color: #333333;
|
||||
background-color: #F4F5F7;
|
||||
padding: 8px;
|
||||
min-width: 32px;
|
||||
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;
|
||||
|
||||
&:hover {
|
||||
.dialog-head {
|
||||
.dialog-menu {
|
||||
opacity: 1;
|
||||
}
|
||||
.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;
|
||||
align-items: center;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #ddd;
|
||||
background-color: #ffffff;
|
||||
|
||||
> i {
|
||||
flex: 1;
|
||||
display: inline-block;
|
||||
@ -147,105 +264,37 @@
|
||||
color: #999;
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
|
||||
& + i {
|
||||
border-left: 1px solid #ddd;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
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 {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-top: 4px;
|
||||
height: 21px;
|
||||
line-height: 1;
|
||||
|
||||
.common-loading {
|
||||
margin: 0 2px;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
}
|
||||
|
||||
.time {
|
||||
color: #bbbbbb;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.done {
|
||||
display: none;
|
||||
margin-left: 4px;
|
||||
@ -253,6 +302,7 @@
|
||||
font-size: 12px;
|
||||
color: $primary-color;
|
||||
}
|
||||
|
||||
.percent {
|
||||
display: none;
|
||||
margin-left: 4px;
|
||||
@ -260,6 +310,7 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dialog-action {
|
||||
align-self: flex-start;
|
||||
display: flex;
|
||||
@ -271,6 +322,7 @@
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
&.history {
|
||||
cursor: pointer;
|
||||
justify-content: center;
|
||||
@ -279,13 +331,16 @@
|
||||
margin: 12px 0;
|
||||
opacity: 0.6;
|
||||
transition: opacity 0.2s;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
&.history-tip {
|
||||
position: relative;
|
||||
padding-top: 60px;
|
||||
|
||||
.history-text {
|
||||
font-style: normal;
|
||||
position: absolute;
|
||||
@ -301,15 +356,18 @@
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
}
|
||||
|
||||
&.loading {
|
||||
padding: 12px 0;
|
||||
justify-content: center;
|
||||
|
||||
.common-loading {
|
||||
margin: 0;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
&.nothing {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
@ -317,32 +375,54 @@
|
||||
transform: translate(-50%, -50%);
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
&.bottom {
|
||||
height: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
&.self {
|
||||
flex-direction: row-reverse;
|
||||
|
||||
.dialog-view {
|
||||
align-items: flex-end;
|
||||
margin: 0 8px 0 0;
|
||||
.dialog-content {
|
||||
color: #ffffff;
|
||||
background-color: $primary-color;
|
||||
border-radius: 6px 6px 0 6px;
|
||||
&.file {
|
||||
background-color: #F4F5F7;
|
||||
|
||||
.dialog-head {
|
||||
flex-direction: row-reverse;
|
||||
|
||||
.dialog-content {
|
||||
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;
|
||||
background-color: transparent;
|
||||
|
||||
.dialog-menu {
|
||||
margin-left: 0;
|
||||
margin-right: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
.dialog-foot {
|
||||
.done {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.percent {
|
||||
display: inline-block;
|
||||
}
|
||||
@ -353,6 +433,7 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dialog-footer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@ -360,6 +441,7 @@
|
||||
padding: 0 28px;
|
||||
margin-bottom: 20px;
|
||||
position: relative;
|
||||
|
||||
.dialog-newmsg {
|
||||
display: none;
|
||||
height: 30px;
|
||||
@ -374,19 +456,23 @@
|
||||
cursor: pointer;
|
||||
z-index: 2;;
|
||||
}
|
||||
|
||||
.dialog-input {
|
||||
background-color: #F4F5F7;
|
||||
padding: 10px 52px 10px 12px;
|
||||
border-radius: 10px;
|
||||
|
||||
.ivu-input {
|
||||
border: 0;
|
||||
resize: none;
|
||||
background-color: transparent;
|
||||
|
||||
&:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dialog-send {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
@ -398,19 +484,23 @@
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.chat-upload {
|
||||
display: none;
|
||||
width: 0;
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
&.newmsg {
|
||||
margin-top: -50px;
|
||||
|
||||
.dialog-newmsg {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.drag-over {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
@ -422,6 +512,7 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
&:before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
@ -432,6 +523,7 @@
|
||||
border: 2px dashed #7b7b7b;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.drag-text {
|
||||
padding: 12px;
|
||||
font-size: 18px;
|
||||
@ -439,23 +531,29 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dialog-wrapper-read-poptip-content {
|
||||
display: flex;
|
||||
position: relative;
|
||||
|
||||
.read,
|
||||
.unread {
|
||||
flex: 1;
|
||||
max-height: 300px;
|
||||
overflow: auto;
|
||||
|
||||
> li {
|
||||
list-style: none;
|
||||
margin-bottom: 12px;
|
||||
|
||||
.common-avatar {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
&.read-title {
|
||||
> em {
|
||||
font-size: 18px;
|
||||
@ -466,11 +564,13 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.unread {
|
||||
> li {
|
||||
padding-left: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
&:before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
@ -484,10 +584,12 @@
|
||||
|
||||
.dialog-wrapper-paste {
|
||||
margin-top: -4px;
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
max-height: 1000px;
|
||||
}
|
||||
|
||||
> div,
|
||||
> img {
|
||||
display: flex;
|
||||
@ -502,6 +604,7 @@
|
||||
.dialog-footer {
|
||||
padding: 0 20px;
|
||||
margin-bottom: 16px;
|
||||
|
||||
.dialog-send {
|
||||
right: 20px;
|
||||
}
|
||||
|
@ -6,7 +6,7 @@
|
||||
min-height: 120px;
|
||||
overflow: auto;
|
||||
.task-info {
|
||||
flex: 1;
|
||||
flex: 3;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
@ -459,6 +459,7 @@
|
||||
}
|
||||
}
|
||||
.task-dialog {
|
||||
flex: 2;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
Loading…
x
Reference in New Issue
Block a user