User.php 28 KB

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