整理代码

This commit is contained in:
kuaifan 2022-02-19 11:36:22 +08:00
parent f4f351cf9d
commit 7a267cc07b
14 changed files with 71 additions and 191 deletions

View File

@ -40,10 +40,10 @@ class DialogController extends AbstractController
{ {
$user = User::auth(); $user = User::auth();
// //
$list = WebSocketDialog::select(['web_socket_dialogs.*','u.top','u.top_at']) $list = WebSocketDialog::select(['web_socket_dialogs.*', 'u.top_at'])
->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('u.top_at')
->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) {
@ -481,7 +481,7 @@ class DialogController extends AbstractController
/** /**
* @api {get} api/dialog/top 12. 会话置顶 * @api {get} api/dialog/top 12. 会话置顶
* *
* @apiDescription 消息撤回限制24小时内需要token身份 * @apiDescription 需要token身份
* @apiVersion 1.0.0 * @apiVersion 1.0.0
* @apiGroup dialog * @apiGroup dialog
* @apiName top * @apiName top
@ -500,12 +500,8 @@ class DialogController extends AbstractController
if (!$dialogUser) { if (!$dialogUser) {
return Base::retError("会话不存在"); return Base::retError("会话不存在");
} }
$top = $dialogUser->top === 1 ? 0 : 1; $dialogUser->top_at = $dialogUser->top_at ? null : Carbon::now();
$topAt = $dialogUser->top === 1 ? null : Carbon::now();
$dialogUser->top = $top;
$dialogUser->top_at = $topAt;
$dialogUser->save(); $dialogUser->save();
return Base::retSuccess("success", $dialogId); return Base::retSuccess("success", $dialogId);
} }
} }

View File

@ -42,24 +42,7 @@ class UsersController extends AbstractController
$type = trim(Request::input('type')); $type = trim(Request::input('type'));
$email = trim(Request::input('email')); $email = trim(Request::input('email'));
$password = trim(Request::input('password')); $password = trim(Request::input('password'));
if(!$email){
return Base::retError('请输入邮箱地址');
}
if ($type == 'reg') { if ($type == 'reg') {
$password2 = trim(Request::input('password2'));
//邮箱
if (!Base::isMail($email)) {
return Base::retError('请输入正确的邮箱地址');
}
if (User::email2userid($email) > 0) {
return Base::retError('邮箱地址已存在');
}
if (empty($password)) {
return Base::retError('请输入密码');
}
if ($password != $password2) {
return Base::retError('确认密码输入不一致');
}
$setting = Base::setting('system'); $setting = Base::setting('system');
if ($setting['reg'] == 'close') { if ($setting['reg'] == 'close') {
return Base::retError('未开放注册'); return Base::retError('未开放注册');
@ -81,9 +64,6 @@ class UsersController extends AbstractController
return Base::retError('请输入正确的验证码', ['code' => 'need']); return Base::retError('请输入正确的验证码', ['code' => 'need']);
} }
} }
if (empty($password)) {
return Base::retError('请输入密码');
}
// //
$retError = function ($msg) use ($email) { $retError = function ($msg) use ($email) {
Cache::forever("code::" . $email, "need"); Cache::forever("code::" . $email, "need");

View File

@ -180,6 +180,13 @@ class User extends AbstractModel
*/ */
public static function reg($email, $password, $other = []) public static function reg($email, $password, $other = [])
{ {
//邮箱
if (!Base::isEmail($email)) {
throw new ApiException('请输入正确的邮箱地址');
}
if (User::email2userid($email) > 0) {
throw new ApiException('邮箱地址已存在');
}
//密码 //密码
self::passwordPolicy($password); self::passwordPolicy($password);
//开始注册 //开始注册

View File

@ -8,7 +8,6 @@ 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 $top_at 置顶时间 * @property \Illuminate\Support\Carbon|null $top_at 置顶时间
* @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

View File

@ -967,7 +967,7 @@ class Base
* @param string $str 需要检测的字符串 * @param string $str 需要检测的字符串
* @return int * @return int
*/ */
public static function isMail($str) public static function isEmail($str)
{ {
$RegExp = '/^[a-z0-9][a-z\.0-9-_]+@[a-z0-9_-]+(?:\.[a-z]{0,3}\.[a-z]{0,2}|\.[a-z]{0,3}|\.[a-z]{0,2})$/i'; $RegExp = '/^[a-z0-9][a-z\.0-9-_]+@[a-z0-9_-]+(?:\.[a-z]{0,3}\.[a-z]{0,2}|\.[a-z]{0,3}|\.[a-z]{0,2})$/i';
return preg_match($RegExp, $str); return preg_match($RegExp, $str);

View File

@ -1,55 +0,0 @@
<?php
namespace App\Tasks;
use App\Exceptions\ApiException;
use App\Models\File;
use App\Models\Tmp;
use App\Models\User;
use App\Models\WebSocketTmpMsg;
use Carbon\Carbon;
use Log;
use Throwable;
/**
* 删除过期临时数据任务
* Class DeleteTmpTask
* @package App\Tasks
*/
class BatchRemoveFileTask extends AbstractTask
{
protected array $_ids = [];
protected int $_userid;
public function __construct(array $ids, $userid)
{
$this->_ids = $ids;
$this->_userid = $userid;
}
public function start()
{
foreach ($this->_ids as $id) {
Log::info("---------- $id ----------");
Log::info("尝试删除Id为[$id]的文件");
$file = File::find($id);
if (empty($file)) {
Log::warning("Id为[$id]的文件不存在或已被删除");
continue;
}
Log::info("获取到文件名为[" . $file->name . "],类型为[" . ( $file->type ?: $file->ext ) . "]");
$permission = $file->getPermission($this->_userid);
if ($permission < 1000) {
Log::warning("文件[$id][" . $file->name . "]仅限所有者或创建者操作");
continue;
}
try {
$file->deleteFile();
Log::info("删除Id为[$id]的文件成功");
} catch (Throwable $throwable) {
Log::error("删除Id为[$id]的文件失败,原因是:" . $throwable->getMessage());
}
}
}
}

View File

@ -1,34 +0,0 @@
<?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

@ -48,7 +48,7 @@
<div class="browse-load" v-if="isLoading">{{$L('加载中...')}}</div> <div class="browse-load" v-if="isLoading">{{$L('加载中...')}}</div>
<div class="browse-list" :class="httpType==='input'?'browse-list-disabled':''" ref="browselistbox"> <div class="browse-list" :class="httpType==='input'?'browse-list-disabled':''" ref="browselistbox">
<div v-if="browseList.length <= 0">{{$L('无内容')}}</div> <div v-if="browseList.length <= 0">{{$L('无内容')}}</div>
<div class="browse-item" v-for="item in browseList" @click="browseItem(item)"> <div v-else class="browse-item" v-for="item in browseList" @click="browseItem(item)">
<Icon v-if="item.active" class="browse-icon" type="ios-checkmark-circle"></Icon> <Icon v-if="item.active" class="browse-icon" type="ios-checkmark-circle"></Icon>
<div class="browse-img" v-bind:style="{ 'background-image': 'url(' + item.thumb + ')' }"></div> <div class="browse-img" v-bind:style="{ 'background-image': 'url(' + item.thumb + ')' }"></div>
<div class="browse-title">{{item.title}}</div> <div class="browse-title">{{item.title}}</div>

View File

@ -354,6 +354,15 @@
return /^1([3456789])\d{9}$/.test(str); return /^1([3456789])\d{9}$/.test(str);
}, },
/**
* 检测邮箱地址格式
* @param email
* @returns {boolean}
*/
isEmail(email) {
return /^[a-z0-9][a-z\.0-9-_]+@[a-z0-9_-]+(?:\.[a-z]{0,3}\.[a-z]{0,2}|\.[a-z]{0,3}|\.[a-z]{0,2})$/.test(email);
},
/** /**
* 根据两点间的经纬度计算距离 * 根据两点间的经纬度计算距离
* @param lng1 * @param lng1

View File

@ -277,6 +277,20 @@ export default {
onLogin() { onLogin() {
this.chackServerUrl(true).then(() => { this.chackServerUrl(true).then(() => {
if (!$A.isEmail(this.email)) {
$A.messageWarning("请输入正确的邮箱地址");
return;
}
if (!this.password) {
$A.messageWarning("请输入密码");
return;
}
if (this.loginType == 'reg') {
if (this.password != this.password2) {
$A.messageWarning("确认密码输入不一致");
return;
}
}
this.loadIng++; this.loadIng++;
this.$store.dispatch("call", { this.$store.dispatch("call", {
url: 'users/login', url: 'users/login',
@ -284,7 +298,6 @@ export default {
type: this.loginType, type: this.loginType,
email: this.email, email: this.email,
password: this.password, password: this.password,
password2: this.password2,
code: this.code, code: this.code,
invite: this.invite, invite: this.invite,
}, },
@ -298,7 +311,7 @@ export default {
}); });
}).catch(({data, msg}) => { }).catch(({data, msg}) => {
this.loadIng--; this.loadIng--;
$A.modalError(this.$L(msg)); $A.modalError(msg);
if (data.code === 'need') { if (data.code === 'need') {
this.reCode(); this.reCode();
this.codeNeed = true; this.codeNeed = true;

View File

@ -74,7 +74,7 @@ const Drawio = () => import('../../../components/Drawio');
export default { export default {
name: "FileContent", name: "FileContent",
components: {AceEditor, TEditor, MDEditor, OnlyOffice,Drawio}, components: {AceEditor, TEditor, MDEditor, OnlyOffice, Drawio},
props: { props: {
value: { value: {
type: Boolean, type: Boolean,

View File

@ -24,12 +24,19 @@
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" ref="dialogWrapper"> <ul
v-if="tabActive==='dialog'"
ref="dialogWrapper"
class="dialog" >
<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},{top:dialog.top === 1}]" :class="{
top: dialog.top_at,
active: dialog.id == dialogId,
operate: dialog.id == topOperateItem.id && topOperateVisible,
}"
@click="openDialog(dialog, true)" @click="openDialog(dialog, true)"
@contextmenu.prevent.stop="handleRightClick($event, dialog)"> @contextmenu.prevent.stop="handleRightClick($event, dialog)">
<template v-if="dialog.type=='group'"> <template v-if="dialog.type=='group'">
@ -72,17 +79,11 @@
:visible="topOperateVisible" :visible="topOperateVisible"
transfer-class-name="page-file-dropdown-menu" transfer-class-name="page-file-dropdown-menu"
@on-clickoutside="handleClickTopOperateOutside" @on-clickoutside="handleClickTopOperateOutside"
@on-visible-change="handleVisibleTopOperate"
transfer> transfer>
<DropdownMenu slot="list"> <DropdownMenu slot="list">
<template v-if="topOperateItem.id"> <DropdownItem @click.native="handleTopClick">
<DropdownItem v-if="topOperateItem.top === 1" @click.native="handleTopClick"> {{ $L(topOperateItem.top_at ? '取消置顶' : '置顶该聊天') }}
{{ $L('取消置顶') }} </DropdownItem>
</DropdownItem>
<DropdownItem v-if="topOperateItem.top === 0" @click.native="handleTopClick">
{{ $L('置顶该聊天') }}
</DropdownItem>
</template>
</DropdownMenu> </DropdownMenu>
</Dropdown> </Dropdown>
</div> </div>
@ -135,15 +136,10 @@ export default {
contactsData: null, contactsData: null,
contactsCurrentPage: 1, contactsCurrentPage: 1,
contactsHasMorePages: false, contactsHasMorePages: false,
topOperateStyles: {
top: 0, topOperateStyles: {},
left: 0,
},
topOperateVisible: false, topOperateVisible: false,
topOperateItem: {}, topOperateItem: {},
scrollY: 0
} }
}, },
@ -158,7 +154,7 @@ 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) { if (a.top_at || b.top_at) {
return $A.Date(b.top_at) - $A.Date(a.top_at); return $A.Date(b.top_at) - $A.Date(a.top_at);
} }
return $A.Date(b.last_at) - $A.Date(a.last_at); return $A.Date(b.last_at) - $A.Date(a.last_at);
@ -194,7 +190,7 @@ export default {
} }
return true; return true;
}).sort((a, b) => { }).sort((a, b) => {
if (a.top || b.top) { if (a.top_at || b.top_at) {
return $A.Date(b.top_at) - $A.Date(a.top_at); return $A.Date(b.top_at) - $A.Date(a.top_at);
} }
return $A.Date(b.last_at) - $A.Date(a.last_at); return $A.Date(b.last_at) - $A.Date(a.last_at);
@ -240,8 +236,7 @@ export default {
this.$store.state.dialogOpenId = id; this.$store.state.dialogOpenId = id;
}, },
dialogOpenId(id) { dialogOpenId(id) {
if ( id > 0 ) if (id > 0) this.dialogId = id;
this.dialogId = id;
}, },
contactsKey(val) { contactsKey(val) {
setTimeout(() => { setTimeout(() => {
@ -266,7 +261,6 @@ export default {
} }
break; break;
} }
this.scrollY = res.scrollY;
this.topOperateVisible = false; this.topOperateVisible = false;
}, },
@ -313,7 +307,7 @@ export default {
}, },
filterDialog(dialog) { filterDialog(dialog) {
if (dialog.unread > 0 || dialog.id == this.dialogId || dialog.top === 1) { if (dialog.unread > 0 || dialog.id == this.dialogId || dialog.top_at) {
return true return true
} }
if (dialog.name === undefined) { if (dialog.name === undefined) {
@ -446,31 +440,25 @@ export default {
} }
}) })
}, },
handleRightClick(event, item) { handleRightClick(event, item) {
this.handleClickTopOperateOutside();
this.topOperateItem = $A.isJson(item) ? item : {}; this.topOperateItem = $A.isJson(item) ? item : {};
if (this.topOperateVisible) {
this.handleClickTopOperateOutside();
}
this.dialogId = this.topOperateItem.id;
this.scrollIntoActive(true);
this.$nextTick(() => { this.$nextTick(() => {
const dialogWrap = this.$refs.dialogWrapper; const dialogWrap = this.$refs.dialogWrapper;
const dialogBounding = dialogWrap.getBoundingClientRect(); const dialogBounding = dialogWrap.getBoundingClientRect();
this.topOperateStyles = { this.topOperateStyles = {
left: `${event.clientX - dialogBounding.left}px`, left: `${event.clientX - dialogBounding.left}px`,
top: `${event.clientY - dialogBounding.top + 100 - this.scrollY}px` top: `${event.clientY - dialogBounding.top + 100 - this.$refs.list.scrollInfo().scrollY}px`
}; };
this.topOperateVisible = true; this.topOperateVisible = true;
}) })
}, },
handleClickTopOperateOutside() { handleClickTopOperateOutside() {
this.topOperateVisible = false; this.topOperateVisible = false;
}, },
handleVisibleTopOperate(visible) {
if (visible && this.topOperateItem.id) {
this.$set(this.topOperateItem, '_highlight', true);
}
},
handleTopClick() { handleTopClick() {
this.$store.dispatch("call", { this.$store.dispatch("call", {
url: 'dialog/top', url: 'dialog/top',

View File

@ -1828,8 +1828,7 @@ export default {
reject({msg: 'Parameter error'}); reject({msg: 'Parameter error'});
return; return;
} }
// 先重置dialogOpenId否者无法重复打开相同对话 state.dialogOpenId = 0; // 先重置dialogOpenId否者无法重复打开相同对话
state.dialogOpenId = 0;
dispatch("call", { dispatch("call", {
url: 'dialog/open/user', url: 'dialog/open/user',
data: { data: {

View File

@ -84,10 +84,12 @@
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: flex-start; align-items: flex-start;
padding: 16px 12px; padding: 14px 10px;
position: relative; position: relative;
cursor: pointer; cursor: pointer;
list-style: none; list-style: none;
margin-right: 1px;
border: 2px solid transparent;
.user-avatar, .user-avatar,
.icon-avatar { .icon-avatar {
width: 42px; width: 42px;
@ -195,6 +197,9 @@
&.active { &.active {
background-color: #F4F5F7; background-color: #F4F5F7;
} }
&.operate {
border-color: $primary-color;
}
&.loading { &.loading {
margin: 0; margin: 0;
height: 52px; height: 52px;
@ -262,21 +267,11 @@
} }
} }
.top-operate { .top-operate {
opacity: 0;
position: absolute; position: absolute;
top: 2px; top: 0;
right: 2px; right: 0;
transition: opacity 0.2s; opacity: 0;
display: flex; 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 {
@ -392,23 +387,6 @@
} }
} }
} }
.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;
}
}
}
} }
} }
} }