UploadBehavior::className(),
'attribute' => 'qrcode',
'entity' => __CLASS__
],
];
}
public function scenarios()
{
$scenarios = parent::scenarios();
return array_merge($scenarios, [
'register' => ['username', 'openid', 'password', 'email', 'tel', 'pid'],
'connect' => ['username', 'email'],
'create' => ['jucai_id', 'email', 'tel'],
'update' => ['username', 'password', 'email', 'tel', 'nickname', 'level_id', 'pid'],
'settings' => ['username', 'password', 'email', 'tel'],
'resetPassword' => ['password']
]);
}
/**
* {@inheritdoc}
*/
public function rules()
{
return [
['username', 'string', 'on' => 'search'],
['username', 'required', 'on' => 'create'],
['password', 'required', 'on' => ['register']],
[['tel'], 'match', 'pattern' => Regexp::$mobile],
[['email'], 'match', 'pattern' => Regexp::$email],
[['privilege'], 'string', 'max' => 255],
[['qrcode', 'dataCount'], 'safe'],
];
}
public function attributeLabels()
{
return [
'pid' => '上级用户',
'jucai_id' => '聚才网ID',
'username' => '用户名',//openid共用字段
'openid' => '微信ID',
'nickname' => '昵称',
'password' => '密码',
'email' => ' 绑定邮箱',
'tel' => '绑定手机',
'avatar' => '头像',
'created_at' => '注册时间',
'login_at' => '最后登录时间',
'type' => '用户类型',
'privilege' => '特权',//微信用户属性
'unionid' => '联合ID',//微信用户属性
'level_id' => '分销等级',//微信用户属性
'qrcode' => '分销码', //小程序码
'is_vip' => '是否vip', //是否vip
'vip_time' => 'vip有效期', //是否vip
'dataCount' => '数据统计',
];
}
/**
* 根据id查询用户
* {@inheritdoc}
*/
public static function findIdentity($id)
{
return static::findOne(['id' => $id, 'blocked_at' => null]);
}
/**
* 根据访问令牌查询用户
* api访问专用
* {@inheritdoc}
*/
public static function findIdentityByAccessToken($token, $type = null)
{
return static::find()->where(['access_token' => $token])->andWhere(['>', 'expired_at', time()])->one();
}
/**
* 根据用户名查询用户
*
* @param string $username
*
* @return mixed
*/
public static function findByUsername($username)
{
return static::find()->where(['username' => $username])
->andWhere(['blocked_at' => null])
->one();
}
/**
* 根据用openid查询用户
*
* @param string $openId
*
* @return mixed
*/
public static function findByOpenid($openId)
{
return static::find()->where(['openid' => $openId])
->andWhere(['blocked_at' => null])
->one();
}
/**
* 根据绑定邮箱查询用户
* @param $email
* @return array|ActiveRecord|null
* @author nodelog
*/
public static function findByEmail($email)
{
return static::find()->where(['email' => $email])
->andWhere(['blocked_at' => null])
->one();
}
/**
* 根据绑定手机号查询用户
* @param $tel
* @return array|ActiveRecord|null
* @author nodelog
*/
public static function findByTel($tel)
{
return static::find()->where(['email' => $tel])
->andWhere(['blocked_at' => null])
->one();
}
/**
* 根据用户名、邮箱、手机号查询用户
* @param $login
* @return array|ActiveRecord|null
* @author nodelog
*/
public static function findByUsernameOrEmailTel($login)
{
return static::find()->where(['or', ['username' => $login], ['email' => $login], ['tel' => $login]])
->andWhere(['blocked_at' => null])
->one();
}
/**
* 根据重置密码令牌查询用户
* Finds user by password reset token.
*
* @param string $token password reset token
*
* @return static|null
*/
public static function findByPasswordResetToken($token)
{
if (!static::isPasswordResetTokenValid($token)) {
return;
}
return static::findOne([
'password_reset_token' => $token,
'blocked_at' => null
]);
}
/**
* Finds out if password reset token is valid.
*
* @param string $token password reset token
*
* @return bool
*/
public static function isPasswordResetTokenValid($token)
{
if (empty($token)) {
return false;
}
$timestamp = (int)substr($token, strrpos($token, '_') + 1);
$expire = Yii::$app->params['user.passwordResetTokenExpire'];
return $timestamp + $expire >= time();
}
/**
* 获取当前用户id,认证身份identity使用
* {@inheritdoc}
*/
public function getId()
{
return $this->getPrimaryKey();
}
/**
* 获取当前身份验证密钥
* {@inheritdoc}
*/
public function getAuthKey()
{
return $this->auth_key;
}
/**
* 验证身份验证密钥
* {@inheritdoc}
*/
public function validateAuthKey($authKey)
{
return $this->getAuthKey() === $authKey;
}
/**
* 验证密码
* @param string $password password to validate
*
* @return bool if password provided is valid for current user
*/
public function validatePassword($password)
{
return Yii::$app->security->validatePassword($password, $this->password_hash);
}
/**
* 从密码生成密码哈希并将其赋值给当前用户。
* @param $password
* @throws \yii\base\Exception
* @author nodelog
*/
public function setPassword($password)
{
$this->password_hash = Yii::$app->security->generatePasswordHash($password);
}
/**
* 验证二维码哈希值
* @param $qrcodeHash
* @return bool
* @author nodelog
*/
public function validateQrcodeHash($qrcodeHash)
{
return $qrcodeHash == md5(self::generateQrcodeLoginUrl($this->access_token));
}
/**
* 生成“记住我”身份验证密钥。
*/
public function generateAuthKey()
{
$this->auth_key = Yii::$app->security->generateRandomString();
}
/**
* 生成新的密码重置令牌。
*/
public function generatePasswordResetToken()
{
$this->password_reset_token = Yii::$app->security->generateRandomString() . '_' . time();
}
/**
* 删除密码重置令牌。
*/
public function removePasswordResetToken()
{
$this->password_reset_token = null;
}
/**
* 生成访问令牌和过期时间
* @param null $access_token
* @throws \yii\base\Exception
* @author nodelog
*/
public function generateAccessToken($access_token = null)
{
if (!$access_token) {
// $access_token = Yii::$app->security->generateRandomString();
}
$this->access_token = $access_token;
$this->expired_at = time() + 60 * 60 * 2;//2小时
}
/**
* 删除访问令牌和过期时间
* @author nodelog
*/
public function removeAccessToken()
{
$this->access_token = null;
$this->expired_at = null;
}
/**
* 创建用户
* @param int $type
* @return bool
* @author nodelog
*/
public function create()
{
if ($this->getIsNewRecord() == false) {
throw new \RuntimeException('Calling "' . __CLASS__ . '::' . __METHOD__ . '" on existing user');
}
$this->confirmed_at = time();
$this->password = $this->password == null ? $this->getModule()->defaultPassword : $this->password;
$this->generateAuthKey();
if (!$this->save()) {
return false;
}
return true;
}
/**
* 创建微信用户 并授权公司管理员角色
* @throws \Exception
* @author nodelog
*/
public function createWechat()
{
$this->type = self::TYPE_PERSON;
if ($this->create()) {
// try {
// $auth = \Yii::$app->authManager;
// //todo 具体授权
// $authorRole = $auth->getRole('superAdmin');
// $auth->assign($authorRole, $this->id);
// } catch (Exception $e) {
// $this->addError('username', $e->getMessage());
// return false;
// }
//创建个人数据设置
return true;
}
return false;
}
/**
* 保存之前生成密码哈希
* @param bool $insert
* @return bool
* @throws \yii\base\Exception
* @author nodelog
*/
public function beforeSave($insert)
{
if (!empty($this->password)) {
$this->password_hash = Yii::$app->security->generatePasswordHash($this->password);
}
return parent::beforeSave($insert);
}
/**
* 禁用用户
* @return bool
* @throws \yii\base\Exception
* @author nodelog
*/
public function block()
{
return (bool)$this->updateAttributes([
'blocked_at' => time(),
'auth_key' => \Yii::$app->security->generateRandomString(),
]);
}
/**
* 解除禁用
* UnBlocks the user by setting 'blocked_at' field to null.
*/
public function unblock()
{
return (bool)$this->updateAttributes(['blocked_at' => null]);
}
/**
* 发送绑定邮箱确认邮件
* @param $email
* @return array
* @throws \yii\base\InvalidConfigException
* @author nodelog
*/
public function sendConfirm($email)
{
$exist = User::find()->where(['<>', 'id', Yii::$app->user->id])->andWhere(['email' => $email])->exists();
$user = Yii::$app->user->identity;
if (!$exist && !$user->isConfirmed) {
/** @var Token $token */
$token = \Yii::createObject([
'class' => Token::className(),
'user_id' => $user->id,
'type' => Token::TYPE_CONFIRMATION,
]);
$token->save(false);
$mailer = Yii::$app->mailer;
$mailer->viewPath = '@common/modules/user/mail';
try {
$mailer->compose(['html' => 'confirmation'], ['user' => $user, 'token' => $token])
->setTo($email)
->setSubject(Yii::t('user', 'Confirm account on {0}', Yii::$app->config->get('name')))
->send();
return [true, null];
} catch (\Exception $e) {
return [false, '发送失败,请确认邮箱是否存在!'];
}
} else {
return [false, '邮箱已存在'];
}
}
/**
* 用户邮箱验证
* @param $code
* @return array
* @throws \yii\db\StaleObjectException
* @author nodelog
*/
public function attemptConfirmation($code)
{
if ($this->getIsConfirmed()) {
return [false, '该用户已验证邮箱'];
}
$token = Token::find()->where(['user_id' => $this->id, 'code' => $code, 'type' => Token::TYPE_CONFIRMATION])->one();
if ($token !== null && !$token->isExpired) {
$token->delete();
if (($success = $this->confirm())) {
$message = \Yii::t('user', 'Thank you, registration is now complete.');
} else {
$message = \Yii::t('user', 'Something went wrong and your account has not been confirmed.');
}
} else {
$success = false;
$message = \Yii::t('user', 'The confirmation link is invalid or expired. Please try requesting a new one.');
}
return [$success, $message];
}
/**
* Confirms the user by setting 'confirmed_at' field to current time.
*/
public function confirm()
{
$result = (bool)$this->updateAttributes(['confirmed_at' => time()]);
return $result;
}
/**
* 获取用户头像
* @param int $width
* @param int $height
* @return string
* @author nodelog
*/
public function getAvatar($width = 96, $height = 0)
{
if (empty($height)) {
$height = $width;
}
if ($this->profile->avatar) {
return Yii::$app->storage->thumbnail($this->profile->avatar, $width, $height);
}
return $this->getDefaultAvatar($width, $height);
}
/**
* 获取用户信息
* @return \yii\db\ActiveQuery
* @author nodelog
*/
public function getProfile()
{
return $this->hasOne(Profile::className(), ['user_id' => 'id']);
}
/**
* 认证车辆
* @return \yii\db\ActiveQuery
* @author nodelog
*/
public function getCar()
{
return $this->hasOne(UserCar::className(), ['user_id' => 'id']);
}
/**
* 获取用户签名
* @return string
* @author nodelog
*/
public function getSignature()
{
return $this->profile->signature;
}
/**
* 获取默认头像
* @param $width
* @param $height
* @return string
* @author nodelog
*/
public static function getDefaultAvatar($width, $height)
{
list ($basePath, $baseUrl) = \Yii::$app->getAssetManager()->publish("@common/static");
$name = "avatars/avatar_" . $width . "x" . $height . ".png";
if (file_exists($basePath . DIRECTORY_SEPARATOR . $name)) {
return $baseUrl . "/" . $name;
}
return $baseUrl . "/" . "avatar_200x200.png";
}
/**
* 保存头像
* @param $avatar
* @author nodelog
*/
public function saveAvatar($avatar)
{
$this->profile->updateAttributes(['avatar' => $avatar]);
}
/**
* 初始化插入数据库后置事件
* @author nodelog
*/
public function init()
{
$this->on(self::EVENT_AFTER_INSERT, [$this, 'afterInsertInternal']);
}
/**
* 设置用户信息的外键关联
* @param $event
* @author nodelog
*/
public function afterInsertInternal($event)
{
$profile = new Profile();
// $profile->voice_id = Voice::getDefaultId();
$this->link('profile', $profile);
//创建个人配置
}
/**
* 是否管理员用户
* @return bool
*/
public function getIsAdmin()
{
return
(\Yii::$app->getAuthManager() && $this->module->adminPermission ?
Yii::$app->getAuthManager()->checkAccess($this->getId(), $this->module->adminPermission) : false)
|| in_array($this->username, $this->module->admins);
}
/**
* 是否确认
* @return bool Whether the user is confirmed or not.
*/
public function getIsConfirmed()
{
return $this->confirmed_at != null;
}
/**
* 是否禁用
* @return bool Whether the user is blocked or not.
*/
public function getIsBlocked()
{
return $this->blocked_at != null;
}
/**
* 获取等级
* @return string
*/
public function getLevel()
{
return UserLevel::getLevel($this->profile->money);
}
/**
* 生成二维码登录url
* @param $access_token
* @return string
* @author nodelog
*/
public static function generateQrcodeLoginUrl($access_token)
{
return Yii::$app->request->hostInfo . '/api/v1/weixin/code?access_token=' . $access_token;
}
public static $typeList = [
self::TYPE_COMPANY => '企业用户',
self::TYPE_PERSON => '个人用户',
self::TYPE_WEB => '后台用户'
];
public static $typeIconList = [
self::TYPE_PERSON => '',
self::TYPE_WEB => ''
];
/**
* 格式化昵称
* @return string
* @author nodelog
*/
private function formatNickname()
{
// $name = $this->profile->nickname ?: $this->username;
// if ($htmlFormat) {
// return Html::tag('span', $name . ' ' . self::$typeIconList[$this->type], ['title' => self::$typeList[$this->type]]);
// }
return $this->nickname ? $this->nickname : $this->username;
}
/**
* 获得用户所有角色描述
* @return string
* @author nodelog
*/
public function getAllRoleDesc()
{
$roles = Yii::$app->authManager->getRolesByUser($this->id);
return implode(' | ', ArrayHelper::getColumn($roles, 'description'));
}
/**
* 查询 左连接 去除公共部分,如教练查询未绑定教练微信用户,销售查询未绑定销售微信用户,FOR 后台添加教练和销售 筛选选择列表数据
* @param $model 模型类名
* @param $inIdArray 过滤的id数组
* @return array|User[]
*/
public static function getAllSelectFromModel($model, $inIdArray = null)
{
if (empty($inIdArray)) {
$list = User::find()->joinWith($model::relationName())->where([self::tableName() . '.blocked_at' => null, $model::tableName() . '.user_id' => null])->all();
} else {
$list = User::find()->joinWith($model::relationName())->where([self::tableName() . '.blocked_at' => null])->andWhere(['or', [$model::tableName() . '.user_id' => null], [$model::tableName() . '.user_id' => $inIdArray]])->all();
}
return $list;
}
/**
* 获取可选管理员用户列表
* @author nodelog
*/
public static function lists()
{
if (Yii::$app->user->identity->getIsAdmin()) {
//已经使用的用户ids
// $usedUserIds = Company::find()->select('user_id')->distinct()->asArray()->indexBy('user_id')->column();
// //去掉当前包含的当前公司id
// if (!empty($this->user_id) && isset($usedUserIds[$this->user_id])) {
// unset($usedUserIds[$this->user_id]);
// }
// return User::find()->where(['not in', 'id', $usedUserIds])->asArray()->indexBy('id')->all();
$lists = User::find()->indexBy('id')->all();
$lists = ArrayHelper::map($lists, 'id', 'nickname');
return $lists;
} else {
return [
Yii::$app->user->id => Yii::$app->user->identity->nickname
];
}
}
/**
* 获取用户的供应商
* @return \yii\db\ActiveQuery
* @author nodelog
*/
public function getStore()
{
return $this->hasOne(Store::className(), ['user_id' => 'id']);
}
/**
* 查询后对数据处理
* @author nodelog
*/
public function afterFind()
{
parent::afterFind();
// $this->nickname = $this->formatNickname();
//更新vip状态
// $this->isVip();
}
/**
* 获取分销等级
* @return \yii\db\ActiveQuery
* @author nodelog
*/
public function getShareLevel()
{
return $this->hasOne(ShareLevel::className(), ['id' => 'level_id']);
}
/**
* 分销海报
*
* @param bool $force
* @return bool|mixed|string
* @throws ServerErrorHttpException
* @author nodelog
*/
public function generateQrcode($force = false)
{
//海报存在直接返回
if ($this->qrcode && !$force) {
return $this->qrcode->url;
}
//小程序码中 scene 放入用户id
$scene = 'pid:' . \Yii::$app->user->id;
$hash = md5($scene);
$qrcodeFile = \Yii::getAlias('@storagePath/upload/qrcode/' . $hash . '.png');//path
$qrcodeUrl = \Yii::getAlias('@storageUrl/upload/qrcode/' . $hash . '.png');//path
try {
ini_set('memory_limit', '256M');
$editor = Grafika::createEditor(GrafikaHelper::getSupportEditorLib());
//背景图
$editor->open($userPoster, Yii::$app->storage->getPath(\Yii::$app->config->get('share_poster_bg')));
//生成推广码
/* @var Qrcode $qrcode */
$qrcode = (new Application())->driver("mini.qrcode");
//小程序码 buffer,宽度220
$qrcodeStream = $qrcode->unLimit($scene, 'pages/index/index', $extra = []);//buffer
$tempFile = \Yii::getAlias('@storagePath/upload/thumb/' . $hash . '.png');
if (!file_exists(dirname($tempFile))) {
@mkdir(dirname($tempFile), 0755, true);
}
file_put_contents($tempFile, $qrcodeStream);
// Yii::$app->storage->put($tempFile, $qrcodeStream);
$editor->open($wxappQrcode, $tempFile);
//测试二维码
// $editor->open($wxappQrcode, Yii::$app->storage->getPath('https://es.jiangzi.xin/storage/upload/20220408/OGGUn-K8HxojZfSesNv0OuVuAhRLYPzSJX0zEiyE.png'));
$avatarPath = Yii::$app->storage->getPath($this->getAvatar(540));
if (strpos($avatarPath, 'http') !== false) {
$avatarPath = Yii::$app->storage->thumbnail(\Yii::$app->config->get('share_image'), 540, 540);
$editor->open($avatar, Yii::$app->storage->getPath($avatarPath));
} else {
$editor->open($avatar, $avatarPath);
}
// $editor->resizeFill($goodsCover, 750, 750);
$editor->resizeExactWidth($avatar, 540);
//附加头像
$editor->blend($userPoster, $avatar, 'normal', 1.0, 'top-left', 105, 4900);
//写入文字
$fontFile = Yii::getAlias('@root/web/assets/fonts/st-heiti-light.ttc');
//加用户昵称
$editor->text($userPoster, mb_substr($this->nickname, 0, 12), 100, 750, 5000, new Color('#ffffff'), $fontFile, 0);
$editor->text($userPoster, Yii::$app->config->get('share_poster_text'), 70, 750, 5250, new Color('#ffffff'), $fontFile, 0);
//调整小程序码图片
$editor->resizeExactWidth($wxappQrcode, 660);
//附加小程序码图片
$editor->blend($userPoster, $wxappQrcode, 'normal', 1.0, 'top-right', -105, 4800);
//保存图片
$editor->save($userPoster, $qrcodeFile, 85);
//删除临时图片
unlink($tempFile);
//上传分销码
list($attachment, $error) = Attachment::uploadFromFile('qrcode', $qrcodeFile);
if ($error == null) {
$this->qrcode = [
'id' => $attachment->id,
'name' => $attachment->name,
'hash' => $attachment->hash,
'url' => $attachment->url,
'path' => $attachment->path,
'extension' => $attachment->extension,
'type' => $attachment->type,
'size' => $attachment->size
];
if ($this->save(false)) {
return ArrayHelper::getValue($this, 'qrcode.url', '');
}
}
} catch (Exception $e) {
throw new ServerErrorHttpException($e->getMessage());
}
return $qrcodeUrl;
}
/**
* 用户是否vip,并且未过期
* @author nodelog
*/
public function isVip()
{
//vip自动过期
if ($this->is_vip) {
$vip = VipUser::find()->where(['user_id' => $this->id])->orderBy(['end_time' => SORT_DESC])->one();
if (!empty($vip) && $vip->isExpire()) {
$this->is_vip = StatusEnum::STATUS_OFF;
$this->save(false);
}
}
return $this->is_vip;
}
/**
* 获取当前vip
* @author nodelog
*/
public function getCurrentVip()
{
$now = time();
return VipUser::find()->where(['user_id' => $this->id])->andWhere(['and', ['<=', 'start_time', $now], ['>', 'end_time', $now]])->one();
}
//
// public function fields() {
// $fields = parent::fields();
//
// $fields[] = 'dataCount';
// return $fields;
// }
/**
* 数据统计
* @author nodelog
*/
public function getDataCount()
{
$data = [
[
'text' => '日课',
'count' => 0
],
[
'text' => '总课',
'count' => 0
],
[
'text' => '辅助课',
'count' => 0
],
];
//每日功课
// $data[0]['count'] = Data::find()->active()->andWhere(['user_id' => $this->id])->today()->count();
//累积功课
// $data[1]['count'] = Data::find()->active()->andWhere(['user_id' => $this->id])->count();
//辅助功课
// $userIds = VipUser::find()->active()->andWhere(['pay_user_id' => $this->id])->andWhere(['!=', 'user_id', $this->id])->select(['user_id'])->distinct()->column();
// $data[2]['count'] = Data::find()->active()->andWhere(['in', 'user_id', $userIds])->count();
//直接获取辅助榜数据
// $helpCount = DataRank::find()->active()->andWhere(['user_id' => $this->id, 'level' => DataTypeEnum::TYPE_HELP])->total()->select(['count'])->scalar();
// $data[2]['count'] = $helpCount ? $helpCount : 0;
return $data;
}
}