549 lines
18 KiB
PHP
549 lines
18 KiB
PHP
<?php
|
||
|
||
namespace app\models;
|
||
|
||
use app\models\Model;
|
||
use app\modules\api\components\ApiHelper;
|
||
use function PHPSTORM_META\type;
|
||
use Yii;
|
||
use yii\web\IdentityInterface;
|
||
use app\components\FlashStorage;
|
||
use app\components\EncryptHelper;
|
||
use app\components\SysConst;
|
||
use app\models\auth\RoleUser;
|
||
use app\models\auth\RolePermission;
|
||
use app\models\integral\Integral;
|
||
use Gumlet\ImageResize;
|
||
use Gumlet\ImageResizeException;
|
||
|
||
/**
|
||
* This is the model class for table "{{%user}}".
|
||
*
|
||
* @property int $id ID
|
||
* @property int $cx_mch_id 平台商户ID
|
||
* @property string $username 用户名
|
||
* @property string $password 密码
|
||
* @property string $auth_key AUTH_KEY
|
||
* @property string $access_token ACCESS_TOKEN
|
||
* @property string $nickname 昵称
|
||
* @property string $avatar_url 头像
|
||
* @property string|null $mobile_phone 手机号
|
||
* @property string|null $mobile_prefix 手机号国家代码
|
||
* @property string|null $email 邮箱
|
||
* @property string|null $real_name 真实姓名
|
||
* @property string|null $desc 个性签名
|
||
* @property int $gender 性别,0=女,1=男,2=保密
|
||
* @property string|null $birthday 生日
|
||
* @property int $status 状态,0=正常,1=封禁,2=挂起,3=注销
|
||
* @property int $parent_id PARENT_ID
|
||
* @property int $is_modify_un 用户名是否可以修改,0=否,1=是
|
||
* @property int $is_delete 是否删除,0=否,1=是
|
||
* @property int $country_id 国家ID
|
||
* @property int $city_id 城市ID
|
||
* @property int $created_at 添加时间
|
||
* @property int $updated_at 更新时间
|
||
* @property int $type 0=用户,1=管理员
|
||
* @property int $is_view 是否有观看视频
|
||
* @property int|null $level_id 用户等级
|
||
* @property float|null $level_exp 升级经验
|
||
*/
|
||
class User extends \yii\db\ActiveRecord implements IdentityInterface
|
||
{
|
||
const STATUS_NORMAL = 0;
|
||
const STATUS_FORBIDDEN = 1;
|
||
const STATUS_HANGUP = 2;
|
||
const STATUS_ACCOUNT_LOGOUT = 3;
|
||
|
||
const IS_YES = 1;
|
||
const IS_NO = 0;
|
||
|
||
const GENDER_UNKNOWN = 0;
|
||
const GENDER_MAN = 1;
|
||
const GENDER_WOMEN = 2;
|
||
const GENDER_SECRET = 3;
|
||
|
||
const TYPE_USER = 0;
|
||
const TYPE_ADMIN = 1;
|
||
const TYPE_STORE = 2;
|
||
const TYPE_COACH = 3;
|
||
const TYPE_STAFF = 6; //员工
|
||
const TYPE_BOSS_STAFF = 7; //boss员工
|
||
const TYPE_ADMIN_STAFF = 8; //总部管理员
|
||
|
||
|
||
const DEFAULT_AVATAR_URL = '/statics/images/avatar.jpg';
|
||
|
||
/**
|
||
* {@inheritdoc}
|
||
*/
|
||
public static function tableName()
|
||
{
|
||
return '{{%user}}';
|
||
}
|
||
|
||
/**
|
||
* {@inheritdoc}
|
||
*/
|
||
public function rules()
|
||
{
|
||
return [
|
||
[['username', 'password', 'auth_key', 'access_token', 'nickname', 'email', 'real_name', 'avatar_url', 'mobile_phone', 'mobile_prefix'], 'trim'],
|
||
[['cx_mch_id', 'gender', 'status', 'parent_id', 'is_modify_un', 'is_delete', 'country_id', 'city_id', 'created_at', 'updated_at', 'type', 'is_view','level_id'], 'integer'],
|
||
[['username', 'password', 'auth_key', 'access_token', 'nickname', 'avatar_url'], 'required'],
|
||
[['birthday'], 'safe'],
|
||
[['level_exp'], 'number'],
|
||
[['username', 'desc'], 'string', 'max' => 64],
|
||
[['password', 'auth_key', 'access_token', 'nickname', 'email', 'real_name'], 'string', 'max' => 256],
|
||
[['avatar_url'], 'string', 'max' => 2048],
|
||
[['mobile_phone'], 'string', 'max' => 128],
|
||
[['mobile_prefix'], 'string', 'max' => 16],
|
||
[['username'], 'unique'],
|
||
];
|
||
}
|
||
|
||
/**
|
||
* {@inheritdoc}
|
||
*/
|
||
public function attributeLabels()
|
||
{
|
||
return [
|
||
'id' => 'ID',
|
||
'cx_mch_id' => '平台商户ID',
|
||
'username' => '用户名',
|
||
'password' => '密码',
|
||
'auth_key' => 'AUTH_KEY',
|
||
'access_token' => 'ACCESS_TOKEN',
|
||
'nickname' => '昵称',
|
||
'avatar_url' => '头像',
|
||
'mobile_phone' => '手机号',
|
||
'mobile_prefix' => '手机号国家代码',
|
||
'email' => '邮箱',
|
||
'real_name' => '真实姓名',
|
||
'desc' => '个性签名',
|
||
'gender' => '性别,0=女,1=男,2=保密',
|
||
'birthday' => '生日',
|
||
'status' => '状态,0=正常,1=封禁,2=挂起,3=注销',
|
||
'parent_id' => 'PARENT_ID',
|
||
'is_modify_un' => '用户名是否可以修改,0=否,1=是',
|
||
'is_delete' => '是否删除,0=否,1=是',
|
||
'country_id' => '国家ID',
|
||
'city_id' => '城市ID',
|
||
'created_at' => '添加时间',
|
||
'updated_at' => '更新时间',
|
||
'type' => '0=普通用户,1=管理员',
|
||
'is_view' => '是否有观看视频',
|
||
'level_id' => '会员等级',
|
||
'level_exp' => '升级经验',
|
||
];
|
||
}
|
||
|
||
|
||
public function beforeSave($insert)
|
||
{
|
||
if (parent::beforeSave($insert)) {
|
||
if ($this->isNewRecord) {
|
||
$this->created_at = time();
|
||
}
|
||
$this->updated_at = time();
|
||
$this->htmlTagFilter();
|
||
return true;
|
||
} else {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
public function htmlTagFilter()
|
||
{
|
||
$this->nickname = Model::htmlTagFilter($this->nickname);
|
||
$this->username = Model::htmlTagFilter($this->username);
|
||
$this->desc = Model::htmlTagFilter($this->desc);
|
||
$this->real_name = Model::htmlTagFilter($this->real_name);
|
||
$this->email = Model::htmlTagFilter($this->email);
|
||
}
|
||
|
||
|
||
/**
|
||
* Validates password
|
||
*
|
||
* @param string $password password to validate
|
||
* @return boolean if password provided is valid for current user
|
||
*/
|
||
public function validatePassword($password)
|
||
{
|
||
return Yii::$app->security->validatePassword($password, $this->password);
|
||
}
|
||
|
||
/**
|
||
* Generates password hash from password and sets it to the model
|
||
*
|
||
* @param string $password
|
||
*/
|
||
public function setPassword($password)
|
||
{
|
||
$this->password = Yii::$app->security->generatePasswordHash($password);
|
||
}
|
||
|
||
/**
|
||
* Finds an identity by the given ID.
|
||
* @param string|int $id the ID to be looked for
|
||
* @return IdentityInterface the identity object that matches the given ID.
|
||
* Null should be returned if such an identity cannot be found
|
||
* or the identity is not in an active state (disabled, deleted, etc.)
|
||
*/
|
||
public static function findIdentity($id)
|
||
{
|
||
return static::findOne([
|
||
'id' => $id,
|
||
'is_delete' => 0,
|
||
'status' => self::STATUS_NORMAL,
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* Finds an identity by the given token.
|
||
* @param mixed $token the token to be looked for
|
||
* @param mixed $type the type of the token. The value of this parameter depends on the implementation.
|
||
* For example, [[\yii\filters\auth\HttpBearerAuth]] will set this parameter to be `yii\filters\auth\HttpBearerAuth`.
|
||
* @return IdentityInterface the identity object that matches the given token.
|
||
* Null should be returned if such an identity cannot be found
|
||
* or the identity is not in an active state (disabled, deleted, etc.)
|
||
*/
|
||
public static function findIdentityByAccessToken($token, $type = null)
|
||
{
|
||
$user_token = UserToken::find()
|
||
->where([
|
||
'is_delete' => 0,
|
||
'token' => $token,
|
||
'cx_mch_id' => Model::getCxMchId()
|
||
])
|
||
->andFilterWhere([
|
||
'type' => $type,
|
||
])->one();
|
||
if ($user_token && $user_token->expire_time > time()) {
|
||
return static::findOne([
|
||
'id' => $user_token->user_id,
|
||
'is_delete' => 0,
|
||
'status' => self::STATUS_NORMAL,
|
||
]);
|
||
}
|
||
return static::findOne([
|
||
'id' => 0,
|
||
'is_delete' => 0,
|
||
'status' => self::STATUS_NORMAL,
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* Returns an ID that can uniquely identify a user identity.
|
||
* @return string|int an ID that uniquely identifies a user identity.
|
||
*/
|
||
public function getId()
|
||
{
|
||
return $this->id;
|
||
}
|
||
|
||
/**
|
||
* Returns a key that can be used to check the validity of a given identity ID.
|
||
*
|
||
* The key should be unique for each individual user, and should be persistent
|
||
* so that it can be used to check the validity of the user identity.
|
||
*
|
||
* The space of such keys should be big enough to defeat potential identity attacks.
|
||
*
|
||
* This is required if [[User::enableAutoLogin]] is enabled.
|
||
* @return string a key that is used to check the validity of a given identity ID.
|
||
* @see validateAuthKey()
|
||
*/
|
||
public function getAuthKey()
|
||
{
|
||
return $this->auth_key;
|
||
}
|
||
|
||
/**
|
||
* Validates the given auth key.
|
||
*
|
||
* This is required if [[User::enableAutoLogin]] is enabled.
|
||
* @param string $authKey the given auth key
|
||
* @return bool whether the given auth key is valid.
|
||
* @see getAuthKey()
|
||
*/
|
||
public function validateAuthKey($authKey)
|
||
{
|
||
return $this->getAuthKey() === $authKey;
|
||
}
|
||
|
||
//是否已经绑定手机号
|
||
public function getIsBindPhone()
|
||
{
|
||
return true;
|
||
$mobile = empty($this->mobile_phone) ? null : EncryptHelper::decryptMobilePhone($this->mobile_phone);
|
||
return $mobile ? true : false;
|
||
}
|
||
|
||
//是否绑定微信小程序登录
|
||
public function getBindWxmp()
|
||
{
|
||
return $this->hasOne(UserOauth::className(), ['user_id' => 'id'])->where(['type' => SysConst::$cxOauthProviderWxmp, 'is_delete' => 0, 'cx_mch_id' => 0]);
|
||
}
|
||
|
||
//账户余额
|
||
public function getBalance()
|
||
{
|
||
// $cx_mch_id = Model::getCxMchId();
|
||
return $this->hasOne(Balance::className(), ['user_id' => 'id'])->where(['is_delete' => 0, 'scene' => Balance::$cxBalanceSceneUserWallet, 'cx_mch_id' => 0]);
|
||
}
|
||
|
||
//账户积分
|
||
public function getIntegral()
|
||
{
|
||
// $cx_mch_id = Model::getCxMchId();
|
||
return $this->hasOne(Integral::className(), ['user_id' => 'id'])->where(['is_delete' => 0, 'scene' => Integral::$cxIntegralSceneUserIntegralWallet, 'cx_mch_id' => 0]);
|
||
}
|
||
|
||
|
||
public static function getGender($gender)
|
||
{
|
||
$labels = self::genderLabels();
|
||
return isset($labels[$gender]) ? $labels[$gender] : "未知";
|
||
}
|
||
|
||
public static function genderLabels()
|
||
{
|
||
return [
|
||
'0' => '未知',
|
||
'1' => '男',
|
||
'2' => '女',
|
||
'3' => '保密'
|
||
];
|
||
}
|
||
|
||
public static function getStatus($status)
|
||
{
|
||
$labels = self::statusLabels();
|
||
return isset($labels[$status]) ? $labels[$status] : "未知";
|
||
}
|
||
|
||
public static function statusLabels()
|
||
{
|
||
return [
|
||
'0' => '正常',
|
||
'1' => '封禁',
|
||
'2' => '挂起',
|
||
'3' => '注销',
|
||
];
|
||
}
|
||
|
||
public static function lastLogin($user_id, $is_pass = 1, $err_msg = null, $cx_mch_id = 0)
|
||
{
|
||
return log\UserLoginLog::logger($user_id, $is_pass, $err_msg, $cx_mch_id);
|
||
}
|
||
|
||
public static function typeLabels()
|
||
{
|
||
return [
|
||
'0' => '普通用户',
|
||
'1' => '管理员',
|
||
'2' => '员工',
|
||
];
|
||
}
|
||
|
||
public static function getType($type)
|
||
{
|
||
$labels = self::typeLabels();
|
||
return isset($labels[$type]) ? $labels[$type] : "未知";
|
||
}
|
||
|
||
|
||
//生成一个用户名
|
||
public static function generateUsername($retry = 3, $prefix = "U", $len = 6)
|
||
{
|
||
$cache_key = "u_g_u";
|
||
$cache_val = FlashStorage::getCache($cache_key);
|
||
if ($cache_val !== false) {
|
||
sleep(1);
|
||
$retry -= 1;
|
||
return $retry > 0 ? self::generateUsername($retry, $prefix) : null;
|
||
}
|
||
FlashStorage::setCache($cache_key, $cache_key);
|
||
$username = null;
|
||
while (true) {
|
||
$username = self::_generate($prefix, $len);
|
||
$exists = User::find()->where(['username' => $username])->exists();
|
||
if (!$exists) {
|
||
FlashStorage::deleteCache($cache_key);
|
||
break;
|
||
}
|
||
}
|
||
return $username;
|
||
}
|
||
|
||
//生成一个昵称
|
||
public static function generateNickname($retry = 3, $prefix = "HY_", $len = 8)
|
||
{
|
||
$cache_key = "u_g_ns";
|
||
$cache_val = FlashStorage::getCache($cache_key);
|
||
if ($cache_val !== false) {
|
||
sleep(1);
|
||
$retry -= 1;
|
||
return $retry > 0 ? self::generateNickname($retry, $prefix) : null;
|
||
}
|
||
FlashStorage::setCache($cache_key, $cache_key);
|
||
$nickname = null;
|
||
while (true) {
|
||
$nickname = self::_generate($prefix, $len);
|
||
$exists = User::find()->where(['nickname' => $nickname])->exists();
|
||
if (!$exists) {
|
||
FlashStorage::deleteCache($cache_key);
|
||
break;
|
||
}
|
||
}
|
||
return $nickname;
|
||
}
|
||
|
||
public static function _generate($prefix, $len)
|
||
{
|
||
$username = $prefix;
|
||
$chars = "qwertyuiopasdfghjklzxcvbnm1234567890MNBVCXZASDFGHJKLPIUIYTREWQ";
|
||
$max = strlen($chars) - 1;
|
||
for ($i = strlen($username); $i < $len; $i++) {
|
||
$start = mt_rand(0, $max);
|
||
$username .= $chars[$start];
|
||
}
|
||
//并发情况生成唯一username
|
||
$cache_key = "u_g_un_{$username}";
|
||
$cache_val = FlashStorage::getCache($cache_key);
|
||
if ($cache_val !== false) {
|
||
usleep(500);
|
||
return self::_generate($prefix, $len);
|
||
}
|
||
FlashStorage::setCache($cache_key, $cache_key, 60);
|
||
return $username;
|
||
}
|
||
|
||
/**
|
||
* 绑定状态
|
||
* @param object $user 用户
|
||
* @param array $data $data['data]
|
||
*/
|
||
public static function bindQuery($user, $data)
|
||
{
|
||
$data['data'] = isset($data['data']) ? $data['data'] : [];
|
||
//手机是否需要绑定
|
||
$data['data']['required_bind_phone'] = \Yii::$app->params['requiredBindMobilePhone'];
|
||
$data['data']['is_bind_phone'] = $user->isBindPhone;
|
||
//是否绑定第三方登录
|
||
$data['data']['required_bind_oauth_login'] = \Yii::$app->params['requiredOauthLogin'];
|
||
//微信小程序
|
||
$data['data']['is_bind_wxmp'] = $user->bindWxmp ? true : false;
|
||
$data['data']['user_id'] = $user->id;
|
||
// $data['data']['user_store_id'] = $user->store_id ? $user->store_id : 0;
|
||
$data['data']['user_store_id'] = $user->store_id ? $user->store_id : 1;
|
||
$data['data']['user_type'] = $user->type;
|
||
if(!in_array($user->type,[2,7,8])){
|
||
$data['data']['user_type'] = 0;
|
||
}
|
||
//门店人员身份 1-门店管理员 2-门店服务员 3-门店财务人员
|
||
if ($user->type == 2) {
|
||
$storeData = ApiHelper::findOneUserStoreId($user->id);
|
||
if(empty($storeData)){
|
||
$data['data']['store_type'] = 0;
|
||
$data['data']['store_id'] = 0;
|
||
$data['data']['user_type'] = 0;
|
||
}else{
|
||
$data['data']['store_type'] = $storeData['user_type'];
|
||
$data['data']['store_id'] = $storeData['store_id'];
|
||
}
|
||
}
|
||
return $data;
|
||
}
|
||
|
||
|
||
public function getPermissions()
|
||
{
|
||
$cx_mch_id = Model::getCxMchId();
|
||
$role_ids = $this->hasMany(RoleUser::className(), ['user_id' => 'id'])->where(['is_delete' => 0, 'cx_mch_id' => $cx_mch_id])->select('role_id')->column();
|
||
$list = RolePermission::find()
|
||
->where([
|
||
'cx_mch_id' => $cx_mch_id,
|
||
'role_id' => $role_ids,
|
||
'is_delete' => 0
|
||
])
|
||
->select('permissions')->column();
|
||
$permissions = [];
|
||
foreach ($list as $index => $item) {
|
||
$item = json_decode($item, true);
|
||
$permissions = array_merge($permissions, $item);
|
||
}
|
||
$permissions = array_unique($permissions);
|
||
return $permissions;
|
||
}
|
||
|
||
//头像处理
|
||
public static function resizeAvatar($filename, $max_width = 512, $max_height = 512)
|
||
{
|
||
$filename = trim($filename);
|
||
$filename = trim($filename, '/');
|
||
if (!file_exists($filename)) {
|
||
return Model::asReturnError("文件{$filename}不存在");
|
||
}
|
||
try {
|
||
$gumletImagic = new ImageResize($filename);
|
||
$gumletImagic->resizeToBestFit($max_width, $max_height);
|
||
$gumletImagic->save($filename);
|
||
} catch (ImageResizeException $ex) {
|
||
return Model::asReturnError($ex->getMessage());
|
||
}
|
||
return Model::asReturnSuccess('ok', ['dst_url' => "/{$filename}"]);
|
||
}
|
||
|
||
|
||
//门店
|
||
public function getStore()
|
||
{
|
||
// return $this->hasOne(Store::className(), ['user_id' => 'id'])->where(['is_delete' => 0]);
|
||
}
|
||
|
||
public function getStoreUser()
|
||
{
|
||
return $this->hasOne(StoreUser::className(), ['user_id' => 'id'])->where(['is_delete' => 0]);
|
||
}
|
||
|
||
/**
|
||
* 分销团队详情
|
||
* @param $id 当前用户id
|
||
* @return array
|
||
*/
|
||
public static function getDistrbutionTeam($id)
|
||
{
|
||
//直属下级
|
||
$down = User::find()
|
||
->select('id,username,nickname,avatar_url,mobile_phone,email,real_name,created_at')
|
||
->where(['is_delete' => 0])->andWhere(['parent_id' => $id])->asArray()->all();
|
||
$down_count = count($down);
|
||
foreach ($down as $index => &$item){
|
||
$item['down_count'] = User::find()->where(['is_delete' => 0])->andWhere(['parent_id' => $item['id']])->count();
|
||
}
|
||
return ['down' => $down,'down_count' => $down_count];
|
||
|
||
}
|
||
|
||
/**
|
||
* 分销-用户名、真实姓名、手机号搜索上级
|
||
* @param $mobile 关键字
|
||
*/
|
||
public static function getParentUser($content)
|
||
{
|
||
$mobile = EncryptHelper::encryptMobilePhone(trim($content));
|
||
$data = User::find()->select('id,nickname,avatar_url,mobile_phone')
|
||
->where(['is_delete' => 0])
|
||
->andWhere(['status' => 0])
|
||
->andWhere([
|
||
'OR',
|
||
['like','nickname',$content],
|
||
['like','mobile_phone',$mobile],
|
||
])
|
||
->asArray()->all();
|
||
return $data;
|
||
}
|
||
}
|