User.php 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987
  1. <?php
  2. namespace common\modules\user\models;
  3. use abei2017\wx\mini\qrcode\Qrcode;
  4. use backend\models\search\SearchModelTrait;
  5. use common\enums\DataTypeEnum;
  6. use common\enums\StatusEnum;
  7. use common\helpers\GrafikaHelper;
  8. use common\helpers\Regexp;
  9. use common\helpers\wx\Application;
  10. use common\models\Data;
  11. use common\models\DataRank;
  12. use common\models\ShareLevel;
  13. use common\models\Store;
  14. use common\models\UserCar;
  15. use common\models\UserLevel;
  16. use common\models\VipUser;
  17. use common\models\Voice;
  18. use common\modules\attachment\behaviors\UploadBehavior;
  19. use common\modules\attachment\models\Attachment;
  20. use common\modules\rbac\controllers\AssignmentController;
  21. use common\modules\user\Module;
  22. use common\modules\user\traits\ModuleTrait;
  23. use Exception;
  24. use Grafika\Color;
  25. use Grafika\Grafika;
  26. use Yii;
  27. use yii\behaviors\TimestampBehavior;
  28. use yii\db\ActiveRecord;
  29. use yii\helpers\ArrayHelper;
  30. use yii\web\IdentityInterface;
  31. use yii\web\ServerErrorHttpException;
  32. /**
  33. * User model.
  34. *
  35. * @property int $id
  36. * @property int $pid
  37. * @property int $jucai_id
  38. * @property string $username
  39. * @property string $password_hash
  40. * @property string $password_reset_token
  41. * @property string $access_token
  42. * @property int $expired_at
  43. * @property string $email
  44. * @property string $tel
  45. * @property string $auth_key
  46. * @property int $created_at
  47. * @property int $updated_at
  48. * @property int $confirmed_at
  49. * @property int $blocked_at
  50. * @property int $login_at
  51. * @property int $type
  52. * @property int $level_id
  53. * @property int $is_vip
  54. * @property int $vip_time
  55. * @property string $password write-only password
  56. * @property Profile $profile
  57. * @property UserCar $car
  58. * @property string $privilege
  59. * @property string $openid
  60. * @property string $unionid
  61. * @property string $nickname
  62. * @property Module $module
  63. * @property Store $store
  64. * @property ShareLevel $shareLevel
  65. * @property Attachment $qrcode
  66. * @property array $dataCount
  67. */
  68. class User extends ActiveRecord implements IdentityInterface
  69. {
  70. use ModuleTrait;
  71. use SearchModelTrait;
  72. public $password;
  73. const TYPE_WEB = 0;//后台用户
  74. const TYPE_PERSON = 1;//个人用户
  75. const TYPE_COMPANY = 2;//企业用户
  76. /**
  77. * {@inheritdoc}
  78. */
  79. public static function tableName()
  80. {
  81. return '{{%user}}';
  82. }
  83. /**
  84. * {@inheritdoc}
  85. */
  86. public function behaviors()
  87. {
  88. return [
  89. TimestampBehavior::className(),
  90. [
  91. 'class' => UploadBehavior::className(),
  92. 'attribute' => 'qrcode',
  93. 'entity' => __CLASS__
  94. ],
  95. ];
  96. }
  97. public function scenarios()
  98. {
  99. $scenarios = parent::scenarios();
  100. return array_merge($scenarios, [
  101. 'register' => ['username', 'openid', 'password', 'email', 'tel', 'pid'],
  102. 'connect' => ['username', 'email'],
  103. 'create' => ['jucai_id', 'email', 'tel'],
  104. 'update' => ['username', 'password', 'email', 'tel', 'nickname', 'level_id', 'pid'],
  105. 'settings' => ['username', 'password', 'email', 'tel'],
  106. 'resetPassword' => ['password']
  107. ]);
  108. }
  109. /**
  110. * {@inheritdoc}
  111. */
  112. public function rules()
  113. {
  114. return [
  115. ['username', 'string', 'on' => 'search'],
  116. ['username', 'required', 'on' => 'create'],
  117. ['password', 'required', 'on' => ['register']],
  118. [['tel'], 'match', 'pattern' => Regexp::$mobile],
  119. [['email'], 'match', 'pattern' => Regexp::$email],
  120. [['privilege'], 'string', 'max' => 255],
  121. [['qrcode', 'dataCount'], 'safe'],
  122. ];
  123. }
  124. public function attributeLabels()
  125. {
  126. return [
  127. 'pid' => '上级用户',
  128. 'jucai_id' => '聚才网ID',
  129. 'username' => '用户名',//openid共用字段
  130. 'openid' => '微信ID',
  131. 'nickname' => '昵称',
  132. 'password' => '密码',
  133. 'email' => ' 绑定邮箱',
  134. 'tel' => '绑定手机',
  135. 'avatar' => '头像',
  136. 'created_at' => '注册时间',
  137. 'login_at' => '最后登录时间',
  138. 'type' => '用户类型',
  139. 'privilege' => '特权',//微信用户属性
  140. 'unionid' => '联合ID',//微信用户属性
  141. 'level_id' => '分销等级',//微信用户属性
  142. 'qrcode' => '分销码', //小程序码
  143. 'is_vip' => '是否vip', //是否vip
  144. 'vip_time' => 'vip有效期', //是否vip
  145. 'dataCount' => '数据统计',
  146. ];
  147. }
  148. /**
  149. * 根据id查询用户
  150. * {@inheritdoc}
  151. */
  152. public static function findIdentity($id)
  153. {
  154. return static::findOne(['id' => $id, 'blocked_at' => null]);
  155. }
  156. /**
  157. * 根据访问令牌查询用户
  158. * api访问专用
  159. * {@inheritdoc}
  160. */
  161. public static function findIdentityByAccessToken($token, $type = null)
  162. {
  163. return static::find()->where(['access_token' => $token])->andWhere(['>', 'expired_at', time()])->one();
  164. }
  165. /**
  166. * 根据用户名查询用户
  167. *
  168. * @param string $username
  169. *
  170. * @return mixed
  171. */
  172. public static function findByUsername($username)
  173. {
  174. return static::find()->where(['username' => $username])
  175. ->andWhere(['blocked_at' => null])
  176. ->one();
  177. }
  178. /**
  179. * 根据用openid查询用户
  180. *
  181. * @param string $openId
  182. *
  183. * @return mixed
  184. */
  185. public static function findByOpenid($openId)
  186. {
  187. return static::find()->where(['openid' => $openId])
  188. ->andWhere(['blocked_at' => null])
  189. ->one();
  190. }
  191. /**
  192. * 根据绑定邮箱查询用户
  193. * @param $email
  194. * @return array|ActiveRecord|null
  195. * @author nodelog
  196. */
  197. public static function findByEmail($email)
  198. {
  199. return static::find()->where(['email' => $email])
  200. ->andWhere(['blocked_at' => null])
  201. ->one();
  202. }
  203. /**
  204. * 根据绑定手机号查询用户
  205. * @param $tel
  206. * @return array|ActiveRecord|null
  207. * @author nodelog
  208. */
  209. public static function findByTel($tel)
  210. {
  211. return static::find()->where(['email' => $tel])
  212. ->andWhere(['blocked_at' => null])
  213. ->one();
  214. }
  215. /**
  216. * 根据用户名、邮箱、手机号查询用户
  217. * @param $login
  218. * @return array|ActiveRecord|null
  219. * @author nodelog
  220. */
  221. public static function findByUsernameOrEmailTel($login)
  222. {
  223. return static::find()->where(['or', ['username' => $login], ['email' => $login], ['tel' => $login]])
  224. ->andWhere(['blocked_at' => null])
  225. ->one();
  226. }
  227. /**
  228. * 根据重置密码令牌查询用户
  229. * Finds user by password reset token.
  230. *
  231. * @param string $token password reset token
  232. *
  233. * @return static|null
  234. */
  235. public static function findByPasswordResetToken($token)
  236. {
  237. if (!static::isPasswordResetTokenValid($token)) {
  238. return;
  239. }
  240. return static::findOne([
  241. 'password_reset_token' => $token,
  242. 'blocked_at' => null
  243. ]);
  244. }
  245. /**
  246. * Finds out if password reset token is valid.
  247. *
  248. * @param string $token password reset token
  249. *
  250. * @return bool
  251. */
  252. public static function isPasswordResetTokenValid($token)
  253. {
  254. if (empty($token)) {
  255. return false;
  256. }
  257. $timestamp = (int)substr($token, strrpos($token, '_') + 1);
  258. $expire = Yii::$app->params['user.passwordResetTokenExpire'];
  259. return $timestamp + $expire >= time();
  260. }
  261. /**
  262. * 获取当前用户id,认证身份identity使用
  263. * {@inheritdoc}
  264. */
  265. public function getId()
  266. {
  267. return $this->getPrimaryKey();
  268. }
  269. /**
  270. * 获取当前身份验证密钥
  271. * {@inheritdoc}
  272. */
  273. public function getAuthKey()
  274. {
  275. return $this->auth_key;
  276. }
  277. /**
  278. * 验证身份验证密钥
  279. * {@inheritdoc}
  280. */
  281. public function validateAuthKey($authKey)
  282. {
  283. return $this->getAuthKey() === $authKey;
  284. }
  285. /**
  286. * 验证密码
  287. * @param string $password password to validate
  288. *
  289. * @return bool if password provided is valid for current user
  290. */
  291. public function validatePassword($password)
  292. {
  293. return Yii::$app->security->validatePassword($password, $this->password_hash);
  294. }
  295. /**
  296. * 从密码生成密码哈希并将其赋值给当前用户。
  297. * @param $password
  298. * @throws \yii\base\Exception
  299. * @author nodelog
  300. */
  301. public function setPassword($password)
  302. {
  303. $this->password_hash = Yii::$app->security->generatePasswordHash($password);
  304. }
  305. /**
  306. * 验证二维码哈希值
  307. * @param $qrcodeHash
  308. * @return bool
  309. * @author nodelog
  310. */
  311. public function validateQrcodeHash($qrcodeHash)
  312. {
  313. return $qrcodeHash == md5(self::generateQrcodeLoginUrl($this->access_token));
  314. }
  315. /**
  316. * 生成“记住我”身份验证密钥。
  317. */
  318. public function generateAuthKey()
  319. {
  320. $this->auth_key = Yii::$app->security->generateRandomString();
  321. }
  322. /**
  323. * 生成新的密码重置令牌。
  324. */
  325. public function generatePasswordResetToken()
  326. {
  327. $this->password_reset_token = Yii::$app->security->generateRandomString() . '_' . time();
  328. }
  329. /**
  330. * 删除密码重置令牌。
  331. */
  332. public function removePasswordResetToken()
  333. {
  334. $this->password_reset_token = null;
  335. }
  336. /**
  337. * 生成访问令牌和过期时间
  338. * @param null $access_token
  339. * @throws \yii\base\Exception
  340. * @author nodelog
  341. */
  342. public function generateAccessToken($access_token = null)
  343. {
  344. if (!$access_token) {
  345. // $access_token = Yii::$app->security->generateRandomString();
  346. }
  347. $this->access_token = $access_token;
  348. $this->expired_at = time() + 60 * 60 * 2;//2小时
  349. }
  350. /**
  351. * 删除访问令牌和过期时间
  352. * @author nodelog
  353. */
  354. public function removeAccessToken()
  355. {
  356. $this->access_token = null;
  357. $this->expired_at = null;
  358. }
  359. /**
  360. * 创建用户
  361. * @param int $type
  362. * @return bool
  363. * @author nodelog
  364. */
  365. public function create()
  366. {
  367. if ($this->getIsNewRecord() == false) {
  368. throw new \RuntimeException('Calling "' . __CLASS__ . '::' . __METHOD__ . '" on existing user');
  369. }
  370. $this->confirmed_at = time();
  371. $this->password = $this->password == null ? $this->getModule()->defaultPassword : $this->password;
  372. $this->generateAuthKey();
  373. if (!$this->save()) {
  374. return false;
  375. }
  376. return true;
  377. }
  378. /**
  379. * 创建微信用户 并授权公司管理员角色
  380. * @throws \Exception
  381. * @author nodelog
  382. */
  383. public function createWechat()
  384. {
  385. $this->type = self::TYPE_PERSON;
  386. if ($this->create()) {
  387. // try {
  388. // $auth = \Yii::$app->authManager;
  389. // //todo 具体授权
  390. // $authorRole = $auth->getRole('superAdmin');
  391. // $auth->assign($authorRole, $this->id);
  392. // } catch (Exception $e) {
  393. // $this->addError('username', $e->getMessage());
  394. // return false;
  395. // }
  396. //创建个人数据设置
  397. return true;
  398. }
  399. return false;
  400. }
  401. /**
  402. * 保存之前生成密码哈希
  403. * @param bool $insert
  404. * @return bool
  405. * @throws \yii\base\Exception
  406. * @author nodelog
  407. */
  408. public function beforeSave($insert)
  409. {
  410. if (!empty($this->password)) {
  411. $this->password_hash = Yii::$app->security->generatePasswordHash($this->password);
  412. }
  413. return parent::beforeSave($insert);
  414. }
  415. /**
  416. * 禁用用户
  417. * @return bool
  418. * @throws \yii\base\Exception
  419. * @author nodelog
  420. */
  421. public function block()
  422. {
  423. return (bool)$this->updateAttributes([
  424. 'blocked_at' => time(),
  425. 'auth_key' => \Yii::$app->security->generateRandomString(),
  426. ]);
  427. }
  428. /**
  429. * 解除禁用
  430. * UnBlocks the user by setting 'blocked_at' field to null.
  431. */
  432. public function unblock()
  433. {
  434. return (bool)$this->updateAttributes(['blocked_at' => null]);
  435. }
  436. /**
  437. * 发送绑定邮箱确认邮件
  438. * @param $email
  439. * @return array
  440. * @throws \yii\base\InvalidConfigException
  441. * @author nodelog
  442. */
  443. public function sendConfirm($email)
  444. {
  445. $exist = User::find()->where(['<>', 'id', Yii::$app->user->id])->andWhere(['email' => $email])->exists();
  446. $user = Yii::$app->user->identity;
  447. if (!$exist && !$user->isConfirmed) {
  448. /** @var Token $token */
  449. $token = \Yii::createObject([
  450. 'class' => Token::className(),
  451. 'user_id' => $user->id,
  452. 'type' => Token::TYPE_CONFIRMATION,
  453. ]);
  454. $token->save(false);
  455. $mailer = Yii::$app->mailer;
  456. $mailer->viewPath = '@common/modules/user/mail';
  457. try {
  458. $mailer->compose(['html' => 'confirmation'], ['user' => $user, 'token' => $token])
  459. ->setTo($email)
  460. ->setSubject(Yii::t('user', 'Confirm account on {0}', Yii::$app->config->get('name')))
  461. ->send();
  462. return [true, null];
  463. } catch (\Exception $e) {
  464. return [false, '发送失败,请确认邮箱是否存在!'];
  465. }
  466. } else {
  467. return [false, '邮箱已存在'];
  468. }
  469. }
  470. /**
  471. * 用户邮箱验证
  472. * @param $code
  473. * @return array
  474. * @throws \yii\db\StaleObjectException
  475. * @author nodelog
  476. */
  477. public function attemptConfirmation($code)
  478. {
  479. if ($this->getIsConfirmed()) {
  480. return [false, '该用户已验证邮箱'];
  481. }
  482. $token = Token::find()->where(['user_id' => $this->id, 'code' => $code, 'type' => Token::TYPE_CONFIRMATION])->one();
  483. if ($token !== null && !$token->isExpired) {
  484. $token->delete();
  485. if (($success = $this->confirm())) {
  486. $message = \Yii::t('user', 'Thank you, registration is now complete.');
  487. } else {
  488. $message = \Yii::t('user', 'Something went wrong and your account has not been confirmed.');
  489. }
  490. } else {
  491. $success = false;
  492. $message = \Yii::t('user', 'The confirmation link is invalid or expired. Please try requesting a new one.');
  493. }
  494. return [$success, $message];
  495. }
  496. /**
  497. * Confirms the user by setting 'confirmed_at' field to current time.
  498. */
  499. public function confirm()
  500. {
  501. $result = (bool)$this->updateAttributes(['confirmed_at' => time()]);
  502. return $result;
  503. }
  504. /**
  505. * 获取用户头像
  506. * @param int $width
  507. * @param int $height
  508. * @return string
  509. * @author nodelog
  510. */
  511. public function getAvatar($width = 96, $height = 0)
  512. {
  513. if (empty($height)) {
  514. $height = $width;
  515. }
  516. if ($this->profile->avatar) {
  517. return Yii::$app->storage->thumbnail($this->profile->avatar, $width, $height);
  518. }
  519. return $this->getDefaultAvatar($width, $height);
  520. }
  521. /**
  522. * 获取用户信息
  523. * @return \yii\db\ActiveQuery
  524. * @author nodelog
  525. */
  526. public function getProfile()
  527. {
  528. return $this->hasOne(Profile::className(), ['user_id' => 'id']);
  529. }
  530. /**
  531. * 认证车辆
  532. * @return \yii\db\ActiveQuery
  533. * @author nodelog
  534. */
  535. public function getCar()
  536. {
  537. return $this->hasOne(UserCar::className(), ['user_id' => 'id']);
  538. }
  539. /**
  540. * 获取用户签名
  541. * @return string
  542. * @author nodelog
  543. */
  544. public function getSignature()
  545. {
  546. return $this->profile->signature;
  547. }
  548. /**
  549. * 获取默认头像
  550. * @param $width
  551. * @param $height
  552. * @return string
  553. * @author nodelog
  554. */
  555. public static function getDefaultAvatar($width, $height)
  556. {
  557. list ($basePath, $baseUrl) = \Yii::$app->getAssetManager()->publish("@common/static");
  558. $name = "avatars/avatar_" . $width . "x" . $height . ".png";
  559. if (file_exists($basePath . DIRECTORY_SEPARATOR . $name)) {
  560. return $baseUrl . "/" . $name;
  561. }
  562. return $baseUrl . "/" . "avatar_200x200.png";
  563. }
  564. /**
  565. * 保存头像
  566. * @param $avatar
  567. * @author nodelog
  568. */
  569. public function saveAvatar($avatar)
  570. {
  571. $this->profile->updateAttributes(['avatar' => $avatar]);
  572. }
  573. /**
  574. * 初始化插入数据库后置事件
  575. * @author nodelog
  576. */
  577. public function init()
  578. {
  579. $this->on(self::EVENT_AFTER_INSERT, [$this, 'afterInsertInternal']);
  580. }
  581. /**
  582. * 设置用户信息的外键关联
  583. * @param $event
  584. * @author nodelog
  585. */
  586. public function afterInsertInternal($event)
  587. {
  588. $profile = new Profile();
  589. // $profile->voice_id = Voice::getDefaultId();
  590. $this->link('profile', $profile);
  591. //创建个人配置
  592. }
  593. /**
  594. * 是否管理员用户
  595. * @return bool
  596. */
  597. public function getIsAdmin()
  598. {
  599. return
  600. (\Yii::$app->getAuthManager() && $this->module->adminPermission ?
  601. Yii::$app->getAuthManager()->checkAccess($this->getId(), $this->module->adminPermission) : false)
  602. || in_array($this->username, $this->module->admins);
  603. }
  604. /**
  605. * 是否确认
  606. * @return bool Whether the user is confirmed or not.
  607. */
  608. public function getIsConfirmed()
  609. {
  610. return $this->confirmed_at != null;
  611. }
  612. /**
  613. * 是否禁用
  614. * @return bool Whether the user is blocked or not.
  615. */
  616. public function getIsBlocked()
  617. {
  618. return $this->blocked_at != null;
  619. }
  620. /**
  621. * 获取等级
  622. * @return string
  623. */
  624. public function getLevel()
  625. {
  626. return UserLevel::getLevel($this->profile->money);
  627. }
  628. /**
  629. * 生成二维码登录url
  630. * @param $access_token
  631. * @return string
  632. * @author nodelog
  633. */
  634. public static function generateQrcodeLoginUrl($access_token)
  635. {
  636. return Yii::$app->request->hostInfo . '/api/v1/weixin/code?access_token=' . $access_token;
  637. }
  638. public static $typeList = [
  639. self::TYPE_COMPANY => '企业用户',
  640. self::TYPE_PERSON => '个人用户',
  641. self::TYPE_WEB => '后台用户'
  642. ];
  643. public static $typeIconList = [
  644. self::TYPE_PERSON => '<i class="fa fa-fw fa-wechat"></i>',
  645. self::TYPE_WEB => '<i class="fa fa-fw fa-desktop"></i>'
  646. ];
  647. /**
  648. * 格式化昵称
  649. * @return string
  650. * @author nodelog
  651. */
  652. private function formatNickname()
  653. {
  654. // $name = $this->profile->nickname ?: $this->username;
  655. // if ($htmlFormat) {
  656. // return Html::tag('span', $name . ' ' . self::$typeIconList[$this->type], ['title' => self::$typeList[$this->type]]);
  657. // }
  658. return $this->nickname ? $this->nickname : $this->username;
  659. }
  660. /**
  661. * 获得用户所有角色描述
  662. * @return string
  663. * @author nodelog
  664. */
  665. public function getAllRoleDesc()
  666. {
  667. $roles = Yii::$app->authManager->getRolesByUser($this->id);
  668. return implode(' | ', ArrayHelper::getColumn($roles, 'description'));
  669. }
  670. /**
  671. * 查询 左连接 去除公共部分,如教练查询未绑定教练微信用户,销售查询未绑定销售微信用户,FOR 后台添加教练和销售 筛选选择列表数据
  672. * @param $model 模型类名
  673. * @param $inIdArray 过滤的id数组
  674. * @return array|User[]
  675. */
  676. public static function getAllSelectFromModel($model, $inIdArray = null)
  677. {
  678. if (empty($inIdArray)) {
  679. $list = User::find()->joinWith($model::relationName())->where([self::tableName() . '.blocked_at' => null, $model::tableName() . '.user_id' => null])->all();
  680. } else {
  681. $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();
  682. }
  683. return $list;
  684. }
  685. /**
  686. * 获取可选管理员用户列表
  687. * @author nodelog
  688. */
  689. public static function lists()
  690. {
  691. if (Yii::$app->user->identity->getIsAdmin()) {
  692. //已经使用的用户ids
  693. // $usedUserIds = Company::find()->select('user_id')->distinct()->asArray()->indexBy('user_id')->column();
  694. // //去掉当前包含的当前公司id
  695. // if (!empty($this->user_id) && isset($usedUserIds[$this->user_id])) {
  696. // unset($usedUserIds[$this->user_id]);
  697. // }
  698. // return User::find()->where(['not in', 'id', $usedUserIds])->asArray()->indexBy('id')->all();
  699. $lists = User::find()->indexBy('id')->all();
  700. $lists = ArrayHelper::map($lists, 'id', 'nickname');
  701. return $lists;
  702. } else {
  703. return [
  704. Yii::$app->user->id => Yii::$app->user->identity->nickname
  705. ];
  706. }
  707. }
  708. /**
  709. * 获取用户的供应商
  710. * @return \yii\db\ActiveQuery
  711. * @author nodelog
  712. */
  713. public function getStore()
  714. {
  715. return $this->hasOne(Store::className(), ['user_id' => 'id']);
  716. }
  717. /**
  718. * 查询后对数据处理
  719. * @author nodelog
  720. */
  721. public function afterFind()
  722. {
  723. parent::afterFind();
  724. // $this->nickname = $this->formatNickname();
  725. //更新vip状态
  726. // $this->isVip();
  727. }
  728. /**
  729. * 获取分销等级
  730. * @return \yii\db\ActiveQuery
  731. * @author nodelog
  732. */
  733. public function getShareLevel()
  734. {
  735. return $this->hasOne(ShareLevel::className(), ['id' => 'level_id']);
  736. }
  737. /**
  738. * 分销海报
  739. *
  740. * @param bool $force
  741. * @return bool|mixed|string
  742. * @throws ServerErrorHttpException
  743. * @author nodelog
  744. */
  745. public function generateQrcode($force = false)
  746. {
  747. //海报存在直接返回
  748. if ($this->qrcode && !$force) {
  749. return $this->qrcode->url;
  750. }
  751. //小程序码中 scene 放入用户id
  752. $scene = 'pid:' . \Yii::$app->user->id;
  753. $hash = md5($scene);
  754. $qrcodeFile = \Yii::getAlias('@storagePath/upload/qrcode/' . $hash . '.png');//path
  755. $qrcodeUrl = \Yii::getAlias('@storageUrl/upload/qrcode/' . $hash . '.png');//path
  756. try {
  757. ini_set('memory_limit', '256M');
  758. $editor = Grafika::createEditor(GrafikaHelper::getSupportEditorLib());
  759. //背景图
  760. $editor->open($userPoster, Yii::$app->storage->getPath(\Yii::$app->config->get('share_poster_bg')));
  761. //生成推广码
  762. /* @var Qrcode $qrcode */
  763. $qrcode = (new Application())->driver("mini.qrcode");
  764. //小程序码 buffer,宽度220
  765. $qrcodeStream = $qrcode->unLimit($scene, 'pages/index/index', $extra = []);//buffer
  766. $tempFile = \Yii::getAlias('@storagePath/upload/thumb/' . $hash . '.png');
  767. if (!file_exists(dirname($tempFile))) {
  768. @mkdir(dirname($tempFile), 0755, true);
  769. }
  770. file_put_contents($tempFile, $qrcodeStream);
  771. // Yii::$app->storage->put($tempFile, $qrcodeStream);
  772. $editor->open($wxappQrcode, $tempFile);
  773. //测试二维码
  774. // $editor->open($wxappQrcode, Yii::$app->storage->getPath('https://es.jiangzi.xin/storage/upload/20220408/OGGUn-K8HxojZfSesNv0OuVuAhRLYPzSJX0zEiyE.png'));
  775. $avatarPath = Yii::$app->storage->getPath($this->getAvatar(540));
  776. if (strpos($avatarPath, 'http') !== false) {
  777. $avatarPath = Yii::$app->storage->thumbnail(\Yii::$app->config->get('share_image'), 540, 540);
  778. $editor->open($avatar, Yii::$app->storage->getPath($avatarPath));
  779. } else {
  780. $editor->open($avatar, $avatarPath);
  781. }
  782. // $editor->resizeFill($goodsCover, 750, 750);
  783. $editor->resizeExactWidth($avatar, 540);
  784. //附加头像
  785. $editor->blend($userPoster, $avatar, 'normal', 1.0, 'top-left', 105, 4900);
  786. //写入文字
  787. $fontFile = Yii::getAlias('@root/web/assets/fonts/st-heiti-light.ttc');
  788. //加用户昵称
  789. $editor->text($userPoster, mb_substr($this->nickname, 0, 12), 100, 750, 5000, new Color('#ffffff'), $fontFile, 0);
  790. $editor->text($userPoster, Yii::$app->config->get('share_poster_text'), 70, 750, 5250, new Color('#ffffff'), $fontFile, 0);
  791. //调整小程序码图片
  792. $editor->resizeExactWidth($wxappQrcode, 660);
  793. //附加小程序码图片
  794. $editor->blend($userPoster, $wxappQrcode, 'normal', 1.0, 'top-right', -105, 4800);
  795. //保存图片
  796. $editor->save($userPoster, $qrcodeFile, 85);
  797. //删除临时图片
  798. unlink($tempFile);
  799. //上传分销码
  800. list($attachment, $error) = Attachment::uploadFromFile('qrcode', $qrcodeFile);
  801. if ($error == null) {
  802. $this->qrcode = [
  803. 'id' => $attachment->id,
  804. 'name' => $attachment->name,
  805. 'hash' => $attachment->hash,
  806. 'url' => $attachment->url,
  807. 'path' => $attachment->path,
  808. 'extension' => $attachment->extension,
  809. 'type' => $attachment->type,
  810. 'size' => $attachment->size
  811. ];
  812. if ($this->save(false)) {
  813. return ArrayHelper::getValue($this, 'qrcode.url', '');
  814. }
  815. }
  816. } catch (Exception $e) {
  817. throw new ServerErrorHttpException($e->getMessage());
  818. }
  819. return $qrcodeUrl;
  820. }
  821. /**
  822. * 用户是否vip,并且未过期
  823. * @author nodelog
  824. */
  825. public function isVip()
  826. {
  827. //vip自动过期
  828. if ($this->is_vip) {
  829. $vip = VipUser::find()->where(['user_id' => $this->id])->orderBy(['end_time' => SORT_DESC])->one();
  830. if (!empty($vip) && $vip->isExpire()) {
  831. $this->is_vip = StatusEnum::STATUS_OFF;
  832. $this->save(false);
  833. }
  834. }
  835. return $this->is_vip;
  836. }
  837. /**
  838. * 获取当前vip
  839. * @author nodelog
  840. */
  841. public function getCurrentVip()
  842. {
  843. $now = time();
  844. return VipUser::find()->where(['user_id' => $this->id])->andWhere(['and', ['<=', 'start_time', $now], ['>', 'end_time', $now]])->one();
  845. }
  846. //
  847. // public function fields() {
  848. // $fields = parent::fields();
  849. //
  850. // $fields[] = 'dataCount';
  851. // return $fields;
  852. // }
  853. /**
  854. * 数据统计
  855. * @author nodelog
  856. */
  857. public function getDataCount()
  858. {
  859. $data = [
  860. [
  861. 'text' => '日课',
  862. 'count' => 0
  863. ],
  864. [
  865. 'text' => '总课',
  866. 'count' => 0
  867. ],
  868. [
  869. 'text' => '辅助课',
  870. 'count' => 0
  871. ],
  872. ];
  873. //每日功课
  874. // $data[0]['count'] = Data::find()->active()->andWhere(['user_id' => $this->id])->today()->count();
  875. //累积功课
  876. // $data[1]['count'] = Data::find()->active()->andWhere(['user_id' => $this->id])->count();
  877. //辅助功课
  878. // $userIds = VipUser::find()->active()->andWhere(['pay_user_id' => $this->id])->andWhere(['!=', 'user_id', $this->id])->select(['user_id'])->distinct()->column();
  879. // $data[2]['count'] = Data::find()->active()->andWhere(['in', 'user_id', $userIds])->count();
  880. //直接获取辅助榜数据
  881. // $helpCount = DataRank::find()->active()->andWhere(['user_id' => $this->id, 'level' => DataTypeEnum::TYPE_HELP])->total()->select(['count'])->scalar();
  882. // $data[2]['count'] = $helpCount ? $helpCount : 0;
  883. return $data;
  884. }
  885. }