TopService.php 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. <?php
  2. /**
  3. * 排行榜
  4. * Created by PhpStorm.
  5. * User: guanxl
  6. * Date: 2018/3/27
  7. * Time: 9:13
  8. */
  9. namespace App\Services;
  10. use App\Models\User;
  11. use App\Traits\Singleton;
  12. use Illuminate\Support\Facades\DB;
  13. use Illuminate\Support\Facades\Redis;
  14. class TopService
  15. {
  16. use Singleton;
  17. const KNOWLEDGE_TOP = "bs_top:km";
  18. const JOIN_TOP = "bs_top:join";
  19. const JOIN_RATE_TOP = "bs_top:joinrate";
  20. const KM_AVG_TOP = "bs_top:kmavg";
  21. const PK_TOP = "bs_top:users:pk";
  22. const KM_TOP = "bs_top:users:km";
  23. const TOP_USERS = "bs_top:users";
  24. /**
  25. * @param $activityId
  26. */
  27. protected function cacheDepartmentTop($activityId){
  28. $datas = DB::select("select count(*) as user_num,sum(is_blockade_success_copy) as sum_is_blockade_success,sum(knowledge_money)as sum_knowledge_money,department_id,avg(knowledge_money) as avg_knowledge_money from bs_users where department_id>0 and status=1 and activity_id={$activityId}
  29. GROUP BY department_id");
  30. foreach ($datas as $data){
  31. $joinRate = 0;
  32. if($data->user_num>0){
  33. $joinRate = ($data->sum_is_blockade_success/$data->user_num)*100;
  34. }
  35. Redis::zAdd(self::KNOWLEDGE_TOP.":".$activityId,$data->sum_knowledge_money,$data->department_id);
  36. Redis::zAdd(self::JOIN_TOP.":".$activityId,$data->sum_is_blockade_success,$data->department_id);
  37. Redis::zAdd(self::JOIN_RATE_TOP.":".$activityId,$joinRate,$data->department_id);
  38. Redis::zAdd(self::KM_AVG_TOP.":".$activityId,$data->avg_knowledge_money,$data->department_id);
  39. }
  40. Redis::expire(self::KNOWLEDGE_TOP.":".$activityId,300);
  41. Redis::expire(self::JOIN_RATE_TOP.":".$activityId,300);
  42. Redis::expire(self::JOIN_TOP.":".$activityId,300);
  43. Redis::expire(self::KM_AVG_TOP.":".$activityId,300);
  44. }
  45. /**
  46. * 个人知识币全行排行榜信息
  47. * @param $activityId
  48. * @param string $limit
  49. * @return mixed
  50. */
  51. public function personKmTop($activityId,$limit = "")
  52. {
  53. return $this->getKmTop($activityId,$limit);
  54. }
  55. /**
  56. * 得到用户在全行的排名
  57. * @param $activityId
  58. * @param $userId
  59. * @return mixed
  60. */
  61. public function personKmRank($activityId,$userId)
  62. {
  63. return $this->getKmRank($activityId,$userId);
  64. }
  65. /**
  66. * 所有用户在全行的PK排名
  67. * @param $activityId
  68. * @param string $limit
  69. * @return mixed
  70. */
  71. public function personPktop($activityId,$limit=""){
  72. return $this->getPkTop($activityId,$limit);
  73. }
  74. /**
  75. * 当前用户在全行的排名
  76. * @param $activityId
  77. * @param $userId
  78. * @return int
  79. */
  80. public function personPkRank($activityId,$userId)
  81. {
  82. return $this->getPkRank($activityId,$userId);
  83. }
  84. /**
  85. * 现在1000名的知识币
  86. * 可以获得奖项的知识币
  87. * @param $activityId
  88. * @param int $rank
  89. * @return int
  90. */
  91. public function prizeKmRank($activityId,$rank = 1000)
  92. {
  93. $users = User::where("activity_id",$activityId)->where("status",1)
  94. ->where("is_blockade_success",1)
  95. ->orderBy("knowledge_money","desc")
  96. ->pluck("knowledge_money","user_id");
  97. $users = collect($users)->toArray();
  98. $i=0;
  99. foreach ($users as $key=>$knowledgeMoney){
  100. $i++;
  101. if($i==$rank){
  102. return $knowledgeMoney;
  103. }
  104. }
  105. return 0;
  106. }
  107. /**
  108. * 个人知识币分行排行榜信息
  109. * @param $activityId
  110. * @param $departmentId
  111. * @param string $limit
  112. * @return mixed
  113. */
  114. public function personKmDepartmentTop($activityId,$departmentId,$limit = "")
  115. {
  116. $userIds = DepartmentService::getInstance()->getUserIdsByDepartmentId($departmentId);
  117. $users = [];
  118. if($userIds){
  119. $users = $this->getUsers($activityId,collect($userIds)->toArray());
  120. }
  121. if($limit>0){
  122. $users = collect($users)->sortByDesc("knowledge_money")->values()->take($limit);
  123. }else{
  124. $users = collect($users)->sortByDesc("knowledge_money")->values()->all();
  125. }
  126. return $users;
  127. }
  128. /**
  129. * 得到用户在分行的排名
  130. * @param $activityId
  131. * @param $userId
  132. * @param $departmentId
  133. * @return mixed
  134. */
  135. public function personKmDepartmentRank($activityId,$userId, $departmentId)
  136. {
  137. $userIds = DepartmentService::getInstance()->getUserIdsByDepartmentId($departmentId);
  138. $users = [];
  139. if($userIds){
  140. $users = $this->getUsers($activityId,collect($userIds)->toArray());
  141. }
  142. $users = collect($users)->sortByDesc("knowledge_money")->values()->all();
  143. $i=0;
  144. foreach ($users as $user){
  145. $i++;
  146. if($user["user_id"]==$userId){
  147. return $i;
  148. }
  149. }
  150. }
  151. /**
  152. * 获取所有分行员工完成必答排行
  153. * @param $activityId
  154. * @param string $limit
  155. * @return mixed
  156. */
  157. public function departmentJoinTop($activityId,$limit = "")
  158. {
  159. $redisKey = self::JOIN_TOP . ":".$activityId;
  160. if(!Redis::exists($redisKey)){
  161. $this->cacheDepartmentTop($activityId);
  162. }
  163. $options = array('withscores' => true);
  164. if ($limit) {
  165. $options["limit"] = $limit;
  166. }
  167. return Redis::zRevrangebyscore($redisKey, "+inf", "-inf", $options);
  168. }
  169. /**
  170. * 获取所有分行的总知识币
  171. * @param $activityId
  172. * @param string $limit
  173. * @return mixed
  174. */
  175. public function departmentKmTop($activityId,$limit="")
  176. {
  177. $redisKey = self::KNOWLEDGE_TOP . ":".$activityId;
  178. if(!Redis::exists($redisKey)){
  179. $this->cacheDepartmentTop($activityId);
  180. }
  181. $options = array('withscores' => true);
  182. if ($limit) {
  183. $options["limit"] = $limit;
  184. }
  185. return Redis::zRevrangebyscore($redisKey, "+inf", "-inf", $options);
  186. }
  187. /**
  188. * 获取分行参与率的排行榜
  189. * @param $activityId
  190. * @param string $limit
  191. * @return
  192. */
  193. public function departmentJoinRateTop($activityId,$limit = "")
  194. {
  195. $redisKey = self::JOIN_RATE_TOP . ":".$activityId;
  196. if(!Redis::exists($redisKey)){
  197. $this->cacheDepartmentTop($activityId);
  198. }
  199. $options = array('withscores' => true);
  200. if ($limit) {
  201. $options["limit"] = $limit;
  202. }
  203. return Redis::zRevrangebyscore($redisKey, "+inf", "-inf", $options);
  204. }
  205. /**
  206. * 获取分行平均分排行榜
  207. * @param $limit
  208. * @return mixed
  209. */
  210. public function departmentKmAvgTop($activityId,$limit = "")
  211. {
  212. $redisKey = self::KM_AVG_TOP . ":".$activityId;
  213. if(!Redis::exists($redisKey)){
  214. $this->cacheDepartmentTop($activityId);
  215. }
  216. $options = array('withscores' => true);
  217. if ($limit) {
  218. $options["limit"] = $limit;
  219. }
  220. return Redis::zRevrangebyscore($redisKey, "+inf", "-inf", $options);
  221. }
  222. /**
  223. * 某分行的排名
  224. * @param $activityId
  225. * @param $departmentId
  226. * @return array
  227. */
  228. public function departmentJoinRateRank($activityId,$departmentId)
  229. {
  230. $redisKey = self::JOIN_RATE_TOP . ":".$activityId;
  231. if(!Redis::exists($redisKey)){
  232. $this->cacheDepartmentTop($activityId);
  233. }
  234. $rank = Redis::zRevrank($redisKey, $departmentId);
  235. if (is_null($rank)) {
  236. return ["index" => 0, "rate" => 0];
  237. } else {
  238. $rate = Redis::zScore($redisKey, $departmentId);
  239. return ["index" => $rank + 1, "rate" => $rate];
  240. }
  241. }
  242. /**
  243. * 某分行的排名
  244. * @param $departmentId
  245. * @return array
  246. */
  247. public function departmentKmAvgRank($activityId,$departmentId)
  248. {
  249. $redisKey = self::KM_AVG_TOP . ":".$activityId;
  250. if(!Redis::exists($redisKey)){
  251. $this->cacheDepartmentTop($activityId);
  252. }
  253. $rank = Redis::zRevrank($redisKey, $departmentId);
  254. if (is_null($rank)) {
  255. return ["index" => 0, "avg_knowledge_money" => 0];
  256. } else {
  257. $avgKm = Redis::zScore($redisKey, $departmentId);
  258. return ["index" => $rank + 1, "avg_knowledge_money" => round($avgKm,2)];
  259. }
  260. }
  261. /**
  262. * 获得用户排行信息
  263. * @param $activityId
  264. * @param array $userIds
  265. * @return array
  266. */
  267. public function getUsers($activityId,$userIds=[]){
  268. $redisKey = self::TOP_USERS.":".$activityId;
  269. if(!Redis::exists($redisKey)){
  270. $departments = DepartmentService::getInstance()->all($activityId);
  271. $pagesize = 5000;
  272. $count = User::where("activity_id",$activityId)->where("status",1)->count();
  273. $pageCount = ceil($count/$pagesize);
  274. for ($page=0;$page<$pageCount;$page++){
  275. $users = User::where("activity_id",$activityId)->where("status",1)->offset($page*$pagesize)->limit($pagesize)->get([
  276. "user_id","name","avatar","department_id","knowledge_money","user_level","user_star"
  277. ]);
  278. $redisData = [];
  279. foreach ($users as $user){
  280. $user = collect($user)->toArray();
  281. $user["department_name"] = empty($departments[$user["department_id"]])? "":$departments[$user["department_id"]];
  282. $redisData[$user["user_id"]] = json_encode($user,256);
  283. }
  284. if($redisData){
  285. Redis::hmset($redisKey,$redisData);
  286. }
  287. }
  288. Redis::expire($redisKey,864000);
  289. }
  290. if(empty($userIds)){
  291. $users = Redis::hgetall($redisKey);
  292. }else{
  293. $users = Redis::hmget($redisKey,$userIds);
  294. }
  295. $datas = [];
  296. foreach ($users as $key=>$val){
  297. $datas[$key] = json_decode($val,true);
  298. }
  299. return $datas;
  300. }
  301. /**
  302. * 更新用户的排名信息
  303. * @param $userId
  304. * @return mixed
  305. */
  306. public function updateUserTop($userId){
  307. $user = UserService::getInstance()->getUser($userId,"",true);
  308. if($user){
  309. $activityId = $user["activity_id"];
  310. $redisData = [
  311. "user_id" => $userId,
  312. "name" => $user["name"],
  313. "avatar" => $user["avatar"],
  314. "department_id" => $user["department_id"],
  315. "department_name" => DepartmentService::getInstance()->getDepartmentName($user["department_id"]),
  316. "knowledge_money" => $user["knowledge_money"],
  317. "user_level" => $user["user_level"],
  318. "user_star" => $user["user_star"]
  319. ];
  320. if(Redis::exists(self::TOP_USERS . ":".$activityId)) {
  321. Redis::hset(self::TOP_USERS . ":" . $activityId, $userId, json_encode($redisData, 256));
  322. }
  323. if(Redis::exists(self::KM_TOP . ":".$activityId)){
  324. Redis::zadd(self::KM_TOP . ":".$activityId,$user["knowledge_money"],$userId);
  325. }
  326. if(Redis::exists(self::PK_TOP . ":".$activityId)) {
  327. Redis::zadd(self::PK_TOP . ":" . $activityId, $user["user_level"] * 1000 + $user["user_star"], $userId);
  328. }
  329. return true;
  330. }
  331. return false;
  332. }
  333. /**
  334. * 取用户的km段位排名
  335. * @param $activityId
  336. * @param $userId
  337. * @return int
  338. */
  339. public function getKmRank($activityId,$userId){
  340. $redisKey = self::KM_TOP . ":".$activityId;
  341. $this->getKmTop($activityId,1);
  342. $rank = Redis::zRevrank($redisKey, $userId);
  343. if (is_null($rank)) {
  344. return 0;
  345. } else {
  346. return $rank + 1;
  347. }
  348. }
  349. /**
  350. * 取用户的PK段位排名
  351. * @param $activityId
  352. * @param $userId
  353. * @return int
  354. */
  355. public function getPkRank($activityId,$userId){
  356. $redisKey = self::PK_TOP . ":".$activityId;
  357. $this->getPkTop($activityId,1);
  358. $rank = Redis::zRevrank($redisKey, $userId);
  359. if (is_null($rank)) {
  360. return 0;
  361. } else {
  362. return $rank + 1;
  363. }
  364. }
  365. /**
  366. * PK段位排行榜
  367. * @param $activityId
  368. * @param int $limit
  369. * @return mixed
  370. */
  371. public function getPkTop($activityId,$limit=100){
  372. $redisKey = self::PK_TOP . ":".$activityId;
  373. if(!Redis::exists($redisKey)){
  374. $users = $this->getUsers($activityId);
  375. foreach ($users as $key=>$val){
  376. Redis::zadd($redisKey,$val["user_level"]*1000+$val["user_star"],$key);
  377. }
  378. Redis::expire($redisKey,84600);
  379. }
  380. $options = [];
  381. if ($limit) {
  382. $options["limit"] = [0,$limit];
  383. }
  384. $datas = [];
  385. $userIds = Redis::zRevrangebyscore($redisKey, "+inf", "-inf", $options);
  386. if($userIds){
  387. $datas = $this->getUsers($activityId,$userIds);
  388. }
  389. return $datas;
  390. }
  391. /**
  392. * 知识币排行
  393. * @param $activityId
  394. * @param int $limit
  395. * @return mixed
  396. */
  397. public function getKmTop($activityId,$limit=100){
  398. $redisKey = self::KM_TOP . ":".$activityId;
  399. if(!Redis::exists($redisKey)){
  400. $users = $this->getUsers($activityId);
  401. foreach ($users as $key=>$val){
  402. Redis::zadd($redisKey,$val["knowledge_money"],$key);
  403. }
  404. Redis::expire($redisKey,84600);
  405. }
  406. $options = [];
  407. if ($limit) {
  408. $options["limit"] = [0,$limit];
  409. }
  410. $userIds = Redis::zRevrangebyscore($redisKey, "+inf", "-inf", $options);
  411. $datas = [];
  412. if($userIds){
  413. $datas = $this->getUsers($activityId,$userIds);
  414. }
  415. return $datas;
  416. }
  417. }