UserNode.php 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742
  1. <?php
  2. /**
  3. * 厦门云联储网络科技有限公司
  4. * https://www.baokuaiyun.com
  5. * Copyright (c) 2023 爆块云 All rights reserved.
  6. */
  7. namespace app\models;
  8. use Yii;
  9. use yii\behaviors\TimestampBehavior;
  10. use yii\db\ActiveRecord;
  11. use yii\db\Expression;
  12. use yii\helpers\ArrayHelper;
  13. use yii\helpers\Json;
  14. use app\constants\OptionSetting;
  15. /**
  16. * This is the model class for table "{{%user_node}}".
  17. *
  18. * @property integer $id
  19. * @property integer $store_id
  20. * @property integer $user_id
  21. * @property integer $parent_id
  22. * @property integer $parent_node
  23. * @property string $recommend_relation
  24. * @property integer $layer
  25. * @property string $recommend_relation_node
  26. * @property integer $layer_node
  27. * @property integer $team_num
  28. * @property integer $area_key
  29. * @property integer $layer_rank
  30. * @property integer $created_at
  31. * @property integer $updated_at
  32. */
  33. class UserNode extends \yii\db\ActiveRecord
  34. {
  35. /**
  36. * @inheritdoc
  37. */
  38. public static function tableName()
  39. {
  40. return '{{%user_node}}';
  41. }
  42. public function behaviors()
  43. {
  44. return [
  45. [
  46. 'class' => TimestampBehavior::class,
  47. 'attributes' => [
  48. ActiveRecord::EVENT_BEFORE_INSERT => ['created_at'],
  49. ActiveRecord::EVENT_BEFORE_UPDATE => ['updated_at']
  50. ]
  51. ]
  52. ];
  53. }
  54. /**
  55. * @inheritdoc
  56. */
  57. public function rules()
  58. {
  59. return [
  60. [['recommend_relation', 'recommend_relation_node'], 'string'],
  61. [
  62. [
  63. 'store_id', 'user_id', 'parent_id', 'layer', 'layer_node', 'created_at', 'updated_at', 'parent_node',
  64. 'team_num', 'area_key', 'layer_rank'
  65. ],
  66. 'integer'
  67. ],
  68. ];
  69. }
  70. /**
  71. * @inheritdoc
  72. */
  73. public function attributeLabels()
  74. {
  75. return [
  76. 'id' => 'ID',
  77. 'store_id' => '店铺id',
  78. 'user_id' => '用户id',
  79. 'parent_id' => '分销上级id',
  80. 'parent_node' => '父节点',
  81. 'recommend_relation_node' => '节点推荐关系',
  82. 'layer_node' => '节点层级',
  83. 'recommend_relation' => '分销推荐关系',
  84. 'layer' => '分销层级',
  85. 'area_key' => '区域Key',
  86. 'layer_rank' => '层级排位',
  87. 'team_num' => '团队人数',
  88. 'created_at' => '创建时间',
  89. 'updated_at' => '更新时间',
  90. ];
  91. }
  92. /**
  93. * 加入节点
  94. * @param $store_id
  95. * @param $user_id
  96. * @return bool
  97. */
  98. public static function joinNode($store_id, $user_id)
  99. {
  100. // $share_setting = Option::get('share_basic_setting', $store_id);
  101. $share_setting = Option::get(OptionSetting::SHARE_STRING_CODE_DEFAULT_SETTING, $store_id, OptionSetting::SHARE_GROUP_NAME, '{}');
  102. $share_setting = $share_setting ? Json::decode($share_setting['value']) : [];
  103. if (!$share_setting) {
  104. //debug_log([__METHOD__, __LINE__, '加入串码节点:未开启分销设置'], strtolower(__CLASS__ . '.log'));
  105. return false;
  106. }
  107. // if (!is_array($share_setting['is_string_code']) || empty($share_setting['is_string_code']['value'])) {
  108. // //debug_log([__METHOD__, __LINE__, '加入串码节点:未开启串码节点功能'], strtolower(__CLASS__ . '.log'));
  109. // return false;
  110. // }
  111. // if (!is_array($share_setting['string_code_layer_max']) || empty($share_setting['string_code_layer_max']['value'])) {
  112. // //debug_log([__METHOD__, __LINE__, '加入串码节点:未设置串码最大层级'], strtolower(__CLASS__ . '.log'));
  113. // return false;
  114. // }
  115. // if (!is_array($share_setting['string_code_condition_coin']) || empty($share_setting['string_code_condition_coin']['value'])) {
  116. // //debug_log([__METHOD__, __LINE__, '加入串码节点:未设置贡献积分条件'], strtolower(__CLASS__ . '.log'));
  117. // return false;
  118. // }
  119. // if (!is_array($share_setting['string_code_root_user_id']) || !isset($share_setting['string_code_root_user_id']['value'])) {
  120. // //debug_log([__METHOD__, __LINE__, '加入串码节点:未设置默认根节点'], strtolower(__CLASS__ . '.log'));
  121. // return false;
  122. // }
  123. // if (!is_array($share_setting['string_code_add_sort']) || !isset($share_setting['string_code_add_sort']['value'])) {
  124. // //debug_log([__METHOD__, __LINE__, '加入串码节点:未设置串码顺序'], strtolower(__CLASS__ . '.log'));
  125. // return false;
  126. // }
  127. if (!is_array($share_setting['string_code_max_layer'])) {
  128. //debug_log([__METHOD__, __LINE__, '加入串码节点:未设置串码最大层级'], strtolower(__CLASS__ . '.log'));
  129. return false;
  130. }
  131. if (!is_array($share_setting['string_code_condition_value'])) {
  132. //debug_log([__METHOD__, __LINE__, '加入串码节点:未设置贡献积分条件'], strtolower(__CLASS__ . '.log'));
  133. return false;
  134. }
  135. if (!is_array($share_setting['string_code_root_user_id'])) {
  136. //debug_log([__METHOD__, __LINE__, '加入串码节点:未设置默认根节点'], strtolower(__CLASS__ . '.log'));
  137. return false;
  138. }
  139. // if (!is_array($share_setting['string_code_shop_value'])) {
  140. // //debug_log([__METHOD__, __LINE__, '加入串码节点:未设置串码顺序'], strtolower(__CLASS__ . '.log'));
  141. // return false;
  142. // }
  143. // 判断是否满足条件
  144. $user = User::findOne(['id' => $user_id]);
  145. if ($user['total_coin'] < $share_setting['string_code_condition_value']) {
  146. //debug_log([__METHOD__, __LINE__, '加入串码节点:用户贡献积分不足'], strtolower(__CLASS__ . '.log'));
  147. return false;
  148. }
  149. $user_string_code = self::findOne(['user_id' => $user_id]);
  150. if ($user_string_code) {
  151. //debug_log([__METHOD__, __LINE__, "加入串码节点:用户:{$user_id}已加入串码节点"], strtolower(__CLASS__ . '.log'));
  152. return false;
  153. }
  154. // 锁定 root 节点
  155. if (!$user['parent_id']) {
  156. $parent_id = (int)$share_setting['string_code_root_user_id'];
  157. } else {
  158. $parent_id = $user['parent_id'];
  159. }
  160. $parent_string_code = self::findOne(['user_id' => $parent_id]);
  161. // $share_setting['string_code_add_sort']['value'] = 1;
  162. // // $parent_id = 73;
  163. // if (empty($share_setting['string_code_add_sort']['value'])) {
  164. // 从上至下,从左至右
  165. list($real_parent_node, $layer_rank, $area_key) = self::getRealParentNode($store_id, $user_id, $parent_id, $share_setting['string_code_max_layer']);
  166. // } else {
  167. // // 深度优先,从左至右
  168. // list($real_parent_node, $layer_rank, $area_key) = self::getRealParentNodePlus($store_id, $user_id, $parent_id, $share_setting['string_code_max_layer']);
  169. // }
  170. if (empty($real_parent_node['recommend_relation_node'])) {
  171. $recommend_relation_node = ',' . $real_parent_node->user_id . ',';
  172. } else {
  173. $recommend_relation_node = $real_parent_node['recommend_relation_node'] . $real_parent_node->user_id . ',';
  174. }
  175. if (empty($parent_string_code['recommend_relation'])) {
  176. $recommend_relation = ',' . $parent_string_code->user_id . ',';
  177. } else {
  178. $recommend_relation = $real_parent_node['recommend_relation'] . $parent_string_code->user_id . ',';
  179. }
  180. // 保存节点数据
  181. $user_string_code = new self();
  182. $user_string_code->store_id = $store_id;
  183. $user_string_code->user_id = $user_id;
  184. $user_string_code->parent_id = $parent_id;
  185. $user_string_code->parent_node = $real_parent_node['user_id'];
  186. $user_string_code->recommend_relation_node = $recommend_relation_node;
  187. $user_string_code->layer_node = $real_parent_node['layer_node'] + 1;
  188. $user_string_code->recommend_relation = $recommend_relation;
  189. $user_string_code->layer = $parent_string_code['layer'] + 1;
  190. $user_string_code->area_key = $area_key;
  191. $user_string_code->layer_rank = $layer_rank;
  192. if (!$user_string_code->save()) {
  193. var_dump($user_string_code->getErrors());
  194. }
  195. // 所有上级节点 团队人数 + 1
  196. self::setTeamCountInc($user_id);
  197. return true;
  198. }
  199. /**
  200. * 指定用户上级所有节点团队人数 + 1
  201. * @param $user_id
  202. * @return int
  203. */
  204. public static function setTeamCountInc($user_id)
  205. {
  206. $parent_node_ids = self::getAllParentNodeIds($user_id);
  207. if ($parent_node_ids) {
  208. return self::updateAll(
  209. ['team_num' => new Expression('team_num + 1')],
  210. ['in', 'user_id', $parent_node_ids]
  211. );
  212. } else {
  213. return 0;
  214. }
  215. }
  216. /**
  217. * 获取用户最后一个节点
  218. * 从上至下,从左至右
  219. * @param $store_id 店铺ID
  220. * @param $user_id 下单用户ID
  221. * @param $parent_id 下单用户上级ID
  222. * @param $max_layer 限制最大层数
  223. * @return array
  224. */
  225. public static function getRealParentNode($store_id, $order_user_id, $parent_id, $max_layer)
  226. {
  227. // 针对父节点对应的区
  228. $real_area_key = 0;
  229. // 针对根节点对应的排序
  230. $real_layer_rank = 0;
  231. $parent_node = self::findOne(['store_id' => $store_id, 'user_id' => $parent_id]);
  232. $children_list = self::findOne(['store_id' => $store_id, 'parent_node' => $parent_id]);
  233. // 未有子节点
  234. if (!$children_list) {
  235. //debug_log([__METHOD__, __LINE__, "未有子节点"], strtolower(__CLASS__ . '.log'));
  236. $real_parent_node = $parent_node;
  237. return [$real_parent_node, $real_area_key, $real_layer_rank];
  238. }
  239. // 先判断 最大层级下 第一列能否能占位
  240. $temp_parent_id = $parent_id;
  241. //debug_log([__METHOD__, __LINE__, "最大层数:{$max_layer}"], strtolower(__CLASS__ . '.log'));
  242. for ($i = 0; $i < $max_layer; $i++) {
  243. //debug_log([__METHOD__, __LINE__, "第1区循环:{$i},用户ID:{$temp_parent_id}"], strtolower(__CLASS__ . '.log'));
  244. $temp_node = self::findOne(['store_id' => $store_id, 'parent_node' => $temp_parent_id, 'area_key' => $real_area_key]);
  245. if (!$temp_node) {
  246. $real_parent_node = self::findOne(['store_id' => $store_id, 'user_id' => $temp_parent_id]);
  247. return [$real_parent_node, $real_layer_rank, $real_area_key];
  248. } else {
  249. $temp_parent_id = $temp_node['user_id'];
  250. }
  251. }
  252. // 广度优先遍历
  253. $queue = [];
  254. $queue[] = $parent_node;
  255. while (!empty($queue)) {
  256. // 当前节点
  257. $current_node = array_shift($queue);
  258. // 当前层数
  259. $current_layer = $current_node['layer_node'] - $parent_node['layer_node'];
  260. //debug_log([__METHOD__, __LINE__, "当前节点ID:{$current_node['user_id']},当前层数:{$current_layer}"], strtolower(__CLASS__ . '.log'));
  261. // 判断用户第1区有无落点
  262. $parent_first_col_auth = self::findOne(['store_id' => $store_id, 'parent_node' => $current_node['user_id'], 'area_key' => 0]);
  263. if (!$parent_first_col_auth) {
  264. $real_area_key = 0;
  265. //debug_log([__METHOD__, __LINE__, "当前节点ID:{$current_node['user_id']},1区没人,落第1区"], strtolower(__CLASS__ . '.log'));
  266. $real_parent_node = self::findOne(['store_id' => $store_id, 'user_id' => $current_node['user_id']]);
  267. $current_layer_rank = self::find()
  268. ->where(['store_id' => $store_id, 'layer_node' => $real_parent_node['layer_node'] + 1])
  269. ->max('layer_rank');
  270. $real_layer_rank = $current_layer_rank + 1;
  271. return [$real_parent_node, $real_layer_rank, $real_area_key];
  272. }
  273. // 判断用户能否开第2区
  274. $parent_second_col_auth = self::checkSecondColumnAuthPlus($store_id, $order_user_id, $current_node['user_id'], $max_layer);
  275. if ($parent_second_col_auth) {
  276. // 判断第2区第一个有无占位
  277. $real_area_key = 1;
  278. $temp_node = self::findOne(['store_id' => $store_id, 'parent_node' => $current_node['user_id'], 'area_key' => $real_area_key]);
  279. if (!$temp_node) {
  280. //debug_log([__METHOD__, __LINE__, "当前节点ID:{$current_node['user_id']},可开第2区,落第2区"], strtolower(__CLASS__ . '.log'));
  281. $real_parent_node = self::findOne(['store_id' => $store_id, 'user_id' => $current_node['user_id']]);
  282. $current_layer_rank = self::find()
  283. ->where(['store_id' => $store_id, 'layer_node' => $real_parent_node['layer_node'] + 1])
  284. ->max('layer_rank');
  285. $real_layer_rank = $current_layer_rank + 1;
  286. return [$real_parent_node, $real_layer_rank, $real_area_key];
  287. }
  288. }
  289. // 判断用户能否开第3区
  290. $parent_multi_col_auth = self::checkMultiColumnAuth($store_id, $current_node['user_id']);
  291. if ($parent_multi_col_auth) {
  292. // 判断第3区第一个有无占位
  293. $real_area_key = 2;
  294. $temp_node = self::findOne(['store_id' => $store_id, 'parent_node' => $current_node['user_id'], 'area_key' => $real_area_key]);
  295. if (!$temp_node) {
  296. //debug_log([__METHOD__, __LINE__, "当前节点ID:{$current_node['user_id']},可开第3区,落第3区"], strtolower(__CLASS__ . '.log'));
  297. $real_parent_node = self::findOne(['store_id' => $store_id, 'user_id' => $current_node['user_id']]);
  298. $current_layer_rank = self::find()
  299. ->where(['store_id' => $store_id, 'layer_node' => $real_parent_node['layer_node'] + 1])
  300. ->max('layer_rank');
  301. $real_layer_rank = $current_layer_rank + 1;
  302. return [$real_parent_node, $real_layer_rank, $real_area_key];
  303. }
  304. }
  305. // 查询当前节点的子节点(假设最多有3个子节点情况,根据实际parent_id关联查询)
  306. $children_nodes = self::find()->where(['store_id' => $store_id, 'parent_node' => $current_node['user_id']])->orderBy("area_key ASC")->all();
  307. if ($children_nodes) {
  308. foreach ($children_nodes as $node) {
  309. $queue[] = $node;
  310. }
  311. }
  312. }
  313. }
  314. /**
  315. * 获取用户最后一个节点
  316. * 深度优先,从左至右
  317. * @param $store_id 店铺ID
  318. * @param $user_id 下单用户ID
  319. * @param $parent_id 下单用户上级ID
  320. * @param $max_layer 限制最大层数
  321. * @return array
  322. */
  323. public static function getRealParentNodePlus($store_id, $order_user_id, $parent_id, $max_layer)
  324. {
  325. // 针对父节点对应的区
  326. $real_area_key = 0;
  327. // 针对根节点对应的排序
  328. $real_layer_rank = 0;
  329. $parent_node = self::findOne(['store_id' => $store_id, 'user_id' => $parent_id]);
  330. $children_list = self::findOne(['store_id' => $store_id, 'parent_node' => $parent_id]);
  331. // 未有子节点
  332. if (!$children_list) {
  333. //debug_log([__METHOD__, __LINE__, "未有子节点"], strtolower(__CLASS__ . '.log'));
  334. $real_parent_node = $parent_node;
  335. return [$real_parent_node, $real_area_key, $real_layer_rank];
  336. }
  337. // 广度优先遍历
  338. $queue = [];
  339. $queue[] = $parent_node;
  340. while (!empty($queue)) {
  341. // 当前节点
  342. $current_node = array_shift($queue);
  343. // 当前层数
  344. $current_layer = $current_node['layer_node'] - $parent_node['layer_node'];
  345. //debug_log([__METHOD__, __LINE__, "当前节点ID:{$current_node['user_id']},当前层数:{$current_layer}"], strtolower(__CLASS__ . '.log'));
  346. // 深度优先
  347. $dfs_parent_node = self::findLastNodeDFS($current_node, $max_layer);
  348. if ($dfs_parent_node) {
  349. //debug_log([__METHOD__, __LINE__, "深度优先:查找到节点用户ID:{$dfs_parent_node['user_id']}"], strtolower(__CLASS__ . '.log'));
  350. $real_parent_node = self::findOne(['store_id' => $store_id, 'user_id' => $dfs_parent_node['user_id']]);
  351. $current_layer_rank = self::find()
  352. ->where(['store_id' => $store_id, 'layer_node' => $real_parent_node['layer_node'] + 1])
  353. ->max('layer_rank');
  354. $real_layer_rank = is_null($current_layer_rank) ? 0 : $current_layer_rank + 1;
  355. $current_area_key = self::find()
  356. ->where(['store_id' => $store_id, 'parent_node' => $real_parent_node['user_id']])
  357. ->max('area_key');
  358. $real_area_key = is_null($current_area_key) ? 0 : $current_area_key + 1;
  359. return [$real_parent_node, $real_layer_rank, $real_area_key];
  360. }
  361. // 取1~n区子节点
  362. // 判断用户第1区有无落点
  363. $parent_first_col_auth = self::findOne(['store_id' => $store_id, 'parent_node' => $current_node['user_id'], 'area_key' => 0]);
  364. if (!$parent_first_col_auth) {
  365. $real_area_key = 0;
  366. //debug_log([__METHOD__, __LINE__, "当前节点ID:{$current_node['user_id']},1区没人,落第1区"], strtolower(__CLASS__ . '.log'));
  367. $real_parent_node = self::findOne(['store_id' => $store_id, 'user_id' => $current_node['user_id']]);
  368. $current_layer_rank = self::find()
  369. ->where(['store_id' => $store_id, 'layer_node' => $real_parent_node['layer_node'] + 1])
  370. ->max('layer_rank');
  371. $real_layer_rank = $current_layer_rank + 1;
  372. return [$real_parent_node, $real_layer_rank, $real_area_key];
  373. }
  374. // 查询当前节点的子节点(假设最多有3个子节点情况,根据实际parent_id关联查询)
  375. $children_nodes = self::find()->where(['store_id' => $store_id, 'parent_node' => $current_node['user_id']])->orderBy("area_key ASC")->all();
  376. if ($children_nodes) {
  377. foreach ($children_nodes as $node) {
  378. $queue[] = $node;
  379. }
  380. }
  381. }
  382. }
  383. /**
  384. * 深度优先搜索
  385. * @param $node
  386. * @return mixed
  387. */
  388. public static function findLastNodeDFS($node, $depth, $current_depth = 0)
  389. {
  390. // 达到指定深度,退出
  391. if ($current_depth + 1 >= $depth) {
  392. return null;
  393. }
  394. $last_node = $node;
  395. $children_nodes = self::find()->where(['store_id' => $last_node['store_id'], 'parent_node' => $last_node['user_id']])->orderBy("area_key ASC")->all();
  396. // 递归处理所有子树
  397. foreach ($children_nodes as $children_node) {
  398. //debug_log([__METHOD__, __LINE__, "深度遍历:查找到子节点用户ID:{$children_node['user_id']},当前深度:{$current_depth},最大深度:{$depth}"], strtolower(__CLASS__ . '.log'));
  399. $temp = self::findLastNodeDFS($children_node, $depth, $current_depth + 1);
  400. if ($temp) {
  401. $last_node = $temp;
  402. }
  403. }
  404. return $last_node;
  405. }
  406. public static function getAllParentIds($user_id)
  407. {
  408. $relation = self::findOne(['user_id' => $user_id]);
  409. $recommon_relation = trim($relation['recommend_relation'], ',');
  410. if (!$recommon_relation) return [];
  411. return explode(',', $recommon_relation);
  412. }
  413. public static function getAllParentNodeIds($user_id)
  414. {
  415. $relation = self::findOne(['user_id' => $user_id]);
  416. $recommon_relation_node = trim($relation['recommend_relation_node'], ',');
  417. if (!$recommon_relation_node) return [];
  418. return explode(',', $recommon_relation_node);
  419. }
  420. public static function getChildNodeIdsByUserId($user_id, $node_key = '', $level = 0, $scope = 'all')
  421. {
  422. $user_node = self::find()->select(['layer_node'])->where(['user_id' => $user_id])->asArray()->one();
  423. $layer_node = (int)$user_node['layer_node'];
  424. $query = self::find()->select(['user_id'])->where(['like', 'recommend_relation_node', (',' . $user_id . ',')]);
  425. if ($node_key) $query->andWhere(['node_key' => $node_key]);
  426. //查询多N代全部子用户
  427. if ($level > 0 && $scope == 'all') $query->andWhere(['>=', 'layer_node', $level + $layer_node]);
  428. //查询指定代子用户
  429. if ($level > 0 && $scope == 'equal') $query->andWhere(['=', 'layer_node', $level + $layer_node]);
  430. return $query->asArray()->column();
  431. }
  432. /**
  433. * 查询用户指定部门的所有用户
  434. * @param $user_id
  435. * @param $node_key
  436. * @return array
  437. */
  438. public static function getChildNodeIdsByNodeKey($user_id, $department_key)
  439. {
  440. // if ($department_key) {
  441. // // 其他 部门
  442. // $first_node = self::find()->select(['user_id'])
  443. // ->where(['parent_id' => $user_id, 'node_key' => $department_key])
  444. // ->asArray()
  445. // ->one();
  446. // if (!$first_node) return [];
  447. // $res = self::find()->select(['user_id'])
  448. // ->where(['or', ['user_id' => $first_node['user_id']], ['like', 'recommend_relation_node', (',' . $first_node['user_id'] . ',')]])
  449. // ->asArray()->column();
  450. // } else {
  451. // // A 部门
  452. // $res = self::find()->select(['user_id'])
  453. // ->where(['like', 'recommend_relation_node', (',' . $user_id . ',')])
  454. // ->asArray()->column();
  455. // }
  456. $res = UserNodeDepartment::find()->select(['child_id'])
  457. ->where(['user_id' => $user_id, 'department_key' => $department_key])
  458. ->asArray()->column();
  459. return $res;
  460. }
  461. public static function getAllParentList($user_id)
  462. {
  463. $relation = self::findOne(['user_id' => $user_id]);
  464. $recommon_relation = trim($relation['recommend_relation'], ',');
  465. $relation_arr = explode(',', $recommon_relation);
  466. if (empty($relation_arr)) {
  467. return [];
  468. }
  469. $list = Share::find()->alias('s')->where(array('in', 's.user_id', $relation_arr))
  470. ->andWhere(['sl.is_delete' => 0])
  471. ->leftJoin(['sl' => ShareLevel::tableName()], 'sl.level=s.level')
  472. ->select('s.user_id, sl.order_layer, sl.point_reward')
  473. ->asArray()
  474. ->all();
  475. if (empty($list)) {
  476. return [];
  477. }
  478. $level_list = ArrayHelper::index($list, "user_id");
  479. $res = [];
  480. foreach ($relation_arr as $v) {
  481. $temp = [];
  482. $temp['user_id'] = $v;
  483. $temp['order_layer'] = $level_list[$v]['order_layer'] ?? 0;
  484. $temp['point_reward'] = $level_list[$v]['point_reward'] ?? 0;
  485. $temp['is_bonus'] = isset($level_list[$v]);
  486. $res[] = $temp;
  487. }
  488. return $res;
  489. }
  490. public static function getAllParentNodeList($user_id)
  491. {
  492. $relation = self::findOne(['user_id' => $user_id]);
  493. $recommon_relation_node = trim($relation['recommend_relation_node'], ',');
  494. $relation_arr = explode(',', $recommon_relation_node);
  495. if (empty($relation_arr)) {
  496. return [];
  497. }
  498. $list = Share::find()->alias('s')->where(array('in', 's.user_id', $relation_arr))
  499. ->andWhere(['sl.is_delete' => 0])
  500. ->leftJoin(['sl' => ShareLevel::tableName()], 'sl.level=s.level')
  501. ->select('s.user_id, sl.order_layer, sl.point_reward')
  502. ->asArray()
  503. ->all();
  504. if (empty($list)) {
  505. return [];
  506. }
  507. $level_list = ArrayHelper::index($list, "user_id");
  508. $res = [];
  509. foreach ($relation_arr as $v) {
  510. $temp = [];
  511. $temp['user_id'] = $v;
  512. $temp['order_layer'] = $level_list[$v]['order_layer'] ?? 0;
  513. $temp['point_reward'] = $level_list[$v]['point_reward'] ?? 0;
  514. $temp['is_bonus'] = isset($level_list[$v]);
  515. $res[] = $temp;
  516. }
  517. return $res;
  518. }
  519. public static function getRecommendRelationByUserId($user_id)
  520. {
  521. $res = "";
  522. $parentList = [];
  523. self::getParentList($user_id, $parentList);
  524. if ($parentList) {
  525. $res = "," . implode(',', array_reverse($parentList)) . ",";
  526. }
  527. return $res;
  528. }
  529. public static function getParentList($user_id, &$parentList)
  530. {
  531. $user = User::findOne(['id' => $user_id]);
  532. if ($user['parent_id']) {
  533. $parentList[] = $user['parent_id'];
  534. $parent = User::findOne(['id' => $user['parent_id']]);
  535. if ($parent) {
  536. return self::getParentList($parent['id'], $parentList);
  537. }
  538. }
  539. return $parentList;
  540. }
  541. public static function getLayerByUserId($user_id)
  542. {
  543. $res = 1;
  544. $parentList = [];
  545. self::getParentList($user_id, $parentList);
  546. if ($parentList) {
  547. $res += count($parentList);
  548. }
  549. return $res;
  550. }
  551. public static function createUserNode($store_id, $user_id)
  552. {
  553. $user_node = UserNode::findOne(['user_id' => $user_id]);
  554. if (!$user_node) {
  555. $user = User::findOne(['id' => $user_id]);
  556. $user_node = new UserNode();
  557. $user_node->store_id = $store_id;
  558. $user_node->user_id = $user_id;
  559. $user_node->parent_id = $user['parent_id'];
  560. $user_node->recommend_relation = self::getRecommendRelationByUserId($user_id);
  561. $user_node->layer = self::getLayerByUserId($user_id);
  562. $user_node->recommend_relation_node = "";
  563. $user_node->layer_node = 0;
  564. $user_node->created_at = time();
  565. if (!$user_node->save()) {
  566. //debug_log([__METHOD__, __LINE__, "用户:{$user_id},节点信息保存失败"], 'share_bind.log');
  567. }
  568. }
  569. return $user_node;
  570. }
  571. public static function getChildNodeCount($user_id)
  572. {
  573. $node_count = self::find()->select('COUNT(id) as node_count')->where(['like', 'recommend_relation_node', (',' . $user_id . ',')])->scalar();
  574. return (int)$node_count;
  575. }
  576. public static function getTeamNodeOrderPrice($user_id)
  577. {
  578. $child_ids = self::getChildNodeIdsByUserId($user_id);
  579. $team_ids = array_merge($child_ids, [$user_id]);
  580. return User::find()->select('SUM(`total_coin`) as node_order_price')->where(['in', 'id', $team_ids])->scalar();
  581. }
  582. /**
  583. * 获取用户部门列表
  584. * @param $user_id
  585. * @return array
  586. */
  587. public static function getUserDepartmentList($user_id)
  588. {
  589. $user = User::findOne(['id' => $user_id]);
  590. $user_share_holder_level = ShareHolder::findOne(['user_id' => $user_id]);
  591. if ($user['total_coin'] < 50) {
  592. // 未消费大礼包只有A部门
  593. $department_key_highest = 0;
  594. } else {
  595. // 有消费则有A,B等多部门
  596. if ($user_share_holder_level['level_id'] < 9) {
  597. // 股东等级小于V7只有A,B两条线
  598. $department_key_highest = 1;
  599. } else {
  600. // 大于等于V7可开多线
  601. $department_key_highest = self::getLastNodeKeyByUserId($user_id) + 1;
  602. }
  603. }
  604. $res = [];
  605. for ($department_key = 0; $department_key <= $department_key_highest; $department_key++) {
  606. $last_user_id = self::getLastUserByDepartmentKey($user_id, $department_key);
  607. $last_user = User::findOne(['id' => $last_user_id]);
  608. $department_name = $department_key + 1;
  609. $temp = [];
  610. $temp['id'] = $department_key;
  611. $temp['department_key'] = $department_key;
  612. $temp['user_id'] = $last_user_id;
  613. $temp['department_name'] = "{$department_name}-部门";
  614. $temp['nickname'] = $last_user['nickname'];
  615. $temp['mobile'] = $last_user['binding'];
  616. $res[] = $temp;
  617. }
  618. return $res;
  619. }
  620. /**
  621. * 获取指定用户最高部门 node_key
  622. * @param $user_id
  623. * @return int|mixed
  624. */
  625. public static function getLastNodeKeyByUserId($user_id)
  626. {
  627. $last_node_key = 0;
  628. $node_list = UserNode::find()
  629. ->where(['parent_id' => $user_id])
  630. ->orderBy('node_key DESC')
  631. ->asArray()
  632. ->one();
  633. if ($node_list) {
  634. $last_node_key = $node_list['node_key'];
  635. }
  636. return $last_node_key;
  637. }
  638. /**
  639. * 获取指定用户的部门最后一个用户
  640. * @param $user_id
  641. * @param $department_name
  642. * @return int
  643. */
  644. public static function getLastUserByDepartmentKey($user_id, $department_key)
  645. {
  646. // $first_node = self::find()->select(['user_id'])
  647. // ->where(['parent_id' => $user_id, 'node_key' => $department_key])
  648. // ->asArray()
  649. // ->one();
  650. // if (!$first_node) return (int)$user_id;
  651. //
  652. // $last_user_node = UserNode::find()
  653. // ->where(['or', ['user_id' => $first_node['user_id']], ['like', 'recommend_relation_node', (',' . $first_node['user_id'] . ',')]])
  654. // ->orderBy('layer_node DESC')
  655. // ->asArray()
  656. // ->one();
  657. //
  658. // if ($last_user_node) {
  659. // return (int)$last_user_node['user_id'];
  660. // } else {
  661. // return (int)$user_id;
  662. // }
  663. $last = UserNodeDepartment::find()
  664. ->where(['user_id' => $user_id, 'department_key' => $department_key])
  665. ->orderBy('id DESC')
  666. ->asArray()
  667. ->one();
  668. return $last['user_id'];
  669. }
  670. public static function getLastParentNodeLeader($user_id)
  671. {
  672. $user_node = self::findOne(['user_id' => $user_id]);
  673. if ($user_node->parent_id == $user_node->parent_node) {
  674. return self::findOne(['user_id' => $user_node->parent_id]);
  675. } else {
  676. return self::getLastParentNodeLeader($user_node->parent_node);
  677. }
  678. }
  679. }