SpreadService.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. <?php
  2. namespace addons\DoubleCopy\service;
  3. use common\traits\ErrorTrait;
  4. use addons\DoubleCopy\common\models\DoubleCopyUser;
  5. use addons\DoubleCopy\common\models\DoubleCopySpread;
  6. use addons\DoubleCopy\common\models\DoubleCopyLevel;
  7. use addons\DoubleCopy\common\enums\DoubleCopyEnum;
  8. use common\enums\StatusEnum;
  9. use yii\db\Exception;
  10. use Yii;
  11. use yii\helpers\Json;
  12. use common\helpers\LockHelper;
  13. use common\models\user\UserPartitionRelationship;
  14. class SpreadService
  15. {
  16. use ErrorTrait;
  17. public static $mallId = 0;
  18. public static $admin;
  19. /**
  20. * 绑定上下级关系处理
  21. *
  22. * @param int $pullUserId 选择下级用户ID
  23. * @param int $pushUserId 绑定上级用户ID
  24. * @param int $mallId 商城ID
  25. * @return bool
  26. */
  27. public static function bindingHandle($pullUserId,$pushUserId,$mallId,$admin)
  28. {
  29. self::$mallId = $mallId;
  30. self::$admin = $admin;
  31. $pullUser = DoubleCopyUser::find()->select('id,user_id,pos,pid,mall_id,help_num,team_num')->where(['mall_id'=>$mallId,'user_id'=>$pullUserId,'status' => StatusEnum::ENABLED])->asArray()->one();
  32. $pushUser = DoubleCopyUser::find()->select('id,user_id,pos,pid,mall_id,help_num,team_num')->where(['mall_id'=>$mallId,'user_id'=>$pushUserId,'status' => StatusEnum::ENABLED])->asArray()->one();
  33. //修改助力用户 团队数量 修改PID 等
  34. self::editHelpTeamNum($pullUser,$pushUser);
  35. //添加数据
  36. self::addSpread($pullUserId,$pushUserId,$pullUser['pid']);
  37. }
  38. /**
  39. * 绑定上级为平台
  40. *
  41. * @param int $pullUserId 选择下级用户ID
  42. * @param int $pushUserId 绑定上级用户ID
  43. * @param int $mallId 商城ID
  44. * @return bool
  45. */
  46. public static function bindingHandlePlatform($pullUserId,$mallId,$admin)
  47. {
  48. self::$mallId = $mallId;
  49. self::$admin = $admin;
  50. $pullUser = DoubleCopyUser::find()->select('id,user_id,pos,pid,mall_id,help_num,team_num')->where(['mall_id'=>$mallId,'user_id'=>$pullUserId,'status' => StatusEnum::ENABLED])->asArray()->one();
  51. $pushUser = DoubleCopyUser::find()->select('id,user_id,pos,pid,mall_id,help_num,team_num')->where(['mall_id'=>$mallId,'user_id'=>$pullUser['pid'],'status' => StatusEnum::ENABLED])->asArray()->one();
  52. //修改助力用户 团队数量 修改PID 等
  53. self::editHelpTeamNumPlatform($pullUser,$pushUser);
  54. //添加数据
  55. self::addSpread($pullUserId,0,$pullUser['pid']);
  56. }
  57. /**
  58. * 绑定上级为平台,修改助力用户 团队数量 修改PID
  59. *
  60. * @param [type] $pullUser 拉取下级用户
  61. * @param [type] $pushUser 绑定上级用户
  62. * @return void
  63. */
  64. public static function editHelpTeamNumPlatform($pullUser,$pushUser)
  65. {
  66. //修改该用户上级的团队数量(team_num)、助力用户数量(help_num)
  67. $userPidAllAttrs = self::recursionGetAllPidUser($pullUser);
  68. if($userPidAllAttrs) self::calculateTeamNum($userPidAllAttrs,'-',$pullUser['team_num']);
  69. if($pullUser['pid']) self::calculateHelpNum($pullUser['pid'],'-');
  70. //修改该用户的兄弟用户,pos都要-1个位置
  71. self::editPullPos($pullUser);
  72. //修改该用户的pid、topid、pos为0
  73. $editPid = DoubleCopyUser::findOne($pullUser['id']);
  74. $editPid->pid = 0;
  75. $editPid->topid = 0;
  76. $editPid->pos = 0;
  77. if(!$editPid->save()) throw new Exception('修改该用户的pid、topid、pos为0,失败');
  78. // 根据用户id,递归找出所有下级中,pos=1 || pos=2的下级,把这些用户的topid改为0
  79. if($pullUser['pid']) {
  80. $result = [];
  81. self::findDescendants($pullUser['user_id'], $result);
  82. DoubleCopyUser::updateAll(['topid' => 0, 'updated_at' => time()], ['id' => $result]);
  83. }
  84. }
  85. // 根据用户id,递归找出所有下级中,pos=1 || pos=2的下级
  86. public static function findDescendants($userId, &$result = [])
  87. {
  88. $children = DoubleCopyUser::find()
  89. ->select(['id', 'user_id', 'pid', 'topid', 'pos'])
  90. ->where(['pid' => $userId, 'status' => StatusEnum::ENABLED])
  91. ->asArray()->all();
  92. foreach ($children as $child) {
  93. // 如果 pos 为 1 或 2,加入结果
  94. if ($child['pos'] == 1 || $child['pos'] == 2) {
  95. $result[] = $child['id'];
  96. }
  97. // 递归查找下级
  98. self::findDescendants($child['user_id'], $result);
  99. }
  100. }
  101. /**
  102. * 修改助力用户 团队数量 修改PID
  103. *
  104. * @param [type] $pullUser 拉取下级用户
  105. * @param [type] $pushUser 绑定上级用户
  106. * @return void
  107. */
  108. public static function editHelpTeamNum($pullUser,$pushUser)
  109. {
  110. //修改拉取上级用户数量 团队 助力用户数量
  111. $userPidAllAttrs = self::recursionGetAllPidUser($pullUser);
  112. if($userPidAllAttrs) self::calculateTeamNum($userPidAllAttrs,'-',$pullUser['team_num']);
  113. if($pullUser['pid']) self::calculateHelpNum($pullUser['pid'],'-');
  114. //修改拉取POS位置
  115. self::editPullPos($pullUser);
  116. //修改绑定上级用户 团队 助力用户数量
  117. $userPushAllAttrs = self::recursionGetAllPidUser($pushUser);
  118. $userPushAllAttrs[] = $pushUser;
  119. self::calculateTeamNum($userPushAllAttrs,'+',$pullUser['team_num']);
  120. if($pushUser['user_id']) self::calculateHelpNum($pushUser['user_id'],'+');
  121. //修改推送Pos位置
  122. self::editPushPos($pullUser,$pushUser);
  123. //修改 Pid
  124. $editPid = DoubleCopyUser::findOne($pullUser['id']);
  125. $editPid->pid = $pushUser['user_id'];
  126. if(!$editPid->save()) throw new Exception("修改Pid失败");
  127. if($pullUser['pid']) self::editTopId($pullUser['pid']);
  128. if($pushUser['user_id']) self::editTopId($pushUser['user_id']);
  129. }
  130. /**
  131. * 获取PID上级所有用户
  132. *
  133. * @param array $user 用户
  134. * @return array
  135. */
  136. public static function recursionGetAllPidUser($userData,&$users = [])
  137. {
  138. $userData = DoubleCopyUser::find()
  139. ->select('id,user_id,pid,help_num,team_num,mall_id')
  140. ->where(['mall_id'=>self::$mallId,'user_id'=>$userData['pid'],'status' => StatusEnum::ENABLED])
  141. ->asArray()
  142. ->one();
  143. if($userData){
  144. $users[] = $userData;
  145. self::recursionGetAllPidUser($userData, $users);
  146. }
  147. return $users;
  148. }
  149. /**
  150. * 处理团队数量
  151. *
  152. * @param array $aggregate 数组循环
  153. * @param string $rule +或者-
  154. * @param integer $step 增加数量
  155. * @return void
  156. */
  157. public static function calculateTeamNum($aggregate,$rule='+',$step=0)
  158. {
  159. $num = $step + 1;//修改的数量
  160. foreach ($aggregate as $k=>$v){
  161. $spread = DoubleCopyUser::findOne($v['id']);
  162. if($rule == '+'){
  163. $spread->team_num = bcadd($v['team_num'],$num);
  164. }else if ($rule == '-') {
  165. $spread->team_num = bcsub($v['team_num'],$num);
  166. }
  167. if(!$spread->save()) throw new Exception("处理团队数量修改失败");
  168. }
  169. }
  170. /**
  171. * 处理助力用户数量
  172. *
  173. * @param [type] 要处理的上级ID
  174. * @param string $rule
  175. * @return void
  176. */
  177. public static function calculateHelpNum($pid,$rule='+')
  178. {
  179. $spread = DoubleCopyUser::find()->where(['user_id'=>$pid,'mall_id'=>self::$mallId,'status' => StatusEnum::ENABLED])->one();
  180. if(!$spread) return false;
  181. if($rule == '+'){
  182. $spread->help_num = bcadd($spread['help_num'],1);
  183. }else if ($rule == '-') {
  184. $spread->help_num = bcsub($spread['help_num'],1);
  185. }
  186. if(!$spread->save()) throw new Exception('修改处理助力用户数量失败');
  187. }
  188. /**
  189. * 修改拉取用户链的Pos
  190. *
  191. * @param [type] $pullUser 拉取用户
  192. * @return bool
  193. */
  194. public static function editPullPos($pullUser)
  195. {
  196. $users = DoubleCopyUser::find()
  197. ->select('id,user_id,pos')
  198. ->where(['status' => StatusEnum::ENABLED,'pid'=>$pullUser['pid'],'mall_id'=>self::$mallId])
  199. ->andWhere(['>','pos',$pullUser['pos']])
  200. ->asArray()
  201. ->all();
  202. if(empty($users)) return true;
  203. foreach ($users as $user) {
  204. $editUserPos = DoubleCopyUser::findOne($user['id']);
  205. $editUserPos->pos = bcsub($user['pos'],1);
  206. if(!$editUserPos->save()) throw new Exception('修改用户链的POS失败');
  207. }
  208. }
  209. /**
  210. * 修改推送用户链的Pos
  211. *
  212. * @param [type] $pullUser 拉取用户
  213. * @param [type] $pushUser 推送用户
  214. * @return bool
  215. */
  216. public static function editPushPos($pullUser,$pushUser)
  217. {
  218. $user = DoubleCopyUser::find()
  219. ->select('id,user_id,pos')
  220. ->where(['status' => StatusEnum::ENABLED,'pid'=>$pushUser['user_id'],'mall_id'=>self::$mallId])
  221. ->orderBy(['pos' => SORT_DESC])
  222. ->asArray()
  223. ->one();
  224. $num = empty($user['pos'])? 1 :$user['pos']+1;
  225. $editUserPos = DoubleCopyUser::findOne($pullUser['id']);
  226. $editUserPos->pos = $num;
  227. if(!$editUserPos->save()) throw new Exception('修改推送用户链的POS失败');
  228. }
  229. /**
  230. * 批量修改TOPID
  231. *
  232. * @param int 输入关系链的上一级的USERID
  233. * @return void
  234. */
  235. public static function editTopId($userId)
  236. {
  237. $boss_level = DoubleCopyLevel::find()->select('upgrade_type_condition, checked_condition_values')->where(['mall_id' => self::$mallId, 'level' => DoubleCopyEnum::LEVEL_BOSS, 'status' => StatusEnum::ENABLED])->asArray()->one();
  238. $upgrade_num = 0;// 需要直推的升级数量
  239. // json解析升级条件数量
  240. $json = Json::decode($boss_level['checked_condition_values'], true);
  241. $upgrade_num = $json[0]['value']['val0'] ?? 0;
  242. $copy_user = DoubleCopyUser::findOne(['user_id' => $userId, 'status' => StatusEnum::ENABLED]);
  243. if (!empty($copy_user)) self::batchGetUsers($copy_user,$upgrade_num);// 非空处理,避免原上级并非二二复制用户情况
  244. }
  245. /**
  246. * 添加推广变更列表
  247. *
  248. * @param int $pullUserId 拉取用户
  249. * @param int $pushUserId 推送用户
  250. * @return void
  251. */
  252. public static function addSpread($pullUserId,$pushUserId,$originalUserid)
  253. {
  254. $add = new DoubleCopySpread();
  255. $add->pull_user_id = $pullUserId;
  256. $add->push_user_id = $pushUserId;
  257. $add->mall_id = self::$mallId;
  258. $add->original_pid = $originalUserid;
  259. $add->admin_id = self::$admin->id;
  260. if(!$add->save()) throw new Exception('推广变更列表失败');
  261. }
  262. /**
  263. * 批量修改用户位置
  264. * @Author: lun
  265. * @DateTime: 2023/6/1 0001 18:44
  266. * @Copyright: copyright (c) 2021 广东七件事集团
  267. * @param DoubleCopyUser $changeUser
  268. * @param $upgrade_num
  269. * @param $change_pos_id
  270. */
  271. public static function batchGetUsers(DoubleCopyUser $changeUser, $upgrade_num)
  272. {
  273. $child_list = self::getAllUserIDs($changeUser->user_id);
  274. foreach ($child_list as $item) {
  275. if ($item == $changeUser->user_id) {
  276. $user = $changeUser;
  277. } else {
  278. $user = DoubleCopyUser::findOne(['user_id' => $item, 'status' => StatusEnum::ENABLED]);
  279. }
  280. if ($user) {
  281. self::updateTopId($user, $upgrade_num);
  282. }
  283. }
  284. }
  285. /**
  286. *
  287. * @Author: lun
  288. * @DateTime: 2023/6/1 0001 18:22
  289. * @Copyright: copyright (c) 2021 广东七件事集团
  290. * @param DoubleCopyUser $user
  291. * @param $upgrade_num
  292. * @param $change_pos_id
  293. */
  294. public static function updateTopId(DoubleCopyUser $user, $upgrade_num)
  295. {
  296. $parent_ids = self::recursionGetAllPidUser($user);
  297. $parent_ids = array_column($parent_ids,'user_id');// 倒序数组
  298. array_unshift($parent_ids, $user->user_id);
  299. foreach ($parent_ids as $key => $pid) {
  300. // 查询上级是否有身份
  301. $pdc_user = DoubleCopyUser::find()->select('user_id,pos,pid')->where(['user_id' => $pid, 'status' => StatusEnum::ENABLED])->asArray()->one();
  302. if (empty($pdc_user)) {
  303. // 获取当前用户的上级uid
  304. $ppuid = $parent_ids[$key + 1] ?? 0;
  305. if ($ppuid) {
  306. // 统计跟此用户同级人数,并且判断当前用户的平级数量是否大于或等于2号位
  307. $equal_num = DoubleCopyUser::find()->where(['pid' => $ppuid, 'status' => StatusEnum::ENABLED])->count();
  308. if ($equal_num >= $upgrade_num) {// 符合位置则表示当前用户的上级必定是拿平台补贴用户(拿平台补贴用户可以没有身份)
  309. $topid = $ppuid;
  310. break;
  311. }
  312. }
  313. } else {
  314. // 如果当前位置是大于或等于3号位则表示此用户上级必定是老板
  315. if ($pdc_user['pos'] > $upgrade_num) {
  316. $topid = $pdc_user['pid'];
  317. break;
  318. }
  319. }
  320. $topid = $pid;
  321. }
  322. // 临时检测的平台补贴用户id跟之前不同则需要修改平台补贴用户id
  323. if ($user->topid != $topid && $user->pid != 0) {
  324. $user->topid = $topid;
  325. $user->save();
  326. }
  327. }
  328. /**
  329. * 获取用户的所有下级 包括自己
  330. *
  331. * @param [type] $topUserId 顶级用户ID
  332. * @return array
  333. */
  334. public static function getAllUserIDs($topUserId)
  335. {
  336. $result = [$topUserId];
  337. $subUsers = DoubleCopyUser::find()->where(['pid' => $topUserId])->all();
  338. foreach ($subUsers as $user) {
  339. $result[] = $user->user_id;
  340. $result = array_merge($result, self::getAllUserIDs($user->user_id));
  341. }
  342. $result = array_unique($result);
  343. return $result;
  344. }
  345. /**
  346. * 判断是否是主商城关系链
  347. *
  348. * @param [type] $pullUserId 下级用户ID
  349. * @param [type] $pushUserId 上级用户ID
  350. * @return bool
  351. */
  352. public static function valPidIsMall($pullUserId,$pushUserId)
  353. {
  354. $pullTree = UserPartitionRelationship::getTree($pullUserId);
  355. $deep = $pullTree[1] - 1;
  356. $pullstrTree = $pullTree[0];
  357. $lastCommaPos = strrpos($pullstrTree, ',');
  358. if ($lastCommaPos !== false) {
  359. $str = substr($pullstrTree, 0, $lastCommaPos);
  360. } else {
  361. $str = $pullstrTree;
  362. }
  363. $treeUser = UserPartitionRelationship::find()->where(['deep'=>$deep,'tree'=>$str])->asArray()->one();
  364. if($pushUserId == $treeUser['user_id']){
  365. return true;
  366. }else{
  367. return false;
  368. }
  369. }
  370. }