FeedService.php 54 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510
  1. <?php
  2. namespace App\Services\Home;
  3. use App\Events\CompleteInfoRemind;
  4. use App\Exceptions\AlertException;
  5. use App\Jobs\FeedRecommendJob;
  6. use App\Models\Common\FeedAlgorithmModel;
  7. use App\Models\Deed\FriendsModel;
  8. use App\Models\Deed\InvitationCardModel;
  9. use App\Models\FlowerLogModel;
  10. use App\Models\PartnerModel;
  11. use App\Models\PraiseModel;
  12. use App\Models\User\FeedType4RemindModel;
  13. use App\Models\User\InviteConfigModel;
  14. use App\Models\User\SuperLikeModel;
  15. use App\Models\User\UserModel;
  16. use App\Models\User\UserStateModel;
  17. use App\Services\Service;
  18. use App\Services\Vendor\Geohash;
  19. use Carbon\Carbon;
  20. use Illuminate\Database\Eloquent\Builder;
  21. use Illuminate\Support\Facades\Redis;
  22. use Ixudra\Curl\Facades\Curl;
  23. use PocketBE\MsyPush\Jobs\RegistEventJob;
  24. /**
  25. * Class FeedService
  26. * @package App\Services\Home
  27. */
  28. class FeedService extends Service
  29. {
  30. /**
  31. * 获取卡片信息
  32. * @param PartnerModel|integer $arg
  33. * @param int|string $uid
  34. * @return PartnerModel
  35. */
  36. public function getPartner($arg, $uid)
  37. {
  38. if (is_int($arg)) {
  39. /** @var PartnerModel $data */
  40. $data = PartnerModel::where('id', $arg)->firstOrFail([
  41. 'id',
  42. 'uid',
  43. 'school',
  44. 'address',
  45. 'home',
  46. 'height',
  47. 'star',
  48. 'introduce',
  49. 'expect',
  50. 'sex',
  51. 'photo_src',
  52. 'check_photo',
  53. 'is_sell',
  54. 'photo_1',
  55. 'photo_1_check',
  56. 'photo_2',
  57. 'photo_2_check',
  58. 'photo_3',
  59. 'photo_3_check',
  60. 'photo_4',
  61. 'photo_4_check',
  62. 'voice',
  63. 'voice_check',
  64. 'praises',
  65. 'age',
  66. 'star',
  67. 'is_recommend',
  68. 'is_push_feed',
  69. 'feed_push_type',
  70. 'black_at',
  71. 'last_three_day_feed',
  72. ]);
  73. $data->black_at = $data->black_at < time() ? 0 : $data->black_at;
  74. } else {
  75. /** @var PartnerModel $arg */
  76. $data = $arg;
  77. }
  78. $data->photo_src = "https://oss.pocketuniversity.cn{$data->photo_src}";
  79. $data->photo_1 = "https://oss.pocketuniversity.cn{$data->photo_1}";
  80. $data->photo_2 = "https://oss.pocketuniversity.cn{$data->photo_2}";
  81. $data->photo_3 = "https://oss.pocketuniversity.cn{$data->photo_3}";
  82. $data->photo_4 = "https://oss.pocketuniversity.cn{$data->photo_4}";
  83. if (1 != $data->check_photo) {
  84. unset($data->photo_src);
  85. }
  86. if (1 == $data->photo_1_check) {
  87. } else {
  88. unset($data->photo_1);
  89. }
  90. if (1 == $data->photo_2_check) {
  91. } else {
  92. unset($data->photo_2);
  93. }
  94. if (1 == $data->photo_3_check) {
  95. } else {
  96. unset($data->photo_3);
  97. }
  98. if (1 != $data->photo_4_check) {
  99. unset($data->photo_4);
  100. }
  101. if (1 != $data->voice_check) {
  102. unset($data->voice);
  103. }
  104. unset($data->check_photo);
  105. unset($data->photo_1_check);
  106. unset($data->photo_2_check);
  107. unset($data->photo_3_check);
  108. unset($data->photo_4_check);
  109. unset($data->voice_check);
  110. /** @var UserModel $user */
  111. $user = UserModel::findOrFail($data->uid, [
  112. 'uid',
  113. 'headimgurl',
  114. 'nickname',
  115. 'be_vip_at',
  116. 'supvip_endat',
  117. 'weixin',
  118. 'qq',
  119. 'age',
  120. 'star',
  121. 'introduce',
  122. 'expect',
  123. 'height',
  124. 'sex',
  125. 'school',
  126. 'address',
  127. 'home',
  128. 'tag_1',
  129. 'tag_2',
  130. 'tag_3',
  131. 'tag_4',
  132. 'login_at',
  133. 'location',
  134. 'identity_auth',
  135. 'wx_auth',
  136. 'claim_tag',
  137. 'work_state',
  138. 'logoff_at',
  139. ]);
  140. /** @var PartnerModel $data */
  141. $key = "{beta:paint}";
  142. $bool = Redis::Sismember($key, $uid);
  143. if (($inviteConf = InviteConfigModel::find($data->uid))) {
  144. $user->task_question = $inviteConf->task_question;
  145. $user->task_sing = $inviteConf->task_sing;
  146. $user->task_question_data = $inviteConf->task_question_data ? true : false;
  147. $user->setAttribute('task_paint', $bool ? true : $inviteConf->task_paint);
  148. $user->setAttribute('task_sing_data', $inviteConf->task_sing_data ? true : false);
  149. } else {
  150. $user->task_question = false;
  151. $user->task_sing = false;
  152. $user->task_question_data = false;
  153. $user->setAttribute('task_paint', $bool);
  154. $user->setAttribute('task_sing_data', false);
  155. }
  156. $user->setAttribute('invite_cnt', InvitationCardModel::where('invite_uid', $data->uid)->count());
  157. // 与self的关系处理
  158. $self = array(
  159. 'friend' => false,
  160. 'praise' => false,
  161. 'invite' => [],
  162. 'superlike' => false,
  163. );
  164. if (is_int($uid)) {
  165. $friend = FriendsModel::where([['uid', $uid], ['friend_uid', $data->uid]])->first();
  166. if ($uid != $data->uid && collect($friend)->isEmpty()) {
  167. !empty($user->weixin) && $user->weixin = mb_substr($user->weixin, 0, 1) . "****" . mb_substr(
  168. $user->weixin,
  169. -1,
  170. 1
  171. );
  172. !empty($user->qq) && $user->qq = mb_substr($user->qq, 0, 1) . "****" . mb_substr($user->qq, -1, 1);
  173. }
  174. /** @var array $self */
  175. $self['friend'] = $friend;
  176. if (PraiseModel::where([['uid', $uid], ['partner_id', $data->id], ['type', 1]])->exists()) {
  177. $self['praise'] = true;
  178. }
  179. $invite = InvitationCardModel::where([
  180. ['uid', $uid],
  181. ['invite_uid', $data->uid],
  182. ['expired_at', '>', time()],
  183. ])->groupBy('question_type')->get(['question_type'])->pluck('question_type');
  184. $self['invite'] = $invite->toArray();
  185. if (SuperLikeModel::where([['uid', $uid], ['partner_id', $data->id]])->exists()) {
  186. $self['superlike'] = true;
  187. }
  188. }
  189. $data->setAttribute('user', $user);
  190. $data->setAttribute('self', $self);
  191. return $data;
  192. }
  193. /**
  194. * 获取用户算法方案和算法推荐结果
  195. * @param int $uid
  196. * @return FeedAlgorithmModel|Builder|mixed|null
  197. * @throws AlertException
  198. */
  199. public function randAlgorithm(int $uid)
  200. {
  201. $algorithms = FeedAlgorithmModel::where([
  202. ['open_at', '<', date('Y-m-d H:i:s')],
  203. ['end_at', '>', date('Y-m-d H:i:s')],
  204. ])->get();
  205. $total = $algorithms->sum('rate');
  206. $rand = rand(1, $total);
  207. $value = 0;
  208. foreach ($algorithms as $algorithm) {
  209. /** @var FeedAlgorithmModel $algorithm */
  210. $value = $value + $algorithm->rate;
  211. if ($rand <= $value) {
  212. UserStateModel::set($uid, 'algorithm', $algorithm->name);
  213. return $algorithm;
  214. }
  215. }
  216. return null;
  217. }
  218. /**
  219. * 获取算法推荐的集合
  220. * @param int $uid
  221. * @param int $sex 性别1男2女
  222. * @return array|null
  223. * @throws AlertException
  224. */
  225. public function algorithmRecommend(int $uid, int $sex = 1)
  226. {
  227. $current = UserStateModel::get($uid, 'algorithm');
  228. $selectAlgo = null;
  229. if (is_null($current)) {
  230. $selectAlgo = $this->randAlgorithm($uid);
  231. } else {
  232. $algorithm = FeedAlgorithmModel::where('name', $current)->first();
  233. if (collect($algorithm)->isEmpty() || !Carbon::now()->isBetween($algorithm->open_at, $algorithm->end_at)) {
  234. $selectAlgo = $this->randAlgorithm($uid);
  235. } else {
  236. $selectAlgo = $algorithm;
  237. }
  238. }
  239. if (is_null($selectAlgo)) {
  240. // 用户方案, 算法结果
  241. return ['N', null];
  242. } else {
  243. if ('N' == $selectAlgo->name) {
  244. // 用户方案, 算法结果
  245. return ['N', null];
  246. } else {
  247. if (1 == $sex) {
  248. $api = trim($selectAlgo->man_url . $uid . "?number=464656");
  249. } else {
  250. $api = trim($selectAlgo->woman_url . $uid . "?number=464656");
  251. }
  252. $resp = Curl::to($api)->withTimeout(1)->asJsonResponse(true)->get();
  253. return [$selectAlgo->name, $resp];
  254. }
  255. }
  256. }
  257. /**
  258. * 信息流-对检索的结果进行组合输出
  259. * @param $feedArr
  260. * @param int $sxo
  261. * @param int $take
  262. * @return array
  263. * @throws AlertException
  264. */
  265. public function feed($feedArr, int $sxo, int $take = 2)
  266. {
  267. // 不同用户层级分配的卡片层级比例
  268. $levelRates = array(
  269. 'A' => [
  270. 1 => [
  271. [
  272. 'pool' => 'likeme',
  273. 'weight' => 5,
  274. ],
  275. [
  276. 'pool' => 'pool',
  277. 'weight' => 95,
  278. 'attribute' => [
  279. [
  280. 'pool' => 'low',
  281. 'weight' => 10,
  282. ],
  283. [
  284. 'pool' => 'normal',
  285. 'weight' => 90,
  286. 'attribute' => [
  287. [
  288. 'pool' => 'select',
  289. 'weight' => 80,
  290. ],
  291. [
  292. 'pool' => 'recommend',
  293. 'weight' => 20,
  294. ],
  295. [
  296. 'pool' => 'new',
  297. 'weight' => 0,
  298. ],
  299. ],
  300. ],
  301. ],
  302. ],
  303. ],
  304. 2 => [
  305. [
  306. 'pool' => 'likeme',
  307. 'weight' => 5,
  308. ],
  309. [
  310. 'pool' => 'pool',
  311. 'weight' => 95,
  312. 'attribute' => [
  313. [
  314. 'pool' => 'low',
  315. 'weight' => 5,
  316. ],
  317. [
  318. 'pool' => 'normal',
  319. 'weight' => 95,
  320. 'attribute' => [
  321. [
  322. 'pool' => 'select',
  323. 'weight' => 80,
  324. ],
  325. [
  326. 'pool' => 'recommend',
  327. 'weight' => 20,
  328. ],
  329. [
  330. 'pool' => 'new',
  331. 'weight' => 0,
  332. ],
  333. ],
  334. ],
  335. ],
  336. ],
  337. ],
  338. ],
  339. 'B' => [
  340. 1 => [
  341. [
  342. 'pool' => 'likeme',
  343. 'weight' => 5,
  344. ],
  345. [
  346. 'pool' => 'pool',
  347. 'weight' => 95,
  348. 'attribute' => [
  349. [
  350. 'pool' => 'low',
  351. 'weight' => 25,
  352. ],
  353. [
  354. 'pool' => 'normal',
  355. 'weight' => 75,
  356. 'attribute' => [
  357. [
  358. 'pool' => 'select',
  359. 'weight' => 40,
  360. ],
  361. [
  362. 'pool' => 'recommend',
  363. 'weight' => 60,
  364. ],
  365. [
  366. 'pool' => 'new',
  367. 'weight' => 0,
  368. ],
  369. ],
  370. ],
  371. ],
  372. ],
  373. ],
  374. 2 => [
  375. [
  376. 'pool' => 'likeme',
  377. 'weight' => 5,
  378. ],
  379. [
  380. 'pool' => 'pool',
  381. 'weight' => 95,
  382. 'attribute' => [
  383. [
  384. 'pool' => 'low',
  385. 'weight' => 20,
  386. ],
  387. [
  388. 'pool' => 'normal',
  389. 'weight' => 80,
  390. 'attribute' => [
  391. [
  392. 'pool' => 'select',
  393. 'weight' => 40,
  394. ],
  395. [
  396. 'pool' => 'recommend',
  397. 'weight' => 60,
  398. ],
  399. [
  400. 'pool' => 'new',
  401. 'weight' => 0,
  402. ],
  403. ],
  404. ],
  405. ],
  406. ],
  407. ],
  408. ],
  409. 'C' => [
  410. 1 => [
  411. [
  412. 'pool' => 'likeme',
  413. 'weight' => 5,
  414. ],
  415. [
  416. 'pool' => 'pool',
  417. 'weight' => 95,
  418. 'attribute' => [
  419. [
  420. 'pool' => 'low',
  421. 'weight' => 25,
  422. ],
  423. [
  424. 'pool' => 'normal',
  425. 'weight' => 75,
  426. 'attribute' => [
  427. [
  428. 'pool' => 'select',
  429. 'weight' => 20,
  430. ],
  431. [
  432. 'pool' => 'recommend',
  433. 'weight' => 80,
  434. ],
  435. [
  436. 'pool' => 'new',
  437. 'weight' => 0,
  438. ],
  439. ],
  440. ],
  441. ],
  442. ],
  443. ],
  444. 2 => [
  445. [
  446. 'pool' => 'likeme',
  447. 'weight' => 5,
  448. ],
  449. [
  450. 'pool' => 'pool',
  451. 'weight' => 95,
  452. 'attribute' => [
  453. [
  454. 'pool' => 'low',
  455. 'weight' => 20,
  456. ],
  457. [
  458. 'pool' => 'normal',
  459. 'weight' => 80,
  460. 'attribute' => [
  461. [
  462. 'pool' => 'select',
  463. 'weight' => 20,
  464. ],
  465. [
  466. 'pool' => 'recommend',
  467. 'weight' => 80,
  468. ],
  469. [
  470. 'pool' => 'new',
  471. 'weight' => 0,
  472. ],
  473. ],
  474. ],
  475. ],
  476. ],
  477. ],
  478. ],
  479. 'D' => [
  480. 1 => [
  481. [
  482. 'pool' => 'likeme',
  483. 'weight' => 5,
  484. ],
  485. [
  486. 'pool' => 'pool',
  487. 'weight' => 95,
  488. 'attribute' => [
  489. [
  490. 'pool' => 'low',
  491. 'weight' => 25,
  492. ],
  493. [
  494. 'pool' => 'normal',
  495. 'weight' => 75,
  496. 'attribute' => [
  497. [
  498. 'pool' => 'select',
  499. 'weight' => 10,
  500. ],
  501. [
  502. 'pool' => 'recommend',
  503. 'weight' => 90,
  504. ],
  505. [
  506. 'pool' => 'new',
  507. 'weight' => 0,
  508. ],
  509. ],
  510. ],
  511. ],
  512. ],
  513. ],
  514. 2 => [
  515. [
  516. 'pool' => 'likeme',
  517. 'weight' => 5,
  518. ],
  519. [
  520. 'pool' => 'pool',
  521. 'weight' => 95,
  522. 'attribute' => [
  523. [
  524. 'pool' => 'low',
  525. 'weight' => 20,
  526. ],
  527. [
  528. 'pool' => 'normal',
  529. 'weight' => 80,
  530. 'attribute' => [
  531. [
  532. 'pool' => 'select',
  533. 'weight' => 10,
  534. ],
  535. [
  536. 'pool' => 'recommend',
  537. 'weight' => 90,
  538. ],
  539. [
  540. 'pool' => 'new',
  541. 'weight' => 0,
  542. ],
  543. ],
  544. ],
  545. ],
  546. ],
  547. ],
  548. ],
  549. 'E' => [
  550. 1 => [
  551. [
  552. 'pool' => 'likeme',
  553. 'weight' => 5,
  554. ],
  555. [
  556. 'pool' => 'pool',
  557. 'weight' => 95,
  558. 'attribute' => [
  559. [
  560. 'pool' => 'low',
  561. 'weight' => 25,
  562. ],
  563. [
  564. 'pool' => 'normal',
  565. 'weight' => 75,
  566. 'attribute' => [
  567. [
  568. 'pool' => 'select',
  569. 'weight' => 20,
  570. ],
  571. [
  572. 'pool' => 'recommend',
  573. 'weight' => 50,
  574. ],
  575. [
  576. 'pool' => 'new',
  577. 'weight' => 30,
  578. ],
  579. ],
  580. ],
  581. ],
  582. ],
  583. ],
  584. 2 => [
  585. [
  586. 'pool' => 'likeme',
  587. 'weight' => 5,
  588. ],
  589. [
  590. 'pool' => 'pool',
  591. 'weight' => 95,
  592. 'attribute' => [
  593. [
  594. 'pool' => 'low',
  595. 'weight' => 20,
  596. ],
  597. [
  598. 'pool' => 'normal',
  599. 'weight' => 80,
  600. 'attribute' => [
  601. [
  602. 'pool' => 'select',
  603. 'weight' => 20,
  604. ],
  605. [
  606. 'pool' => 'recommend',
  607. 'weight' => 50,
  608. ],
  609. [
  610. 'pool' => 'new',
  611. 'weight' => 30,
  612. ],
  613. ],
  614. ],
  615. ],
  616. ],
  617. ],
  618. ],
  619. 'F' => [
  620. 1 => [
  621. [
  622. 'pool' => 'likeme',
  623. 'weight' => 5,
  624. ],
  625. [
  626. 'pool' => 'pool',
  627. 'weight' => 95,
  628. 'attribute' => [
  629. [
  630. 'pool' => 'low',
  631. 'weight' => 25,
  632. ],
  633. [
  634. 'pool' => 'normal',
  635. 'weight' => 75,
  636. 'attribute' => [
  637. [
  638. 'pool' => 'select',
  639. 'weight' => 10,
  640. ],
  641. [
  642. 'pool' => 'recommend',
  643. 'weight' => 60,
  644. ],
  645. [
  646. 'pool' => 'new',
  647. 'weight' => 30,
  648. ],
  649. ],
  650. ],
  651. ],
  652. ],
  653. ],
  654. 2 => [
  655. [
  656. 'pool' => 'likeme',
  657. 'weight' => 5,
  658. ],
  659. [
  660. 'pool' => 'pool',
  661. 'weight' => 95,
  662. 'attribute' => [
  663. [
  664. 'pool' => 'low',
  665. 'weight' => 20,
  666. ],
  667. [
  668. 'pool' => 'normal',
  669. 'weight' => 80,
  670. 'attribute' => [
  671. [
  672. 'pool' => 'select',
  673. 'weight' => 10,
  674. ],
  675. [
  676. 'pool' => 'recommend',
  677. 'weight' => 60,
  678. ],
  679. [
  680. 'pool' => 'new',
  681. 'weight' => 30,
  682. ],
  683. ],
  684. ],
  685. ],
  686. ],
  687. ],
  688. ],
  689. 'G' => [
  690. 1 => [
  691. [
  692. 'pool' => 'likeme',
  693. 'weight' => 5,
  694. ],
  695. [
  696. 'pool' => 'pool',
  697. 'weight' => 95,
  698. 'attribute' => [
  699. [
  700. 'pool' => 'low',
  701. 'weight' => 25,
  702. ],
  703. [
  704. 'pool' => 'normal',
  705. 'weight' => 75,
  706. 'attribute' => [
  707. [
  708. 'pool' => 'select',
  709. 'weight' => 5,
  710. ],
  711. [
  712. 'pool' => 'recommend',
  713. 'weight' => 65,
  714. ],
  715. [
  716. 'pool' => 'new',
  717. 'weight' => 30,
  718. ],
  719. ],
  720. ],
  721. ],
  722. ],
  723. ],
  724. 2 => [
  725. [
  726. 'pool' => 'likeme',
  727. 'weight' => 5,
  728. ],
  729. [
  730. 'pool' => 'pool',
  731. 'weight' => 95,
  732. 'attribute' => [
  733. [
  734. 'pool' => 'low',
  735. 'weight' => 20,
  736. ],
  737. [
  738. 'pool' => 'normal',
  739. 'weight' => 80,
  740. 'attribute' => [
  741. [
  742. 'pool' => 'select',
  743. 'weight' => 5,
  744. ],
  745. [
  746. 'pool' => 'recommend',
  747. 'weight' => 65,
  748. ],
  749. [
  750. 'pool' => 'new',
  751. 'weight' => 30,
  752. ],
  753. ],
  754. ],
  755. ],
  756. ],
  757. ],
  758. ],
  759. );
  760. $disRates = array(
  761. 'likeme' => array(
  762. [
  763. 'min' => 0,
  764. 'max' => 20,
  765. 'weight' => 30,
  766. ],
  767. [
  768. 'min' => 20,
  769. 'max' => 50,
  770. 'weight' => 30,
  771. ],
  772. [
  773. 'min' => 50,
  774. 'max' => 100,
  775. 'weight' => 15,
  776. ],
  777. [
  778. 'min' => 100,
  779. 'max' => 200,
  780. 'weight' => 10,
  781. ],
  782. [
  783. 'min' => 200,
  784. 'max' => 300,
  785. 'weight' => 7,
  786. ],
  787. [
  788. 'min' => 300,
  789. 'max' => 400,
  790. 'weight' => 5,
  791. ],
  792. [
  793. 'min' => 400,
  794. 'max' => INF,
  795. 'weight' => 3,
  796. ],
  797. ),
  798. 'low' => array(
  799. [
  800. 'min' => 0,
  801. 'max' => 20,
  802. 'weight' => 30,
  803. ],
  804. [
  805. 'min' => 20,
  806. 'max' => 50,
  807. 'weight' => 30,
  808. ],
  809. [
  810. 'min' => 50,
  811. 'max' => 100,
  812. 'weight' => 15,
  813. ],
  814. [
  815. 'min' => 100,
  816. 'max' => 200,
  817. 'weight' => 10,
  818. ],
  819. [
  820. 'min' => 200,
  821. 'max' => 300,
  822. 'weight' => 7,
  823. ],
  824. [
  825. 'min' => 300,
  826. 'max' => 400,
  827. 'weight' => 5,
  828. ],
  829. [
  830. 'min' => 400,
  831. 'max' => INF,
  832. 'weight' => 3,
  833. ],
  834. ),
  835. 'new' => array(
  836. [
  837. 'min' => 0,
  838. 'max' => 20,
  839. 'weight' => 30,
  840. ],
  841. [
  842. 'min' => 20,
  843. 'max' => 50,
  844. 'weight' => 30,
  845. ],
  846. [
  847. 'min' => 50,
  848. 'max' => 100,
  849. 'weight' => 15,
  850. ],
  851. [
  852. 'min' => 100,
  853. 'max' => 200,
  854. 'weight' => 10,
  855. ],
  856. [
  857. 'min' => 200,
  858. 'max' => 300,
  859. 'weight' => 7,
  860. ],
  861. [
  862. 'min' => 300,
  863. 'max' => 400,
  864. 'weight' => 5,
  865. ],
  866. [
  867. 'min' => 400,
  868. 'max' => INF,
  869. 'weight' => 3,
  870. ],
  871. ),
  872. 'recommend' => array(
  873. [
  874. 'min' => 0,
  875. 'max' => 20,
  876. 'weight' => 30,
  877. ],
  878. [
  879. 'min' => 20,
  880. 'max' => 50,
  881. 'weight' => 30,
  882. ],
  883. [
  884. 'min' => 50,
  885. 'max' => 100,
  886. 'weight' => 15,
  887. ],
  888. [
  889. 'min' => 100,
  890. 'max' => 200,
  891. 'weight' => 10,
  892. ],
  893. [
  894. 'min' => 200,
  895. 'max' => 300,
  896. 'weight' => 7,
  897. ],
  898. [
  899. 'min' => 300,
  900. 'max' => 400,
  901. 'weight' => 5,
  902. ],
  903. [
  904. 'min' => 400,
  905. 'max' => INF,
  906. 'weight' => 3,
  907. ],
  908. ),
  909. 'select' => array(
  910. [
  911. 'min' => 0,
  912. 'max' => 20,
  913. 'weight' => 30,
  914. ],
  915. [
  916. 'min' => 20,
  917. 'max' => 50,
  918. 'weight' => 30,
  919. ],
  920. [
  921. 'min' => 50,
  922. 'max' => 100,
  923. 'weight' => 15,
  924. ],
  925. [
  926. 'min' => 100,
  927. 'max' => 200,
  928. 'weight' => 10,
  929. ],
  930. [
  931. 'min' => 200,
  932. 'max' => 300,
  933. 'weight' => 7,
  934. ],
  935. [
  936. 'min' => 300,
  937. 'max' => 400,
  938. 'weight' => 5,
  939. ],
  940. [
  941. 'min' => 400,
  942. 'max' => INF,
  943. 'weight' => 3,
  944. ],
  945. ),
  946. );
  947. // dump("开始:".microtime(true));
  948. $res = array();
  949. for ($i = 0; $i < $take; $i++) {
  950. // 滑卡奖励
  951. $flowerLog = new FlowerLogModel();
  952. if (is_int($feedArr['uid']) && $redpack = $flowerLog->redpack($feedArr['uid'])) {
  953. Redis::hincrby("session_msy_{$feedArr['uid']}", "feed_limit", 1);
  954. $res[] = array(
  955. 'type' => 1,
  956. 'data' => $redpack,
  957. );
  958. continue;
  959. }
  960. // dump(" 输出单元{$i}:" . microtime(true));
  961. $levelCnt = 0;
  962. do {
  963. // dump(" 输出单元{$i}定义检索条件:" . microtime(true));
  964. $poolList = $levelRates[$feedArr['feed_level']][$sxo];
  965. ++$levelCnt;
  966. if (0 == $feedArr['partner_id']) {
  967. $pool = "select"; // 新用户只看精选的 - 正常卡片-标记精选池分配比例
  968. } else {
  969. $poolArray = $this->getRandomList($poolList, 'weight');
  970. if ('pool' == $poolArray['pool']) {
  971. $poolArray = $this->getRandomList($poolArray['attribute'], 'weight');
  972. if ('normal' == $poolArray['pool']) {
  973. $poolArray = $this->getRandomList($poolArray['attribute'], 'weight');
  974. $pool = $poolArray['pool'];
  975. } else {
  976. $pool = $poolArray['pool'];
  977. }
  978. } else {
  979. $pool = $poolArray['pool'];
  980. }
  981. }
  982. $disList = $disRates[$pool];
  983. $disArray = $this->getRandomList($disList, 'weight');
  984. $reduceFeed = Redis::get("reduce_feed");
  985. if ($reduceFeed && $reduceFeed > 0) {
  986. $disArray = array(
  987. 'min' => 0,
  988. 'max' => INF,
  989. );
  990. }
  991. // dump(" 得到检索条件:性别:{$sxo};池:{$pool};min:{$disArray['min']};max:{$disArray['max']};" .microtime(true));
  992. $feed = $this->feedpartner($feedArr, $sxo, $pool, $disArray['min'], $disArray['max']);
  993. // Ntodo 移除没有的$poolList和$disList
  994. } while (collect($feed)->isEmpty() && $levelCnt < 3);
  995. if (collect($feed)->isEmpty()) {
  996. continue;
  997. } else {
  998. Redis::hincrby("session_msy_{$feedArr['uid']}", "feed_limit", 1);
  999. $res[] = array(
  1000. 'type' => $feed->feed_push_type,
  1001. 'data' => $feed,
  1002. );
  1003. continue;
  1004. }
  1005. }
  1006. return $res;
  1007. }
  1008. /**
  1009. * 检索feed流卡片
  1010. * @param array $feedUser 检索者信息
  1011. * @param int $sxo 输出性别
  1012. * @param string $pool 卡片等级
  1013. * @param int $minDis 最近距离
  1014. * @param float $maxDis 最远距离
  1015. * @return PartnerModel
  1016. * @throws AlertException
  1017. */
  1018. public function feedpartner(array $feedUser, int $sxo, string $pool, int $minDis = 0, float $maxDis = INF)
  1019. {
  1020. // LBS缓存key
  1021. $cacheLbskey = ($sxo == 1) ? "fpdx:user:locations:sell:boy" : "fpdx:user:locations:sell:girl";
  1022. // 看过的卡片id缓存key
  1023. $cacheIsSeedPartnerIds = "charge_feed_{$feedUser['uid']}";
  1024. // 信息流所以卡片分数缓存key
  1025. $cachePartnerScore = "feed:push:partner:score";
  1026. // 卡片等级缓存key
  1027. $searchUidskey = "feed:pool:{$pool}:sex:{$sxo}";
  1028. // 某人某条件搜索的缓存key
  1029. $cacheKey = "feed:user:{$feedUser['uid']}:sex:{$sxo}:pool:{$pool}:mindis:{$minDis}:maxdis:{$maxDis}";
  1030. // 某人某条件搜索的结果缓存key
  1031. $cacheResult = "feed:user:{$feedUser['uid']}:sex:{$sxo}:pool:{$pool}:mindis:{$minDis}:maxdis:{$maxDis}:result";
  1032. $feed = new PartnerModel();
  1033. $whereUid = Redis::smembers($cacheKey);
  1034. if (empty($whereUid)) {
  1035. // dump("未命中缓存:".microtime(true));
  1036. // 可查询的用户uid集合A
  1037. $where = array(['sex', $sxo], ['is_sell', 1], ['score', '>=', 0]);
  1038. switch ($pool) {
  1039. case 'likeme': // 喜欢我的
  1040. $useAlgorithm = false;
  1041. $uids = PraiseModel::where([
  1042. ['partner_id', $feedUser['partner_id']],
  1043. ['type', 1],
  1044. ])->get(['uid'])->pluck('uid')->toArray();
  1045. $searchUids = PartnerModel::where(array(['sex', $sxo], ['is_sell', 1]))->whereIn(
  1046. 'uid',
  1047. $uids
  1048. )->get(['uid'])->pluck('uid')->toArray();
  1049. break;
  1050. case 'select': // 正常卡片-标记精选池分配比例
  1051. $useAlgorithm = false; // 是否运用算法
  1052. $where[] = array('is_select', 1);
  1053. $searchUids = PartnerModel::where($where)->get(['uid'])->pluck('uid')->toArray();
  1054. break;
  1055. case 'low': // 低保池
  1056. $useAlgorithm = false; // 是否运用算法
  1057. $searchUids = Redis::Smembers($searchUidskey);
  1058. break;
  1059. case 'recommend': // 正常卡片-标记推荐池分配比例
  1060. $useAlgorithm = false; // 是否运用算法 true
  1061. $searchUids = Redis::Smembers($searchUidskey);
  1062. break;
  1063. case 'new': // 正常卡片-新卡片(未标记)池分配比例
  1064. $useAlgorithm = false; // 是否运用算法 true
  1065. $searchUids = Redis::Smembers($searchUidskey);
  1066. break;
  1067. default:
  1068. return $feed;
  1069. }
  1070. $whereUid = $searchUids;
  1071. // 看过的用户集合B
  1072. $hideIds = Redis::zrange($cacheIsSeedPartnerIds, 0, -1);
  1073. if (empty($hideIds)) {
  1074. $hideIds = array();
  1075. }
  1076. $isSeeUids = PartnerModel::whereIn('id', $hideIds)->get(['uid'])->pluck('uid')->toArray();
  1077. $whereUid = array_diff($whereUid, $isSeeUids);
  1078. if (empty($whereUid)) {
  1079. Redis::sadd($cacheKey, ...[-1]);
  1080. Redis::setex($cacheResult, 3600 * 2, 0);
  1081. Redis::expire($cacheKey, 3600 * 2);
  1082. return collect([]);
  1083. }
  1084. // LBS用户集合D
  1085. if (INF == $maxDis) {
  1086. $maxDisUids = $whereUid;
  1087. } else {
  1088. $maxDisUids = Redis::geoRadius(
  1089. $cacheLbskey,
  1090. $feedUser['lng'],
  1091. $feedUser['lat'],
  1092. $maxDis,
  1093. "km",
  1094. array('ASC')
  1095. );
  1096. }
  1097. if (0 == $minDis) {
  1098. $minDisUids = array();
  1099. } else {
  1100. $minDisUids = Redis::geoRadius(
  1101. $cacheLbskey,
  1102. $feedUser['lng'],
  1103. $feedUser['lat'],
  1104. $minDis,
  1105. "km",
  1106. array('ASC')
  1107. );
  1108. }
  1109. $disUids = array_diff($maxDisUids, $minDisUids);
  1110. $whereUid = array_intersect($whereUid, $disUids);
  1111. // 算法卡片用户集合C
  1112. $isAlgorithm = false;
  1113. if (is_integer($feedUser['uid'])) {
  1114. list($selectPlan, $algorithm) = $this->algorithmRecommend($feedUser['uid'], $feedUser['sex']);
  1115. } else {
  1116. list($selectPlan, $algorithm) = array('N', null);
  1117. }
  1118. if ($useAlgorithm && !is_null($algorithm)) {
  1119. $algorithmIds = array_column($algorithm, 'ItemId');
  1120. $algoHash = array_combine($algorithmIds, $algorithm);
  1121. $algorithmUids = PartnerModel::whereIn('id', $algorithmIds)->get(['id', 'uid'])->toArray();
  1122. $algorithmUids = array_column($algorithmUids, 'uid');
  1123. $byFeed = $selectPlan;
  1124. } else {
  1125. $algorithmUids = [];
  1126. $algoHash = [];
  1127. $byFeed = 'N';
  1128. }
  1129. // 结果集合E
  1130. $whereAUid = array_intersect($whereUid, $algorithmUids);
  1131. if (empty($whereAUid)) {
  1132. $algoHash = [];
  1133. $byFeed = 'N';
  1134. } else {
  1135. $whereUid = $whereAUid;
  1136. }
  1137. } else {
  1138. if (1 == abs($whereUid[0])) {
  1139. // dump("未命中缓存".microtime(true));
  1140. return collect([]);
  1141. }
  1142. // dump("命中缓存".microtime(true));
  1143. // 看过的用户集合B
  1144. $hideIds = Redis::zrange("charge_feed_{$feedUser['uid']}", 0, -1);
  1145. if (empty($hideIds)) {
  1146. $hideIds = array();
  1147. }
  1148. $isSeeUids = PartnerModel::whereIn('id', $hideIds)->get(['uid'])->pluck('uid')->toArray();
  1149. $whereUid = array_diff($whereUid, $isSeeUids);
  1150. if (is_integer($feedUser['uid'])) {
  1151. list($selectPlan, $algorithm) = $this->algorithmRecommend($feedUser['uid'], $feedUser['sex']);
  1152. } else {
  1153. list($selectPlan, $algorithm) = array('N', null);
  1154. }
  1155. if (!is_null($algorithm)) {
  1156. $algorithmIds = array_column($algorithm, 'ItemId');
  1157. $algoHash = array_combine($algorithmIds, $algorithm);
  1158. } else {
  1159. $algoHash = [];
  1160. }
  1161. $isAlgorithm = Redis::get($cacheResult) ?? 0;
  1162. if ($isAlgorithm) {
  1163. $byFeed = $selectPlan;
  1164. } else {
  1165. $byFeed = "N";
  1166. }
  1167. }
  1168. if (empty($whereUid)) {
  1169. Redis::sadd($cacheKey, ...[-1]);
  1170. Redis::setex($cacheResult, 3600 * 2, 0);
  1171. Redis::expire($cacheKey, 3600 * 2);
  1172. return collect([]);
  1173. }
  1174. $scoreRandomUids = array();
  1175. foreach ($whereUid as $wu) {
  1176. $scoreRandomUids[] = array(
  1177. 'uid' => $wu,
  1178. 'score' => rand(1, 100),
  1179. );
  1180. }
  1181. // dump(" 得到可用集合" . microtime(true));
  1182. // $whereUidScores = array_combine($whereUid, array_pad([], count($whereUid), 0));
  1183. // Redis::zadd($cachePartnerScoreWhereUid, $whereUidScores);
  1184. // Redis::zinterstore($cachePartnerScoreResult, [$cachePartnerScore, $cachePartnerScoreWhereUid]);
  1185. // $scoreUids = Redis::zrange($cachePartnerScoreResult, 0, -1, ['withscores' => true]);
  1186. // Redis::del([$cachePartnerScoreWhereUid, $cachePartnerScoreResult]);
  1187. // if (empty($scoreUids)) {
  1188. // Redis::sadd($cacheKey, ...[-1]);
  1189. // Redis::setex($cacheResult, 3600 * 2, 0);
  1190. // Redis::expire($cacheKey, 3600 * 2);
  1191. // return collect([]);
  1192. // } else {
  1193. // $scoreRandomUids = array();
  1194. // foreach ($scoreUids as $sk => $sv) {
  1195. // $scoreRandomUids[] = array(
  1196. // 'score' => $sv,
  1197. // 'uid' => $sk
  1198. // );
  1199. // }
  1200. // }
  1201. $resultUid = $this->getRandomList($scoreRandomUids, 'score');
  1202. // dump(" 加权随机" . microtime(true));
  1203. $cacheWhereUid = array_diff($whereUid, [$resultUid['uid']]);
  1204. if (!empty($cacheWhereUid)) {
  1205. Redis::sadd($cacheKey, ...$cacheWhereUid);
  1206. Redis::setex($cacheResult, 3600 * 2, $isAlgorithm ? 1 : 0);
  1207. Redis::expire($cacheKey, 3600 * 2);
  1208. }
  1209. $feed = PartnerModel::whereIn('uid', $resultUid)->where('is_sell', 1)->first();
  1210. if (!$feed) {
  1211. return collect([]);
  1212. }
  1213. $feed = $this->getPartner(/** @var PartnerModel $feed */ $feed, $feedUser['uid']);
  1214. if ($pool == 'low') {
  1215. $feed->setAttribute('feed_push_type', 5);
  1216. }
  1217. $attach = array(
  1218. 'belong_feed' => $selectPlan, // 用户所属方案
  1219. 'by_feed' => $byFeed, // 卡片的输出方案
  1220. 'algorithm_score' => 0, // 算法分数
  1221. 'user_level' => $feedUser['feed_level'], // 用户分级
  1222. 'partner_level' => $pool, // 卡片分级
  1223. );
  1224. if ($isAlgorithm) {
  1225. $attach['algorithm_score'] = $algoHash[$feed->id]['Score'];
  1226. }
  1227. $feed->setAttribute('attach', json_encode($attach));
  1228. Redis::zadd("charge_feed_{$feedUser['uid']}", [$feed->id => time()]);
  1229. Redis::expire("charge_feed_{$feedUser['uid']}", 86400 * 60);
  1230. // dump(" 输出:".microtime(true));
  1231. return $feed;
  1232. }
  1233. /**
  1234. * 加权随机数
  1235. * @param array $list 随机项
  1236. * @param string $weightKey 权重字段
  1237. * @return int|string|null
  1238. */
  1239. public function getRandomList(array $list, string $weightKey = "score")
  1240. {
  1241. $sum = 0;
  1242. $listPoint = array(0);
  1243. foreach ($list as $key => $value) {
  1244. if (0 > $value[$weightKey]) {
  1245. $value[$weightKey] = 1;
  1246. }
  1247. $sum += $value[$weightKey];
  1248. array_push($listPoint, $sum);
  1249. }
  1250. $num = rand(0, $sum);
  1251. for ($i = 0; $i < count($listPoint) - 1; $i++) {
  1252. if ($num >= $listPoint[$i] && $num <= $listPoint[$i + 1]) {
  1253. $elem = array_slice($list, $i, 1);
  1254. return array_pop($elem);
  1255. }
  1256. }
  1257. return array_pop(array_slice($list, 0, 1));
  1258. }
  1259. /**
  1260. * 获取用户和卡片之间的分数
  1261. * @param int $uid
  1262. * @param int $partner_id
  1263. * @return array
  1264. */
  1265. public function getScoreUid2Partner(int $uid, int $partner_id): array
  1266. {
  1267. $info = array();
  1268. $user = UserModel::find($uid);
  1269. /** @var UserModel $puser */
  1270. $puser = UserModel::where('partner_id', $partner_id)->firstOrFail();
  1271. $score = array(
  1272. 'score' => 0,
  1273. 'show' => "not_show",
  1274. );
  1275. // 预需求
  1276. $user_pre = explode(',', $user->claim_tag);
  1277. $puser_pre = explode(',', $puser->claim_tag);
  1278. $pre_request = count(array_intersect($user_pre, $puser_pre)) * 20;
  1279. if ($pre_request > $score['score']) {
  1280. $score['score'] = $pre_request;
  1281. $score['show'] = "pre_request";
  1282. }
  1283. // 工作状态
  1284. $work_state = 0;
  1285. if (!empty($puser->school)) {
  1286. switch ($user->work_state) {
  1287. case "工作党":
  1288. $work_state = 40;
  1289. break;
  1290. case "高中党":
  1291. case "大学党":
  1292. $work_state = 80;
  1293. break;
  1294. default:
  1295. $work_state = 60;
  1296. break;
  1297. }
  1298. }
  1299. if ($work_state > $score['score']) {
  1300. $score['score'] = $work_state;
  1301. $score['show'] = "work_state";
  1302. }
  1303. // 兴趣
  1304. $puser_tag2 = explode(',', $puser->tag_2);
  1305. $user_tag2 = explode(',', $user->tag_2);
  1306. $puser_tag3 = explode(',', $puser->tag_3);
  1307. $user_tag3 = explode(',', $user->tag_3);
  1308. $puser_tag4 = explode(',', $puser->tag_4);
  1309. $user_tag4 = explode(',', $user->tag_4);
  1310. $intersect_tag2 = array_intersect($puser_tag2, $user_tag2);
  1311. $intersect_tag3 = array_intersect($puser_tag3, $user_tag3);
  1312. $intersect_tag4 = array_intersect($puser_tag4, $user_tag4);
  1313. $info['tags'] = compact('intersect_tag2', 'intersect_tag3', 'intersect_tag4');
  1314. $cnt = count($intersect_tag2) + count($intersect_tag3) + count($intersect_tag4);
  1315. $tag = $cnt * 10;
  1316. if ($tag > $score['score']) {
  1317. $score['score'] = $tag;
  1318. $score['show'] = "tag";
  1319. }
  1320. // 身高
  1321. if ($user->height != 0 && $puser->height != 0) {
  1322. if ($user->sex == 1) {
  1323. $height = ceil(100 / abs($user->height / 1.09 - $puser->height));
  1324. } else {
  1325. $height = ceil(100 / abs($puser->height / 1.09 - $user->height));
  1326. }
  1327. if ($height > $score['score']) {
  1328. $score['score'] = $height;
  1329. $score['show'] = "height";
  1330. }
  1331. }
  1332. // 家乡
  1333. $home = 0;
  1334. if (!empty($puser->home)) {
  1335. if ($puser->home == $user->home) {
  1336. $home = 100;
  1337. }
  1338. if ($home > $score['score']) {
  1339. $score['score'] = $home;
  1340. $score['show'] = "home";
  1341. }
  1342. }
  1343. // 距离
  1344. $geo = new Geohash();
  1345. $dis = $geo->getDistance($user->lat, $user->lng, $puser->lat, $puser->lng) + rand(1000, 5000);
  1346. return array($puser->location, $dis, $score, $info);
  1347. }
  1348. /**
  1349. * feed流每日滑卡片限制
  1350. * @param int $uid
  1351. * @return bool
  1352. */
  1353. public function limit(int $uid)
  1354. {
  1355. $last_time = Redis::hget("session_msy_{$uid}", "last_feed_time") ?? time();
  1356. if ($last_time < mktime(0, 0, 0)) {
  1357. Redis::hset("session_msy_{$uid}", "feed_limit", 0);
  1358. Redis::hset("session_msy_{$uid}", "flower_limit", 0);
  1359. Redis::hset("session_msy_{$uid}", "hd_cnt", 0);
  1360. Redis::hset("session_msy_{$uid}", "init_recommend_queues", 0);
  1361. $count = Redis::zcount("fpdx:feed:thumb:{$uid}", 0, "+inf");
  1362. if ($count <= 10) {
  1363. Redis::hset("session_msy_{$uid}", "thumbme_limit", 2);
  1364. } elseif ($count > 10 && $count < 50) {
  1365. Redis::hset("session_msy_{$uid}", "thumbme_limit", 5);
  1366. } else {
  1367. Redis::hset("session_msy_{$uid}", "thumbme_limit", 10);
  1368. }
  1369. }
  1370. $limit = Redis::hget("session_msy_{$uid}", "hd_cnt");
  1371. $low_limit = Redis::hget("session_msy_{$uid}", "feed_limit");
  1372. Redis::hset("session_msy_{$uid}", "last_feed_time", time());
  1373. Redis::expire("session_msy_{$uid}", 86400);
  1374. if (($limit > 200 || $low_limit > 400) && !in_array($uid, [94302, 98047, 10771042])) {
  1375. return false;
  1376. } else {
  1377. if (0 == Redis::hget("session_msy_{$uid}", "init_recommend_queues")) {
  1378. FeedRecommendJob::dispatch($uid);
  1379. Redis::hset("session_msy_{$uid}", "init_recommend_queues", 1);
  1380. }
  1381. Redis::hincrby("session_msy_{$uid}", "feed_count", 1);
  1382. return true;
  1383. }
  1384. }
  1385. /**
  1386. * 获取点赞队列存量
  1387. * @param int $uid
  1388. * @return int
  1389. */
  1390. public function getHasThumb(int $uid)
  1391. {
  1392. $count = Redis::zcount("fpdx:feed:thumb:{$uid}", 0, "+inf");
  1393. return $count;
  1394. }
  1395. /**
  1396. * 提醒TA补全信息
  1397. * @param int $uid
  1398. * @param int $remind_uid
  1399. * @param $type
  1400. * @return bool
  1401. */
  1402. public function remindType4(int $uid, int $remind_uid, $type): bool
  1403. {
  1404. // 我提醒过
  1405. if (
  1406. FeedType4RemindModel::where([
  1407. ['uid', $uid],
  1408. ['is_remind_uid', $remind_uid],
  1409. ['is_update_feedback_at', 0],
  1410. ['type', $type],
  1411. ])->exists()
  1412. ) {
  1413. return false;
  1414. }
  1415. FeedType4RemindModel::create([
  1416. 'uid' => $uid,
  1417. 'is_remind_uid' => $remind_uid,
  1418. 'type' => $type,
  1419. ]);
  1420. // 被提醒过两次以上则不发送
  1421. if (FeedType4RemindModel::where(['is_remind_uid' => $remind_uid, 'type' => $type])->count() > 2) {
  1422. return false;
  1423. }
  1424. switch ($type) {
  1425. case '1':
  1426. // 发起提醒事件
  1427. $nickname = UserModel::find($uid)->value('nickname');
  1428. event(new CompleteInfoRemind(UserModel::find($remind_uid), $nickname));
  1429. break;
  1430. case '2':
  1431. // 通知队列
  1432. $to_user = UserModel::find($remind_uid);
  1433. $from_user = UserModel::find($uid);
  1434. $payload = [
  1435. 'to_user' => $to_user->getAuth(),
  1436. 'user' => $to_user->toArray(),
  1437. 'from_user' => $from_user->toArray(),
  1438. ];
  1439. dispatch(new RegistEventJob(100009, $payload))->onQueue("{push}");
  1440. break;
  1441. case '3':
  1442. // 通知队列
  1443. $to_user = UserModel::find($remind_uid);
  1444. $from_user = UserModel::find($uid);
  1445. $payload = [
  1446. 'to_user' => $to_user->getAuth(),
  1447. 'user' => $to_user->toArray(),
  1448. 'from_user' => $from_user->toArray(),
  1449. ];
  1450. dispatch(new RegistEventJob(100008, $payload))->onQueue("{push}");
  1451. break;
  1452. }
  1453. return true;
  1454. }
  1455. }