perf: 优化删除成员

This commit is contained in:
kuaifan 2022-07-16 16:22:05 +08:00
parent 29ba6713f0
commit fa1c917b97
8 changed files with 205 additions and 47 deletions

View File

@ -382,7 +382,7 @@ class UsersController extends AbstractController
*/
public function search()
{
$builder = User::select(['userid', 'email', 'nickname', 'profession', 'userimg', 'az', 'pinyin', 'line_at', 'disable_at']);
$builder = User::select(User::$basicField);
//
$keys = Request::input('keys');
$sorts = Request::input('sorts');
@ -455,6 +455,8 @@ class UsersController extends AbstractController
*/
public function basic()
{
User::auth();
//
$userid = Request::input('userid');
$array = Base::json2array($userid);
if (empty($array)) {
@ -466,6 +468,9 @@ class UsersController extends AbstractController
$retArray = [];
foreach ($array AS $id) {
$basic = User::userid2basic($id);
if (empty($basic)) {
$basic = UserDelete::userid2basic($id);
}
if ($basic) {
$retArray[] = $basic;
}
@ -576,7 +581,7 @@ class UsersController extends AbstractController
* - clearadmin 取消管理员
* - setdisable 设为离职(需要参数 disable_time、transfer_userid
* - cleardisable 取消离职
* - delete 删除会员
* - delete 删除会员(需要参数 delete_reason
* @apiParam {String} [email] 邮箱地址
* @apiParam {String} [tel] 联系电话
* @apiParam {String} [password] 新的密码
@ -584,6 +589,7 @@ class UsersController extends AbstractController
* @apiParam {String} [profession] 职位
* @apiParam {String} [disable_time] 离职时间
* @apiParam {String} [transfer_userid] 离职交接人
* @apiParam {String} [delete_reason] 删除原因
*
* @apiSuccess {Number} ret 返回状态码1正确、0错误
* @apiSuccess {String} msg 返回信息(错误描述)
@ -644,7 +650,10 @@ class UsersController extends AbstractController
if ($userInfo->userid === $user->userid) {
return Base::retError('不能删除自己');
}
$userInfo->deleteUser();
if (empty($data['delete_reason'])) {
return Base::retError('请填写删除原因');
}
$userInfo->deleteUser($data['delete_reason']);
break;
}
if (isset($upArray['identity'])) {
@ -1119,13 +1128,7 @@ class UsersController extends AbstractController
}
}
if ($type == 'confirm') {
$deleteArr = [
'userid' => $user->userid,
'email' => $user->email,
'reason' => $reason
];
$userDelete = UserDelete::createInstance($deleteArr);
if ($userDelete->save() && $user->deleteUser()) {
if ($user->deleteUser($reason)) {
return Base::retSuccess('删除成功', $user);
} else {
return Base::retError('删除失败');

View File

@ -71,7 +71,11 @@ class User extends AbstractModel
'updated_at',
];
protected $defaultAvatarMode = 'auto'; // auto自动生成system系统默认
// 默认头像类型auto自动生成system系统默认
public static $defaultAvatarMode = 'auto';
// 基本信息的字段
public static $basicField = ['userid', 'email', 'nickname', 'profession', 'userimg', 'az', 'pinyin', 'line_at', 'disable_at'];
/**
* 更新数据校验
@ -104,9 +108,9 @@ class User extends AbstractModel
public function getUserimgAttribute($value)
{
if ($value && !str_contains($value, 'avatar/')) {
// 自定义头像
return Base::fillUrl($value);
}
if ($this->defaultAvatarMode === 'auto') {
} else if (self::$defaultAvatarMode === 'auto') {
// 自动生成头像
return url("avatar/" . urlencode($this->nickname) . ".png");
} else {
@ -182,12 +186,30 @@ class User extends AbstractModel
/**
* 删除会员
* @param $reason
* @return bool|null
*/
public function deleteUser()
public function deleteUser($reason)
{
UserEmailVerification::whereEmail($this->email)->delete();
return $this->delete();
return AbstractModel::transaction(function () use ($reason) {
// 删除原因
$userDelete = UserDelete::createInstance([
'operator' => User::userid(),
'userid' => $this->userid,
'email' => $this->email,
'reason' => $reason,
'cache' => $this->getRawOriginal()
]);
$userDelete->save();
// 删除未读
WebSocketDialogMsgRead::whereUserid($this->userid)->delete();
// 删除待办
WebSocketDialogMsgTodo::whereUserid($this->userid)->delete();
// 删除邮箱验证记录
UserEmailVerification::whereEmail($this->email)->delete();
//
return $this->delete();
});
}
/** ***************************************************************************************** */
@ -436,8 +458,7 @@ class User extends AbstractModel
if (isset($_A["__static_userid2basic_" . $userid])) {
return $_A["__static_userid2basic_" . $userid];
}
$fields = ['userid', 'email', 'nickname', 'profession', 'userimg', 'az', 'pinyin', 'line_at', 'disable_at'];
$userInfo = self::whereUserid($userid)->select($fields)->first();
$userInfo = self::whereUserid($userid)->select(User::$basicField)->first();
if ($userInfo) {
$userInfo->online = $userInfo->getOnlineStatus();
}

View File

@ -3,22 +3,27 @@
namespace App\Models;
use App\Module\Base;
/**
* App\Models\UserDelete
*
* @property int $id
* @property int|null $operator 操作人员
* @property int|null $userid 用户id
* @property string|null $email 邮箱
* @property string|null $email 邮箱
* @property string|null $reason 注销原因
* @property string|null $cache 会员资料缓存
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @method static \Illuminate\Database\Eloquent\Builder|UserDelete newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|UserDelete newQuery()
* @method static \Illuminate\Database\Eloquent\Builder|UserDelete query()
* @method static \Illuminate\Database\Eloquent\Builder|UserDelete whereCache($value)
* @method static \Illuminate\Database\Eloquent\Builder|UserDelete whereCreatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|UserDelete whereEmail($value)
* @method static \Illuminate\Database\Eloquent\Builder|UserDelete whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder|UserDelete whereOperator($value)
* @method static \Illuminate\Database\Eloquent\Builder|UserDelete whereReason($value)
* @method static \Illuminate\Database\Eloquent\Builder|UserDelete whereUpdatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|UserDelete whereUserid($value)
@ -26,5 +31,46 @@ namespace App\Models;
*/
class UserDelete extends AbstractModel
{
/**
* 昵称
* @param $value
* @return string
*/
public function getCacheAttribute($value)
{
if (!is_array($value)) {
$value = Base::json2array($value);
// 昵称
if (!$value['nickname']) {
$value['nickname'] = Base::cardFormat($value['email']);
}
// 头像
if ($value['userimg'] && !str_contains($value['userimg'], 'avatar/')) {
$value['userimg'] = Base::fillUrl($value['userimg']);
} else if (User::$defaultAvatarMode === 'auto') {
$value['userimg'] = url("avatar/" . urlencode($value['nickname']) . ".png");
} else {
$name = ($value['userid'] - 1) % 21 + 1;
$value['userimg'] = url("images/avatar/default_{$name}.png");
}
}
return $value;
}
/**
* userid 获取 基础信息
* @param int $userid 会员ID
* @return array|null
*/
public static function userid2basic($userid)
{
$row = self::whereUserid($userid)->first();
if (empty($row) || empty($row->cache)) {
return null;
}
$cache = $row->cache;
$cache = array_intersect_key($cache, array_flip(User::$basicField));
$cache['delete_at'] = $row->created_at->format($row->dateFormat ?: 'Y-m-d H:i:s');
return $cache;
}
}

View File

@ -0,0 +1,34 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddUserDeletesOperator extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('user_deletes', function (Blueprint $table) {
if (!Schema::hasColumn('user_deletes', 'operator')) {
$table->bigInteger('operator')->nullable()->default(0)->after('id')->comment('操作人员');
}
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('user_deletes', function (Blueprint $table) {
$table->dropColumn("operator");
});
}
}

View File

@ -0,0 +1,34 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddUserDeletesCache extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('user_deletes', function (Blueprint $table) {
if (!Schema::hasColumn('user_deletes', 'cache')) {
$table->text('cache')->after('reason')->nullable()->default('')->comment('会员资料缓存');
}
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('user_deletes', function (Blueprint $table) {
$table->dropColumn("cache");
});
}
}

View File

@ -7,9 +7,10 @@
:placement="tooltipPlacement">
<div slot="content" class="common-avatar-transfer">
<slot/>
<p>{{$L('昵称')}}: {{user.nickname}}</p>
<p>{{$L('昵称')}}: {{user.nickname}}<em v-if="user.delete_at" class="deleted no-dark-content">{{$L('已删除')}}</em><em v-else-if="user.disable_at" class="disabled no-dark-content">{{$L('已离职')}}</em></p>
<p>{{$L('职位/职称')}}: {{user.profession || '-'}}</p>
<p v-if="user.disable_at"><strong>{{$L('离职时间')}}: {{user.disable_at}}</strong></p>
<p v-if="user.delete_at"><strong>{{$L('删除时间')}}: {{user.delete_at}}</strong></p>
<p v-else-if="user.disable_at"><strong>{{$L('离职时间')}}: {{user.disable_at}}</strong></p>
<slot name="end"/>
<div v-if="userId != userid && showIconMenu" class="avatar-icons">
<Icon type="ios-chatbubbles" @click="openDialog"/>
@ -27,7 +28,6 @@
</div>
<template v-if="showName">
<div class="avatar-name" :style="nameStyle">{{user.nickname}}</div>
<div v-if="user.disable_at" class="avatar-disable">{{$L('离职')}}</div>
</template>
</div>
</ETooltip>
@ -118,7 +118,8 @@
return {
'avatar-box': true,
'online': this.userId === this.userid || this.user.online,
'disable': this.user.disable_at
'disabled': this.user.disable_at,
'deleted': this.user.delete_at
}
},
@ -145,13 +146,16 @@
nameStyle() {
const {showIcon} = this;
const {delete_at, disable_at} = this.user
const styles = {}
if (!showIcon) {
return {
paddingLeft: 0
}
} else {
return {}
styles.paddingLeft = 0
}
if (delete_at || disable_at) {
styles.opacity = 0.8
styles.textDecoration = "line-through"
}
return styles
},
avatarSize() {

View File

@ -484,16 +484,21 @@ export default {
break;
case 'delete':
$A.modalConfirm({
content: `你确定要删除帐号【ID:${row.userid}${row.nickname}】吗?`,
loading: true,
onOk: () => {
$A.modalInput({
title: `删除帐号【ID:${row.userid}${row.nickname}`,
placeholder: "请输入删除原因",
okText: "确定删除",
onOk: (value) => {
if (!value) {
return '删除原因不能为空'
}
return this.operationUser({
userid: row.userid,
type: name,
delete_reason: value
});
}
});
})
break;
default:

View File

@ -43,7 +43,8 @@
background-color: $primary-color;
}
}
&.disable {
&.disabled,
&.deleted {
&:after {
content: "";
position: absolute;
@ -56,6 +57,11 @@
border-radius: 50%;
}
}
&.deleted {
&:after {
transform: rotate(-45deg);
}
}
}
.avatar-name {
padding-left: 6px;
@ -63,19 +69,6 @@
text-overflow: ellipsis;
white-space: nowrap;
}
.avatar-disable {
margin-left: 2px;
white-space: nowrap;
font-size: 12px;
height: 20px;
line-height: 20px;
padding: 0 6px;
border-radius: 3px;
transform: scale(0.9);
transform-origin: right center;
color: #ffffff;
background-color: #ED4014;
}
}
}
.common-avatar-transfer {
@ -83,6 +76,24 @@
line-height: 1.5;
> p {
padding: 1px 2px;
> em {
font-style: normal;
&.disabled,
&.deleted {
display: inline-block;
margin-left: 2px;
white-space: nowrap;
font-size: 12px;
height: 20px;
line-height: 20px;
padding: 0 6px;
border-radius: 3px;
transform: scale(0.9);
transform-origin: right center;
color: #ffffff;
background-color: #ED4014;
}
}
}
.avatar-icons {
margin-top: 12px;