UserRepository.php 56 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
  8. // +----------------------------------------------------------------------
  9. // | Author: CRMEB Team <admin@crmeb.com>
  10. // +----------------------------------------------------------------------
  11. namespace app\common\repositories\user;
  12. use app\common\dao\BaseDao;
  13. use app\common\dao\user\UserDao;
  14. use app\common\model\user\User;
  15. use app\common\model\wechat\WechatUser;
  16. use app\common\repositories\BaseRepository;
  17. use app\common\repositories\community\CommunityRepository;
  18. use app\common\repositories\store\order\StoreOrderRepository;
  19. use app\common\repositories\store\service\StoreServiceRepository;
  20. use app\common\repositories\system\attachment\AttachmentRepository;
  21. use app\common\repositories\wechat\WechatUserRepository;
  22. use crmeb\exceptions\AuthException;
  23. use crmeb\jobs\SendNewPeopleCouponJob;
  24. use crmeb\jobs\UserBrokerageLevelJob;
  25. use crmeb\services\JwtTokenService;
  26. use crmeb\services\QrcodeService;
  27. use crmeb\services\WechatService;
  28. use FormBuilder\Exception\FormBuilderException;
  29. use FormBuilder\Factory\Elm;
  30. use FormBuilder\Form;
  31. use think\db\exception\DataNotFoundException;
  32. use think\db\exception\DbException;
  33. use think\db\exception\ModelNotFoundException;
  34. use think\exception\ValidateException;
  35. use think\facade\Cache;
  36. use think\facade\Config;
  37. use think\facade\Db;
  38. use think\facade\Queue;
  39. use think\facade\Route;
  40. use think\Model;
  41. /**
  42. * Class UserRepository
  43. * @package app\common\repositories\user
  44. * @author xaboy
  45. * @day 2020-04-28
  46. * @mixin UserDao
  47. */
  48. class UserRepository extends BaseRepository
  49. {
  50. /**
  51. * UserRepository constructor.
  52. * @param UserDao $dao
  53. */
  54. public function __construct(UserDao $dao)
  55. {
  56. $this->dao = $dao;
  57. }
  58. public function promoter($uid)
  59. {
  60. return $this->dao->update($uid, ['is_promoter' => 1, 'promoter_time' => date('Y-m-d H:i:s')]);
  61. }
  62. public function createForm()
  63. {
  64. return Elm::createForm(Route::buildUrl('systemUserCreate')->build(), [
  65. Elm::input('account', '手机号(账号)')->required(),
  66. Elm::password('pwd', '密码')->required(),
  67. Elm::password('repwd', '确认密码')->required(),
  68. Elm::input('nickname', '用户昵称')->required(),
  69. Elm::frameImage('avatar', '头像', '/' . config('admin.admin_prefix') . '/setting/uploadPicture?field=avatar&type=1')
  70. ->modal(['modal' => false])
  71. ->width('896px')
  72. ->height('480px'),
  73. Elm::input('real_name', '真实姓名'),
  74. Elm::input('phone', '手机号'),
  75. Elm::input('card_id', '身份证'),
  76. Elm::radio('sex', '性别', 0)->options([
  77. ['value' => 0, 'label' => '保密'],
  78. ['value' => 1, 'label' => '男'],
  79. ['value' => 2, 'label' => '女'],
  80. ]),
  81. Elm::radio('status', '状态', 1)->options([
  82. ['value' => 0, 'label' => '禁用'],
  83. ['value' => 1, 'label' => '正常'],
  84. ])->requiredNum(),
  85. Elm::radio('is_promoter', '推广员', 1)->options([
  86. ['value' => 0, 'label' => '关闭'],
  87. ['value' => 1, 'label' => '开启'],
  88. ])->requiredNum()
  89. ])->setTitle('添加用户')->formData([]);
  90. }
  91. public function changePasswordForm(int $id)
  92. {
  93. $formData = $this->dao->get($id);
  94. if (!$formData) throw new ValidateException('用户不存在');
  95. return Elm::createForm(Route::buildUrl('systemUserChangePassword',['id' => $id])->build(), [
  96. Elm::input('account', '账号', $formData->account)->disabled(true),
  97. Elm::password('pwd', '新密码')->required(),
  98. Elm::password('repwd', '确认新密码')->required(),
  99. ])->setTitle('修改密码')->formData([]);
  100. }
  101. /**
  102. * @param $id
  103. * @return Form
  104. * @throws DataNotFoundException
  105. * @throws DbException
  106. * @throws FormBuilderException
  107. * @throws ModelNotFoundException
  108. * @author xaboy
  109. * @day 2020-05-09
  110. */
  111. public function userForm($id)
  112. {
  113. $user = $this->dao->get($id);
  114. $user['uid'] = (string)$user['uid'];
  115. return Elm::createForm(Route::buildUrl('systemUserUpdate', compact('id'))->build(), [
  116. Elm::input('uid', '用户 ID', '')->disabled(true)->required(true),
  117. Elm::input('real_name', '真实姓名'),
  118. Elm::input('phone', '手机号'),
  119. Elm::date('birthday', '生日'),
  120. Elm::input('card_id', '身份证'),
  121. Elm::input('addres', '用户地址'),
  122. Elm::textarea('mark', '备注'),
  123. Elm::select('group_id', '用户分组')->options(function () {
  124. $data = app()->make(UserGroupRepository::class)->allOptions();
  125. $options = [['value' => 0, 'label' => '请选择']];
  126. foreach ($data as $value => $label) {
  127. $options[] = compact('value', 'label');
  128. }
  129. return $options;
  130. }),
  131. Elm::selectMultiple('label_id', '用户标签')->options(function () {
  132. $data = app()->make(UserLabelRepository::class)->allOptions();
  133. $options = [];
  134. foreach ($data as $value => $label) {
  135. $value = (string)$value;
  136. $options[] = compact('value', 'label');
  137. }
  138. return $options;
  139. }),
  140. Elm::radio('status', '状态', 1)->options([
  141. ['value' => 0, 'label' => '关闭'],
  142. ['value' => 1, 'label' => '开启'],
  143. ])->requiredNum(),
  144. Elm::radio('is_promoter', '推广员', 1)->options([
  145. ['value' => 0, 'label' => '关闭'],
  146. ['value' => 1, 'label' => '开启'],
  147. ])->requiredNum()
  148. ])->setTitle('编辑')->formData($user->toArray());
  149. }
  150. /**
  151. * @param array $where
  152. * @param $page
  153. * @param $limit
  154. * @return array
  155. * @throws DataNotFoundException
  156. * @throws DbException
  157. * @throws ModelNotFoundException
  158. * @author xaboy
  159. * @day 2020-05-07
  160. */
  161. public function getList(array $where, $page, $limit)
  162. {
  163. $query = $this->dao->search($where)->with([
  164. 'spread' => function ($query) {
  165. $query->field('uid,nickname,spread_uid');
  166. },
  167. 'member' => function ($query) {
  168. $query->field('user_brokerage_id,brokerage_level,brokerage_name,brokerage_icon');
  169. },
  170. 'group']);
  171. $make = app()->make(UserLabelRepository::class);
  172. $count = $query->count($this->dao->getPk());
  173. $list = $query->page($page, $limit)->select()->each(function ($item) use ($make) {
  174. return $item->label = count($item['label_id']) ? $make->labels($item['label_id']) : [];
  175. });
  176. return compact('count', 'list');
  177. }
  178. public function getPulbicLst(array $where, $page, $limit)
  179. {
  180. $query = $this->dao->search($where);
  181. $count = $query->count();
  182. $list = $query->page($page, $limit)->setOption('field',[])->field('uid,nickname,avatar')->select();
  183. return compact('count', 'list');
  184. }
  185. public function promoterCount()
  186. {
  187. $total = $this->dao->search(['is_promoter' => 1])
  188. ->field('sum(spread_count) as spread_count,sum(spread_pay_count) as spread_pay_count,sum(spread_pay_price) as spread_pay_price,count(uid) as total_user,sum(brokerage_price) as brokerage_price')->find();
  189. $total = $total ? $total->toArray() : ['spread_count' => 0, 'spread_pay_count' => 0, 'spread_pay_price' => 0, 'total_user' => 0, 'brokerage_price' => 0];
  190. $total['total_extract'] = app()->make(UserExtractRepository::class)->getTotalExtractPrice();
  191. return [
  192. [
  193. 'className' => 'el-icon-s-goods',
  194. 'count' => $total['total_user'] ?? 0,
  195. 'name' => '分销员人数(人)'
  196. ],
  197. [
  198. 'className' => 'el-icon-s-order',
  199. 'count' => $total['spread_count'] ?? 0,
  200. 'name' => '推广人数(人)'
  201. ],
  202. [
  203. 'className' => 'el-icon-s-cooperation',
  204. 'count' => (int)($total['spread_pay_count'] ?? 0),
  205. 'name' => '推广订单数'
  206. ],
  207. [
  208. 'className' => 'el-icon-s-cooperation',
  209. 'count' => (float)($total['spread_pay_price'] ?? 0),
  210. 'name' => '推广订单金额'
  211. ],
  212. [
  213. 'className' => 'el-icon-s-cooperation',
  214. 'count' => (float)($total['total_extract'] ?? 0),
  215. 'name' => '已提现金额(元)'
  216. ],
  217. [
  218. 'className' => 'el-icon-s-cooperation',
  219. 'count' => (float)($total['brokerage_price'] ?? 0),
  220. 'name' => '未提现金额(元)'
  221. ],
  222. ];
  223. }
  224. public function promoterList(array $where, $page, $limit)
  225. {
  226. $where['is_promoter'] = 1;
  227. $query = $this->dao->search($where)->with(['spread' => function ($query) {
  228. $query->field('uid,nickname,spread_uid');
  229. }, 'brokerage' => function ($query) {
  230. $query->field('brokerage_level,brokerage_name,brokerage_icon');
  231. }]);
  232. $count = $query->count($this->dao->getPk());
  233. $list = $query->page($page, $limit)->select()->toArray();
  234. if (count($list)) {
  235. $promoterInfo = app()->make(UserExtractRepository::class)->getPromoterInfo(array_column($list, 'uid'));
  236. if (count($promoterInfo)) {
  237. $promoterInfo = array_combine(array_column($promoterInfo, 'uid'), $promoterInfo);
  238. }
  239. $user_relation = app()->make(UserRelationRepository::class);
  240. foreach ($list as $k => $item) {
  241. $list[$k]['total_extract_price'] = $promoterInfo[$item['uid']]['total_price'] ?? 0;
  242. $list[$k]['total_extract_num'] = $promoterInfo[$item['uid']]['total_num'] ?? 0;
  243. $list[$k]['total_brokerage_price'] = (float)bcadd($item['brokerage_price'], $list[$k]['total_extract_num'], 2);
  244. //获取推广员关注店铺数量
  245. $relation_num = 0;
  246. $user_info = $this->selectWhere(['spread_uid' =>$item['uid']],'uid');
  247. if($user_info){
  248. foreach ($user_info as $v){
  249. $is_relation = $user_relation->getWhere(array('uid'=>$v->uid,'type'=>10));
  250. if($is_relation){
  251. $relation_num++;
  252. }
  253. }
  254. }
  255. $list[$k]['relation_num'] = $relation_num;
  256. }
  257. }
  258. return compact('list', 'count');
  259. }
  260. public function merList(string $keyword, $page, $limit)
  261. {
  262. $query = $this->dao->searchMerUser($keyword);
  263. $count = $query->count($this->dao->getPk());
  264. $list = $query->page($page, $limit)->setOption('field', [])->field('uid,nickname,avatar,user_type,sex')->select();
  265. return compact('count', 'list');
  266. }
  267. /**
  268. * @param $id
  269. * @return Form
  270. * @throws DataNotFoundException
  271. * @throws DbException
  272. * @throws ModelNotFoundException
  273. * @throws FormBuilderException
  274. * @author xaboy
  275. * @day 2020-05-07
  276. */
  277. public function changeGroupForm($id)
  278. {
  279. $isArray = is_array($id);
  280. if (!$isArray)
  281. $user = $this->dao->get($id);
  282. /** @var UserGroupRepository $make */
  283. $data = app()->make(UserGroupRepository::class)->allOptions();
  284. return Elm::createForm(Route::buildUrl($isArray ? 'systemUserBatchChangeGroup' : 'systemUserChangeGroup', $isArray ? [] : compact('id'))->build(), [
  285. Elm::hidden('ids', $isArray ? $id : [$id]),
  286. Elm::select('group_id', '用户分组', $isArray ? '' : $user->group_id)->options(function () use ($data) {
  287. $options = [['label' => '不设置', 'value' => '0']];
  288. foreach ($data as $value => $label) {
  289. $options[] = compact('value', 'label');
  290. }
  291. return $options;
  292. })
  293. ])->setTitle('修改用户分组');
  294. }
  295. /**
  296. * @param $id
  297. * @return Form
  298. * @throws DataNotFoundException
  299. * @throws DbException
  300. * @throws ModelNotFoundException
  301. * @throws FormBuilderException
  302. * @author xaboy
  303. * @day 2020-05-07
  304. */
  305. public function changeLabelForm($id)
  306. {
  307. $isArray = is_array($id);
  308. if (!$isArray)
  309. $user = $this->dao->get($id);
  310. /** @var UserLabelRepository $make */
  311. $data = app()->make(UserLabelRepository::class)->allOptions();
  312. return Elm::createForm(Route::buildUrl($isArray ? 'systemUserBatchChangeLabel' : 'systemUserChangeLabel', $isArray ? [] : compact('id'))->build(), [
  313. Elm::hidden('ids', $isArray ? $id : [$id]),
  314. Elm::selectMultiple('label_id', '用户标签', $isArray ? [] : $user->label_id)->options(function () use ($data) {
  315. $options = [];
  316. foreach ($data as $value => $label) {
  317. $value = (string)$value;
  318. $options[] = compact('value', 'label');
  319. }
  320. return $options;
  321. })
  322. ])->setTitle('修改用户标签');
  323. }
  324. /**
  325. * @param $id
  326. * @return Form
  327. * @throws FormBuilderException
  328. * @author xaboy
  329. * @day 2020-05-07
  330. */
  331. public function changeNowMoneyForm($id)
  332. {
  333. return Elm::createForm(Route::buildUrl('systemUserChangeNowMoney', compact('id'))->build(), [
  334. Elm::radio('type', '修改余额', 1)->options([
  335. ['label' => '增加', 'value' => 1],
  336. ['label' => '减少', 'value' => 0],
  337. ])->requiredNum(),
  338. Elm::number('now_money', '金额')->required()->min(0)->max(999999)
  339. ])->setTitle('修改用户余额');
  340. }
  341. public function changeIntegralForm($id)
  342. {
  343. return Elm::createForm(Route::buildUrl('systemUserChangeIntegral', compact('id'))->build(), [
  344. Elm::radio('type', '修改红包米', 1)->options([
  345. ['label' => '增加', 'value' => 1],
  346. ['label' => '减少', 'value' => 0],
  347. ])->requiredNum(),
  348. Elm::number('now_money', '红包米')->required()->min(0)->max(999999)
  349. ])->setTitle('修改用户红包米');
  350. }
  351. /**
  352. * @param $id
  353. * @param $adminId
  354. * @param $type
  355. * @param $nowMoney
  356. * @throws DataNotFoundException
  357. * @throws DbException
  358. * @throws ModelNotFoundException
  359. * @author xaboy
  360. * @day 2020-05-07
  361. */
  362. public function changeNowMoney($id, $adminId, $type, $nowMoney)
  363. {
  364. $user = $this->dao->get($id);
  365. Db::transaction(function () use ($id, $adminId, $user, $type, $nowMoney) {
  366. $balance = $type == 1 ? bcadd($user->now_money, $nowMoney, 2) : bcsub($user->now_money, $nowMoney, 2);
  367. $user->save(['now_money' => $balance]);
  368. /** @var UserBillRepository $make */
  369. $make = app()->make(UserBillRepository::class);
  370. if ($type == 1) {
  371. $make->incBill($id, 'now_money', 'sys_inc_money', [
  372. 'link_id' => $adminId,
  373. 'status' => 1,
  374. 'title' => '系统增加余额',
  375. 'number' => $nowMoney,
  376. 'mark' => '系统增加了' . floatval($nowMoney) . '余额',
  377. 'balance' => $balance
  378. ]);
  379. } else {
  380. $make->decBill($id, 'now_money', 'sys_dec_money', [
  381. 'link_id' => $adminId,
  382. 'status' => 1,
  383. 'title' => '系统减少余额',
  384. 'number' => $nowMoney,
  385. 'mark' => '系统减少了' . floatval($nowMoney) . '余额',
  386. 'balance' => $balance
  387. ]);
  388. }
  389. });
  390. }
  391. /**
  392. * @param $id
  393. * @param $adminId
  394. * @param $type
  395. * @param $integral
  396. * @throws DataNotFoundException
  397. * @throws DbException
  398. * @throws ModelNotFoundException
  399. * @author xaboy
  400. * @day 2020-05-07
  401. */
  402. public function changeIntegral($id, $adminId, $type, $integral)
  403. {
  404. $user = $this->dao->get($id);
  405. Db::transaction(function () use ($id, $adminId, $user, $type, $integral) {
  406. $integral = (int)$integral;
  407. $balance = $type == 1 ? bcadd($user->integral, $integral, 0) : bcsub($user->integral, $integral, 0);
  408. $user->save(['integral' => $balance]);
  409. /** @var UserBillRepository $make */
  410. $make = app()->make(UserBillRepository::class);
  411. if ($type == 1) {
  412. $make->incBill($id, 'integral', 'sys_inc', [
  413. 'link_id' => $adminId,
  414. 'status' => 1,
  415. 'title' => '系统增加红包米',
  416. 'number' => $integral,
  417. 'mark' => '系统增加了' . $integral . '红包米',
  418. 'balance' => $balance
  419. ]);
  420. } else {
  421. $make->decBill($id, 'integral', 'sys_dec', [
  422. 'link_id' => $adminId,
  423. 'status' => 1,
  424. 'title' => '系统减少红包米',
  425. 'number' => $integral,
  426. 'mark' => '系统减少了' . $integral . '红包米',
  427. 'balance' => $balance
  428. ]);
  429. }
  430. });
  431. }
  432. /**
  433. * @param $password
  434. * @return false|string|null
  435. * @author xaboy
  436. * @day 2020/6/22
  437. */
  438. public function encodePassword($password)
  439. {
  440. return password_hash($password, PASSWORD_BCRYPT);
  441. }
  442. public function userType($type)
  443. {
  444. if ($type === 'apple') {
  445. return 'app';
  446. }
  447. if (!$type)
  448. return 'h5';
  449. return $type;
  450. }
  451. public function syncBaseAuth(array $auth, User $user)
  452. {
  453. $wechatUser = app()->make(WechatUserRepository::class)->get($auth['id']);
  454. if ($wechatUser) {
  455. $data = ['wechat_user_id' => $auth['id'], 'user_type' => $auth['type']];
  456. if ($wechatUser['nickname']) {
  457. $data['nickname'] = $wechatUser['nickname'];
  458. }
  459. if ($wechatUser['headimgurl']) {
  460. $data['avatar'] = $wechatUser['headimgurl'];
  461. }
  462. $data['sex'] = $wechatUser['sex'] ?? 0;
  463. $user->save($data);
  464. }
  465. }
  466. /**
  467. * @param WechatUser $wechatUser
  468. * @return BaseDao|array|Model|null
  469. * @throws DataNotFoundException
  470. * @throws DbException
  471. * @throws ModelNotFoundException
  472. * @author xaboy
  473. * @day 2020-04-28
  474. */
  475. public function syncWechatUser(WechatUser $wechatUser, $userType = 'wechat')
  476. {
  477. $user = $this->dao->wechatUserIdBytUser($wechatUser->wechat_user_id);
  478. $request = request();
  479. if ($user) {
  480. // if ($wechatUser['nickname'] == '微信用户') {
  481. // unset($wechatUser['nickname'],$wechatUser['headimgurl']);
  482. // }
  483. $user->save(array_filter([
  484. 'nickname' => $wechatUser['nickname'] ?? '',
  485. 'avatar' => $wechatUser['headimgurl'] ?? '',
  486. 'sex' => $wechatUser['sex'] ?? 0,
  487. 'last_time' => date('Y-m-d H:i:s'),
  488. 'last_ip' => $request->ip(),
  489. ]));
  490. } else {
  491. $user = $this->create($userType, [
  492. 'account' => 'wx' . $wechatUser->wechat_user_id . time(),
  493. 'wechat_user_id' => $wechatUser->wechat_user_id,
  494. 'pwd' => $this->encodePassword($this->dao->defaultPwd()),
  495. 'nickname' => $wechatUser['nickname'] ?? '',
  496. 'avatar' => $wechatUser['headimgurl'] ?? '',
  497. 'sex' => $wechatUser['sex'] ?? 0,
  498. 'spread_uid' => 0,
  499. 'is_promoter' => 0,
  500. 'last_time' => date('Y-m-d H:i:s'),
  501. 'last_ip' => $request->ip()
  502. ]);
  503. }
  504. return $user;
  505. }
  506. /**
  507. * @param string $type
  508. * @param array $userInfo
  509. * @return BaseDao|Model
  510. * @author xaboy
  511. * @day 2020-04-28
  512. */
  513. public function create(string $type, array $userInfo)
  514. {
  515. $userInfo['user_type'] = $this->userType($type);
  516. if (!isset($userInfo['status'])) {
  517. $userInfo['status'] = 1;
  518. }
  519. $user = $this->dao->create($userInfo);
  520. try {
  521. Queue::push(SendNewPeopleCouponJob::class, $user->uid);
  522. } catch (\Exception $e) {
  523. }
  524. $user->isNew = true;
  525. return $user;
  526. }
  527. /**
  528. * @param User $user
  529. * @return array
  530. * @author xaboy
  531. * @day 2020-04-29
  532. */
  533. public function createToken(User $user)
  534. {
  535. $service = new JwtTokenService();
  536. $exp = intval(Config::get('admin.user_token_valid_exp', 15));
  537. $token = $service->createToken($user->uid, 'user', strtotime("+ {$exp}day"));
  538. $this->cacheToken($token['token'], $token['out']);
  539. return $token;
  540. }
  541. /**
  542. * //TODO 登录成功后
  543. * @param User $user
  544. * @author xaboy
  545. * @day 2020/6/22
  546. */
  547. public function loginAfter(User $user)
  548. {
  549. $user->last_time = date('Y-m-d H:i:s', time());
  550. $user->last_ip = request()->ip();
  551. $user->save();
  552. }
  553. /**
  554. * @param string $token
  555. * @param int $exp
  556. * @author xaboy
  557. * @day 2020-04-29
  558. */
  559. public function cacheToken(string $token, int $exp)
  560. {
  561. Cache::store('file')->set('user_' . $token, time() + $exp, $exp);
  562. }
  563. /**
  564. * @param string $token
  565. * @author xaboy
  566. * @day 2020-04-29
  567. */
  568. public function checkToken(string $token)
  569. {
  570. $cache = Cache::store('file');
  571. $has = $cache->has('user_' . $token);
  572. if (!$has)
  573. throw new AuthException('无效的token');
  574. $lastTime = $cache->get('user_' . $token);
  575. if (($lastTime + (intval($cache->get('admin.user_token_valid_exp', 15))) * 24 * 60 * 60) < time())
  576. throw new AuthException('token 已过期');
  577. }
  578. /**
  579. * @param string $token
  580. * @author xaboy
  581. * @day 2020-04-29
  582. */
  583. public function updateToken(string $token)
  584. {
  585. Cache::store('file')->set('user_' . $token, time(), intval(Config::get('admin.user_token_valid_exp', 15)) * 24 * 60 * 60);
  586. }
  587. /**
  588. * @param string $token
  589. * @author xaboy
  590. * @day 2020-04-29
  591. */
  592. public function clearToken(string $token)
  593. {
  594. Cache::delete('user_' . $token);
  595. }
  596. /**
  597. * @param string $key
  598. * @param string $code
  599. * @author xaboy
  600. * @day 2020/6/1
  601. */
  602. public function checkCode(string $key, string $code)
  603. {
  604. $_code = Cache::get('am_captcha' . $key);
  605. if (!$_code) {
  606. throw new ValidateException('验证码过期');
  607. }
  608. if (strtolower($_code) != strtolower($code)) {
  609. throw new ValidateException('验证码错误');
  610. }
  611. //删除code
  612. Cache::delete('am_captcha' . $key);
  613. }
  614. /**
  615. * @param string $code
  616. * @return string
  617. * @author xaboy
  618. * @day 2020/6/1
  619. */
  620. public function createLoginKey(string $code)
  621. {
  622. $key = uniqid(microtime(true), true);
  623. Cache::set('am_captcha' . $key, $code, Config::get('admin.captcha_exp', 5) * 60);
  624. return $key;
  625. }
  626. public function registr(string $phone, ?string $pwd, $user_type = 'h5', int $pid, int $order_id)
  627. {
  628. $pwd = $pwd ? $this->encodePassword($pwd) : $this->encodePassword($this->dao->defaultPwd());
  629. $data = [
  630. 'account' => $phone,
  631. 'pwd' => $pwd,
  632. 'nickname' => substr($phone, 0, 3) . '****' . substr($phone, 7, 4),
  633. 'avatar' => '',
  634. 'phone' => $phone,
  635. 'pid' => $pid,
  636. 'order_id' => $order_id,
  637. 'is_promoter' => 1,
  638. 'last_ip' => app('request')->ip()
  639. ];
  640. return $this->create($user_type, $data);
  641. }
  642. public function routineSpreadImage(User $user)
  643. {
  644. //小程序
  645. $name = md5('surt' . $user['uid'] . $user['is_promoter'] . date('Ymd')) . '.jpg';
  646. $attachmentRepository = app()->make(AttachmentRepository::class);
  647. $imageInfo = $attachmentRepository->getWhere(['attachment_name' => $name]);
  648. $spreadBanner = systemGroupData('spread_banner');
  649. if (!count($spreadBanner)) return [];
  650. $siteName = systemConfig('site_name');
  651. $siteUrl = systemConfig('site_url');
  652. $uploadType = (int)systemConfig('upload_type') ?: 1;
  653. $urlCode = app()->make(QrcodeService::class)->getRoutineQrcodePath($name, 'pages/index/index', 'spid=' . $user['uid']);
  654. if (!$urlCode)
  655. throw new ValidateException('二维码生成失败');
  656. $filelink = [
  657. 'Bold' => 'public/font/Alibaba-PuHuiTi-Regular.otf',
  658. 'Normal' => 'public/font/Alibaba-PuHuiTi-Regular.otf',
  659. ];
  660. if (!file_exists($filelink['Bold'])) throw new ValidateException('缺少字体文件Bold');
  661. if (!file_exists($filelink['Normal'])) throw new ValidateException('缺少字体文件Normal');
  662. $resRoutine = true;
  663. foreach ($spreadBanner as $key => &$item) {
  664. $posterInfo = '海报生成失败:(';
  665. $config = array(
  666. 'image' => array(
  667. array(
  668. 'url' => $urlCode, //二维码资源
  669. 'stream' => 0,
  670. 'left' => 114,
  671. 'top' => 790,
  672. 'right' => 0,
  673. 'bottom' => 0,
  674. 'width' => 120,
  675. 'height' => 120,
  676. 'opacity' => 100
  677. )
  678. ),
  679. 'text' => array(
  680. array(
  681. 'text' => $user['nickname'],
  682. 'left' => 250,
  683. 'top' => 840,
  684. 'fontPath' => $filelink['Bold'], //字体文件
  685. 'fontSize' => 16, //字号
  686. 'fontColor' => '40,40,40', //字体颜色
  687. 'angle' => 0,
  688. ),
  689. array(
  690. 'text' => '邀请您加入' . $siteName,
  691. 'left' => 250,
  692. 'top' => 880,
  693. 'fontPath' => $filelink['Normal'], //字体文件
  694. 'fontSize' => 16, //字号
  695. 'fontColor' => '40,40,40', //字体颜色
  696. 'angle' => 0,
  697. )
  698. ),
  699. 'background' => $item['pic']
  700. );
  701. $resRoutine = $resRoutine && $posterInfo = setSharePoster($config, 'routine/spread/poster');
  702. if (!is_array($posterInfo)) throw new ValidateException($posterInfo);
  703. $posterInfo['dir'] = tidy_url($posterInfo['dir'], 0, $siteUrl);
  704. if ($resRoutine) {
  705. $attachmentRepository->create($uploadType, -1, $user->uid, [
  706. 'attachment_category_id' => 0,
  707. 'attachment_name' => $posterInfo['name'],
  708. 'attachment_src' => $posterInfo['dir']
  709. ]);
  710. $item['poster'] = $posterInfo['dir'];
  711. }
  712. }
  713. return $spreadBanner;
  714. }
  715. public function wxQrcode(User $user)
  716. {
  717. $name = md5('uwx_i' . $user['uid'] . date('Ymd')) . '.jpg';
  718. $key = 'home_' . $user['uid'];
  719. return app()->make(QrcodeService::class)->getWechatQrcodePath($name, rtrim(systemConfig('site_url'), '/') . '?spread=' . $user['uid'] . '&spid=' . $user['uid'], false, $key);
  720. }
  721. public function mpQrcode(User $user)
  722. {
  723. $name = md5('surt_i' . $user['uid'] . $user['is_promoter'] . date('Ymd')) . '.jpg';
  724. return app()->make(QrcodeService::class)->getRoutineQrcodePath($name, 'pages/index/index', 'spid=' . $user['uid']);
  725. }
  726. public function wxSpreadImage(User $user)
  727. {
  728. $name = md5('uwx' . $user['uid'] . $user['is_promoter'] . date('Ymd')) . '.jpg';
  729. $spreadBanner = systemGroupData('spread_banner');
  730. if (!count($spreadBanner)) return [];
  731. $siteName = systemConfig('site_name');
  732. $attachmentRepository = app()->make(AttachmentRepository::class);
  733. $imageInfo = $attachmentRepository->getWhere(['attachment_name' => $name]);
  734. $siteUrl = rtrim(systemConfig('site_url'), '/');
  735. $uploadType = (int)systemConfig('upload_type') ?: 1;
  736. $resWap = true;
  737. //检测远程文件是否存在
  738. if (isset($imageInfo['attachment_src']) && strstr($imageInfo['attachment_src'], 'http') !== false && curl_file_exist($imageInfo['attachment_src']) === false) {
  739. $imageInfo->delete();
  740. $imageInfo = null;
  741. }
  742. if (!$imageInfo) {
  743. $codeUrl = $siteUrl . '?spread=' . $user['uid'] . '&spid=' . $user['uid'];//二维码链接
  744. if (systemConfig('open_wechat_share')) {
  745. $qrcode = WechatService::create(false)->qrcodeService();
  746. $codeUrl = $qrcode->forever('_scan_url_home_' . $user['uid'])->url;
  747. }
  748. $imageInfo = app()->make(QrcodeService::class)->getQRCodePath($codeUrl, $name);
  749. if (is_string($imageInfo)) throw new ValidateException('二维码生成失败');
  750. $imageInfo['dir'] = tidy_url($imageInfo['dir'], null, $siteUrl);
  751. $attachmentRepository->create(systemConfig('upload_type') ?: 1, -1, $user->uid, [
  752. 'attachment_category_id' => 0,
  753. 'attachment_name' => $imageInfo['name'],
  754. 'attachment_src' => $imageInfo['dir']
  755. ]);
  756. $urlCode = $imageInfo['dir'];
  757. } else $urlCode = $imageInfo['attachment_src'];
  758. $filelink = [
  759. 'Bold' => 'public/font/Alibaba-PuHuiTi-Regular.otf',
  760. 'Normal' => 'public/font/Alibaba-PuHuiTi-Regular.otf',
  761. ];
  762. if (!file_exists($filelink['Bold'])) throw new ValidateException('缺少字体文件Bold');
  763. if (!file_exists($filelink['Normal'])) throw new ValidateException('缺少字体文件Normal');
  764. foreach ($spreadBanner as $key => &$item) {
  765. $posterInfo = '海报生成失败:(';
  766. $config = array(
  767. 'image' => array(
  768. array(
  769. 'url' => $urlCode, //二维码资源
  770. 'stream' => 0,
  771. 'left' => 114,
  772. 'top' => 790,
  773. 'right' => 0,
  774. 'bottom' => 0,
  775. 'width' => 120,
  776. 'height' => 120,
  777. 'opacity' => 100
  778. )
  779. ),
  780. 'text' => array(
  781. array(
  782. 'text' => $user['nickname'],
  783. 'left' => 250,
  784. 'top' => 840,
  785. 'fontPath' => $filelink['Bold'], //字体文件
  786. 'fontSize' => 16, //字号
  787. 'fontColor' => '40,40,40', //字体颜色
  788. 'angle' => 0,
  789. ),
  790. array(
  791. 'text' => '邀请您加入' . $siteName,
  792. 'left' => 250,
  793. 'top' => 880,
  794. 'fontPath' => $filelink['Normal'], //字体文件
  795. 'fontSize' => 16, //字号
  796. 'fontColor' => '40,40,40', //字体颜色
  797. 'angle' => 0,
  798. )
  799. ),
  800. 'background' => $item['pic']
  801. );
  802. $resWap = $resWap && $posterInfo = setSharePoster($config, 'wap/spread/poster');
  803. if (!is_array($posterInfo)) throw new ValidateException('海报生成失败');
  804. $posterInfo['dir'] = tidy_url($posterInfo['dir'], null, $siteUrl);
  805. $attachmentRepository->create($uploadType, -1, $user->uid, [
  806. 'attachment_category_id' => 0,
  807. 'attachment_name' => $posterInfo['name'],
  808. 'attachment_src' => $posterInfo['dir']
  809. ]);
  810. if ($resWap) {
  811. $item['wap_poster'] = $posterInfo['dir'];
  812. }
  813. }
  814. return $spreadBanner;
  815. }
  816. public function getUsername($uid)
  817. {
  818. return User::getDB()->where('uid', $uid)->value('nickname');
  819. }
  820. /**
  821. * @param $uid
  822. * @param $inc
  823. * @param string $type
  824. * @author xaboy
  825. * @day 2020/6/22
  826. */
  827. public function incBrokerage($uid, $inc, $type = '+')
  828. {
  829. $moneyKey = 'b_top_' . date('Y-m');
  830. $weekKey = 'b_top_' . monday();
  831. //TODO 佣金周榜
  832. $brokerage = Cache::zscore($weekKey, $uid);
  833. $brokerage = $type == '+' ? bcadd($brokerage, $inc, 2) : bcsub($brokerage, $inc, 2);
  834. Cache::zadd($weekKey, $brokerage, $uid);
  835. //TODO 佣金月榜
  836. $brokerage = Cache::zscore($moneyKey, $uid);
  837. $brokerage = $type == '+' ? bcadd($brokerage, $inc, 2) : bcsub($brokerage, $inc, 2);
  838. Cache::zadd($moneyKey, $brokerage, $uid);
  839. }
  840. /**
  841. * TODO 删除排行榜中的个人排行
  842. * @param $uid
  843. * @author Qinii
  844. * @day 2022/10/18
  845. */
  846. public function delBrokerageTop($uid)
  847. {
  848. $moneyKey = 'b_top_' . date('Y-m');
  849. $weekKey = 'b_top_' . monday();
  850. Cache::zrem($weekKey,$uid);
  851. Cache::zrem($moneyKey,$uid);
  852. }
  853. public function brokerageWeekTop($uid, $page, $limit)
  854. {
  855. $key = 'b_top_' . monday();
  856. return $this->topList($key, $page, $limit) + ['position' => $this->userPosition($key, $uid)];
  857. }
  858. public function brokerageMonthTop($uid, $page, $limit)
  859. {
  860. $key = 'b_top_' . date('Y-m');
  861. return $this->topList($key, $page, $limit) + ['position' => $this->userPosition($key, $uid)];
  862. }
  863. /**
  864. * //TODO 绑定上下级关系
  865. * @param User $user
  866. * @param int $spreadUid
  867. * @throws DbException
  868. * @author xaboy
  869. * @day 2020/6/22
  870. */
  871. public function bindSpread(User $user, int $spreadUid)
  872. {
  873. if ($spreadUid && !$user->spread_uid && $user->uid != $spreadUid && ($spread = $this->dao->get($spreadUid)) && $spread->spread_uid != $user->uid && !$spread->cancel_time) {
  874. $config = systemConfig(['extension_limit', 'extension_limit_day', 'integral_user_give']);
  875. event('user.spread.before', compact('user','spreadUid'));
  876. Db::transaction(function () use ($spread, $spreadUid, $user, $config) {
  877. $user->spread_uid = $spreadUid;
  878. $user->spread_time = date('Y-m-d H:i:s');
  879. if ($config['extension_limit'] && $config['extension_limit_day']) {
  880. $user->spread_limit = date('Y-m-d H:i:s', strtotime('+ ' . $config['extension_limit_day'] . ' day'));
  881. }
  882. $spread->spread_count++;
  883. if ($config['integral_user_give'] > 0 && $user->isNew) {
  884. $integral = (int)$config['integral_user_give'];
  885. $spread->integral += $integral;
  886. app()->make(UserBillRepository::class)->incBill($spreadUid, 'integral', 'spread', [
  887. 'link_id' => $user->uid,
  888. 'status' => 1,
  889. 'title' => '邀请好友',
  890. 'number' => $integral,
  891. 'mark' => '邀请好友奖励' . $integral . '红包米',
  892. 'balance' => $spread->integral
  893. ]);
  894. }
  895. $spread->save();
  896. $user->save();
  897. //TODO 推广人月榜
  898. Cache::zincrby('s_top_' . date('Y-m'), 1, $spreadUid);
  899. //TODO 推广人周榜
  900. Cache::zincrby('s_top_' . monday(), 1, $spreadUid);
  901. });
  902. Queue::push(UserBrokerageLevelJob::class, ['uid' => $spreadUid, 'type' => 'spread_user', 'inc' => 1]);
  903. app()->make(UserBrokerageRepository::class)->incMemberValue($user->uid, 'member_share_num', 0);
  904. event('user.spread', compact('user','spreadUid'));
  905. }
  906. }
  907. public function userPosition($key, $uid)
  908. {
  909. $index = Cache::zrevrank($key, $uid);
  910. if ($index === false)
  911. return 0;
  912. else
  913. return $index + 1;
  914. }
  915. public function topList($key, $page, $limit)
  916. {
  917. $res = Cache::zrevrange($key, ($page - 1) * $limit, $limit, true);
  918. $ids = array_keys($res);
  919. $count = Cache::zcard($key);
  920. $list = count($ids) ? $this->dao->users($ids, 'uid,avatar,nickname')->toArray() : [];
  921. foreach ($list as $k => $v) {
  922. $list[$k]['count'] = $res[$v['uid']] ?? 0;
  923. }
  924. $sort = array_column($list, 'count');
  925. array_multisort($sort, SORT_DESC, $list);
  926. return compact('count', 'list');
  927. }
  928. public function spreadWeekTop($page, $limit)
  929. {
  930. $key = 's_top_' . monday();
  931. return $this->topList($key, $page, $limit);
  932. }
  933. public function spreadMonthTop($page, $limit)
  934. {
  935. $key = 's_top_' . date('Y-m');
  936. return $this->topList($key, $page, $limit);
  937. }
  938. /**
  939. * @param $uid
  940. * @param $nickname
  941. * @param $sort
  942. * @param $page
  943. * @param $limit
  944. * @return array
  945. * @throws DataNotFoundException
  946. * @throws DbException
  947. * @throws ModelNotFoundException
  948. * @author xaboy
  949. * @day 2020/6/22
  950. */
  951. public function getOneLevelList($uid, $nickname, $sort, $page, $limit)
  952. {
  953. $query = $this->search(['spread_uid' => $uid, 'nickname' => $nickname, 'sort' => $sort]);
  954. $count = $query->count();
  955. $list = $query->setOption('field', [])->field('uid,avatar,nickname,pay_count,pay_price,spread_count,spread_time')->page($page, $limit)->select();
  956. return compact('list', 'count');
  957. }
  958. /**
  959. * @param $uid
  960. * @param $nickname
  961. * @param $sort
  962. * @param $page
  963. * @param $limit
  964. * @return array
  965. * @throws DataNotFoundException
  966. * @throws DbException
  967. * @throws ModelNotFoundException
  968. * @author xaboy
  969. * @day 2020/6/22
  970. */
  971. public function getTwoLevelList($uid, $nickname, $sort, $page, $limit)
  972. {
  973. $ids = $this->dao->getSubIds($uid);
  974. if (count($ids)) {
  975. $query = $this->search(['spread_uids' => $ids, 'nickname' => $nickname, 'sort' => $sort]);
  976. $count = $query->count();
  977. $list = $query->setOption('field', [])->field('uid,avatar,nickname,pay_count,pay_price,spread_count,spread_time')->page($page, $limit)->select();
  978. } else {
  979. $list = [];
  980. $count = 0;
  981. }
  982. return compact('list', 'count');
  983. }
  984. public function getLevelList($uid, array $where, $page, $limit)
  985. {
  986. if (!$where['level']) {
  987. $ids = $this->dao->getSubIds($uid);
  988. $ids[] = $uid;
  989. $where['spread_uids'] = $ids;
  990. } else if ($where['level'] == 2) {
  991. $ids = $this->dao->getSubIds($uid);
  992. if (!count($ids)) return ['list' => [], 'count' => 0];
  993. $where['spread_uids'] = $ids;
  994. } else {
  995. $where['spread_uid'] = $uid;
  996. }
  997. $query = $this->search($where);
  998. $count = $query->count();
  999. $list = $query->setOption('field', [])->field('uid,avatar,nickname,is_promoter,pay_count,pay_price,spread_count,create_time,spread_time,spread_limit')->page($page, $limit)->select();
  1000. return compact('list', 'count');
  1001. }
  1002. /**
  1003. * @param $uid
  1004. * @param $page
  1005. * @param $limit
  1006. * @param array $where
  1007. * @return array
  1008. * @throws DataNotFoundException
  1009. * @throws DbException
  1010. * @throws ModelNotFoundException
  1011. * @author xaboy
  1012. * @day 2020/6/26
  1013. */
  1014. public function subOrder($uid, $page, $limit, array $where = [])
  1015. {
  1016. if (isset($where['level'])) {
  1017. if (!$where['level']) {
  1018. $ids = $this->dao->getSubIds($uid);
  1019. $subIds = $ids ? $this->dao->getSubAllIds($ids) : [];
  1020. } else if ($where['level'] == 2) {
  1021. $ids = $this->dao->getSubIds($uid);
  1022. $subIds = $ids ? $this->dao->getSubAllIds($ids) : [];
  1023. $ids = [];
  1024. } else if ($where['level'] == -1) {
  1025. $ids = [];
  1026. $subIds = [];
  1027. } else {
  1028. $ids = $this->dao->getSubIds($uid);
  1029. $subIds = [];
  1030. }
  1031. } else {
  1032. $ids = $this->dao->getSubIds($uid);
  1033. $subIds = $ids ? $this->dao->getSubAllIds($ids) : [];
  1034. }
  1035. $all = array_unique(array_merge($ids, $subIds));
  1036. $all[] = -1;
  1037. $query = app()->make(StoreOrderRepository::class)->usersOrderQuery($where, $all, (!isset($where['level']) || !$where['level'] || $where['level'] == -1) ? $uid : 0);
  1038. $count = $query->count();
  1039. $list = $query->page($page, $limit)->field('uid,order_sn,pay_time,extension_one,extension_two,is_selfbuy')->with(['user' => function ($query) {
  1040. $query->field('avatar,nickname,uid');
  1041. }])->select()->toArray();
  1042. foreach ($list as $k => $item) {
  1043. if ($item['is_selfbuy']) {
  1044. if ($item['uid'] == $uid) {
  1045. $list[$k]['brokerage'] = $item['extension_one'];
  1046. } else if (in_array($item['uid'], $ids)) {
  1047. $list[$k]['brokerage'] = $item['extension_two'];
  1048. } else {
  1049. $list[$k]['brokerage'] = 0;
  1050. }
  1051. } else {
  1052. $list[$k]['brokerage'] = in_array($item['uid'], $ids) ? $item['extension_one'] : $item['extension_two'];
  1053. }
  1054. unset($list[$k]['extension_one'], $list[$k]['extension_two']);
  1055. }
  1056. return compact('count', 'list');
  1057. }
  1058. /**
  1059. * @param User $user
  1060. * @return User
  1061. * @throws DataNotFoundException
  1062. * @throws DbException
  1063. * @throws ModelNotFoundException
  1064. * @author xaboy
  1065. * @day 2020/7/2
  1066. */
  1067. public function mainUser(User $user): User
  1068. {
  1069. if (!$user->main_uid || $user->uid == $user->main_uid) return $user;
  1070. $switchUser = $this->dao->get($user->main_uid);
  1071. if (!$switchUser) return $user;
  1072. if ($user->wechat_user_id && !$switchUser->wechat_user_id) {
  1073. $switchUser->wechat_user_id = $user->wechat_user_id;
  1074. $switchUser->save();
  1075. }
  1076. return $switchUser;
  1077. }
  1078. public function switchUser(User $user, $uid)
  1079. {
  1080. if ($user->uid == $uid || !$this->dao->existsWhere(['uid' => $uid, 'phone' => $user->phone]))
  1081. throw new ValidateException('操作失败');
  1082. $this->dao->update($user->uid, ['main_uid' => $uid]);
  1083. $this->dao->getSearch([])->where('main_uid', $user->uid)->update(['main_uid' => $uid]);
  1084. $switchUser = $this->dao->get($uid);
  1085. if (!$switchUser->wechat_user_id) {
  1086. $switchUser->wechat_user_id = $user->wechat_user_id;
  1087. $switchUser->save();
  1088. }
  1089. return $switchUser;
  1090. }
  1091. public function returnToken($user, $tokenInfo)
  1092. {
  1093. if (!$user->status) {
  1094. throw new ValidateException('账号已被禁用');
  1095. }
  1096. $user = $user->hidden(['label_id', 'group_id', 'main_uid', 'pwd', 'addres', 'card_id', 'last_time', 'last_ip', 'create_time', 'mark', 'status', 'spread_uid', 'spread_time', 'real_name', 'birthday', 'brokerage_price'])->toArray();
  1097. return [
  1098. 'token' => $tokenInfo['token'],
  1099. 'exp' => $tokenInfo['out'],
  1100. 'expires_time' => strtotime('+ '.$tokenInfo['out']. 'seconds'),
  1101. 'user' => $user
  1102. ];
  1103. }
  1104. public function switchBrokerage(User $user, $brokerage)
  1105. {
  1106. $user->now_money = bcadd($user->now_money, $brokerage, 2);
  1107. $user->brokerage_price = bcsub($user->brokerage_price, $brokerage, 2);
  1108. Db::transaction(function () use ($brokerage, $user) {
  1109. $user->save();
  1110. app()->make(UserBillRepository::class)->incBill($user->uid, 'now_money', 'brokerage', [
  1111. 'link_id' => 0,
  1112. 'status' => 1,
  1113. 'title' => '佣金转入余额',
  1114. 'number' => $brokerage,
  1115. 'mark' => '成功转入余额' . floatval($brokerage) . '元',
  1116. 'balance' => $user->now_money
  1117. ]);
  1118. app()->make(UserBillRepository::class)->decBill($user->uid, 'brokerage', 'now_money', [
  1119. 'link_id' => 0,
  1120. 'status' => 1,
  1121. 'title' => '佣金转入余额',
  1122. 'number' => $brokerage,
  1123. 'mark' => '成功转入余额' . floatval($brokerage) . '元',
  1124. 'balance' => $user->brokerage_price
  1125. ]);
  1126. });
  1127. }
  1128. public function rmLabel($id)
  1129. {
  1130. return $this->search(['label_id' => $id])->update([
  1131. 'label_id' => Db::raw('trim(BOTH \',\' FROM replace(CONCAT(\',\',label_id,\',\'),\',' . $id . ',\',\',\'))')
  1132. ]);
  1133. }
  1134. public function changeSpreadForm($id)
  1135. {
  1136. $user = $this->dao->get($id);
  1137. $form = Elm::createForm(Route::buildUrl('systemUserSpreadChange', compact('id'))->build(), [
  1138. [
  1139. 'type' => 'span',
  1140. 'title' => '用户昵称',
  1141. 'children' => [$user->nickname]
  1142. ], [
  1143. 'type' => 'span',
  1144. 'title' => '上级合伙人 Id',
  1145. 'children' => [$user->spread ? (string)$user->spread->uid : '无']
  1146. ], [
  1147. 'type' => 'span',
  1148. 'title' => '上级合伙人昵称',
  1149. 'children' => [$user->spread ? (string)$user->spread->nickname : '无']
  1150. ], Elm::frameImage('spid', '上级合伙人', '/' . config('admin.admin_prefix') . '/setting/referrerList?field=spid')->prop('srcKey', 'src')->value($user->spread ? [
  1151. 'src' => $user->spread->avatar,
  1152. 'id' => $user->spread->uid,
  1153. ] : [])->modal(['modal' => false])->width('896px')->height('480px'),
  1154. ]);
  1155. return $form->setTitle('修改合伙人');
  1156. }
  1157. public function changeSpread($uid, $spread_id, $admin = 0)
  1158. {
  1159. $spreadLogRepository = app()->make(UserSpreadLogRepository::class);
  1160. $user = $this->dao->get($uid);
  1161. if ($user->spread_uid == $spread_id)
  1162. return;
  1163. $config = systemConfig(['extension_limit', 'extension_limit_day']);
  1164. Db::transaction(function () use ($config, $user, $spreadLogRepository, $spread_id, $admin) {
  1165. $old = $user->spread_uid ?: 0;
  1166. $spreadLogRepository->add($user->uid, $spread_id, $old, $admin);
  1167. $user->spread_time = $spread_id ? date('Y-m-d H:i:s') : null;
  1168. if ($spread_id && $config['extension_limit'] && $config['extension_limit_day']) {
  1169. $user->spread_limit = date('Y-m-d H:i:s', strtotime('+ ' . $config['extension_limit_day'] . ' day'));
  1170. } else {
  1171. $user->spread_limit = null;
  1172. }
  1173. $user->spread_uid = $spread_id;
  1174. if ($spread_id) {
  1175. $this->dao->incSpreadCount($spread_id);
  1176. }
  1177. if ($old) {
  1178. $this->dao->decSpreadCount($old);
  1179. }
  1180. $user->save();
  1181. });
  1182. }
  1183. public function syncSpreadStatus()
  1184. {
  1185. if (systemConfig('extension_limit')) {
  1186. $this->dao->syncSpreadStatus();
  1187. }
  1188. }
  1189. /**
  1190. * TODO 红包米增加
  1191. * @param int $uid
  1192. * @param int $number
  1193. * @param $title
  1194. * @param $type
  1195. * @param $data
  1196. * @author Qinii
  1197. * @day 6/9/21
  1198. */
  1199. public function incIntegral(int $uid,int $number,$title,$type,$data)
  1200. {
  1201. Db::transaction(function() use($uid,$number,$title,$type,$data){
  1202. $user = $this->dao->get($uid);
  1203. $user->integral = $user->integral + $number;
  1204. $user->save();
  1205. app()->make(UserBillRepository::class)
  1206. ->incBill($uid, 'integral', $type,
  1207. [
  1208. 'link_id' => 0,
  1209. 'status' => 1,
  1210. 'title' => $title,
  1211. 'number' => $data['number'],
  1212. 'mark' => $data['mark'],
  1213. 'balance' =>$data['balance'],
  1214. ]);
  1215. });
  1216. }
  1217. public function memberForm(int $id ,int $type)
  1218. {
  1219. if ($type) {
  1220. $form = Elm::createForm(Route::buildUrl('systemUserMemberSave', ['id' => $id])->build());
  1221. $field = 'member_level';
  1222. } else {
  1223. $form = Elm::createForm(Route::buildUrl('systemUserSpreadSave', ['id' => $id])->build());
  1224. $field = 'brokerage_level';
  1225. }
  1226. $data = $this->dao->get($id);
  1227. if (!$data) throw new ValidateException('数据不存在');
  1228. if (!$type && !$data['is_promoter']) throw new ValidateException('用户不是分销员');
  1229. $rules = [
  1230. Elm::select($field, '级别',$data->$field)->options(function () use($type){
  1231. $options = app()->make(UserBrokerageRepository::class)->options(['type' => $type])->toArray();
  1232. return $options;
  1233. }),
  1234. ];
  1235. $form->setRule($rules);
  1236. return $form->setTitle($type ? '编辑会员等级' : '编辑分销等级');
  1237. }
  1238. public function updateLevel(int $id, array $data, int $type)
  1239. {
  1240. $make = app()->make(UserBrokerageRepository::class);
  1241. $user = $this->dao->get($id);
  1242. $field = $type ? 'member_level' : 'brokerage_level';
  1243. if ($data[$field] == $user->$field) return true;
  1244. $has = $make->fieldExists('brokerage_level', $data[$field], null, $type);
  1245. if (!$has) throw new ValidateException('等级不存在');
  1246. Db::transaction(function() use($id, $data, $field, $user, $type){
  1247. $user->$field = $data[$field];
  1248. if ($type) $user->member_value = 0;
  1249. $user->save();
  1250. if ($type == 0) app()->make(UserBillRepository::class)->search(['category' => 'sys_brokerage'])->where('uid', $id)->delete();
  1251. });
  1252. }
  1253. public function cancel(User $user)
  1254. {
  1255. Db::transaction(function () use ($user) {
  1256. $uid = $user->uid;
  1257. $name = '已注销用户' . substr(uniqid(true, true), -6);
  1258. if ($user->wechat) {
  1259. $user->wechat->save([
  1260. 'unionid' => '',
  1261. 'openid' => '',
  1262. 'routine_openid' => '',
  1263. 'nickname' => $name,
  1264. 'headimgurl' => '',
  1265. 'city' => '',
  1266. 'province' => '',
  1267. 'country' => '',
  1268. ]);
  1269. }
  1270. $user->save([
  1271. 'account' => '',
  1272. 'real_name' => '',
  1273. 'nickname' => $name,
  1274. 'avatar' => '',
  1275. 'phone' => '',
  1276. 'address' => '',
  1277. 'card_id' => '',
  1278. 'main_uid' => 0,
  1279. 'label_id' => '',
  1280. 'group_id' => 0,
  1281. 'spread_uid' => 0,
  1282. 'status' => 0,
  1283. 'is_promoter' => 0,
  1284. 'wechat_user_id' => 0,
  1285. 'cancel_time' => date('Y-m-d H:i:s')
  1286. ]);
  1287. $this->getSearch([])->where('main_uid', $uid)->update(['main_uid' => 0]);
  1288. app()->make(UserAddressRepository::class)->getSearch([])->where('uid', $uid)->delete();
  1289. app()->make(UserMerchantRepository::class)->getSearch([])->where('uid', $uid)->delete();
  1290. app()->make(UserReceiptRepository::class)->getSearch([])->where('uid', $uid)->delete();
  1291. app()->make(StoreServiceRepository::class)->getSearch([])->where('uid', $uid)->update(['uid' => 0, 'status' => 0, 'is_open' => 0]);
  1292. $this->getSearch([])->where('spread_uid', $uid)->update(['spread_uid' => 0]);
  1293. $this->delBrokerageTop($uid);
  1294. app()->make(CommunityRepository::class)->destoryByUid($uid);
  1295. });
  1296. }
  1297. public function svipForm(int $id)
  1298. {
  1299. $formData = $this->dao->get($id);
  1300. if (!$formData) throw new ValidateException('数据不存在');
  1301. $form = Elm::createForm(Route::buildUrl('systemUserSvipUpdate', ['id' => $id])->build());
  1302. $form->setRule([
  1303. Elm::switches('is_svip', '付费会员', $formData->is_svip > 0 ? 1 : 0)->activeValue(1)->inactiveValue(0)->inactiveText('关')->activeText('开'),
  1304. Elm::radio('type', '修改类型', 1)->options([
  1305. ['label' => '增加', 'value' => 1],
  1306. ['label' => '减少', 'value' => 0],
  1307. ])->requiredNum(),
  1308. Elm::number('add_time', '付费会员期限(天)')->required()->min(1),
  1309. Elm::input('end_time', '当前有效期期限', $formData->is_svip > 0 ? $formData->svip_endtime : 0)->disabled(true),
  1310. ]);
  1311. return $form->setTitle( '编辑付费会员期限' );
  1312. }
  1313. /**
  1314. * TODO 设置付费会员
  1315. * @param $id
  1316. * @param $data
  1317. * @author Qinii
  1318. * @day 2022/11/22
  1319. */
  1320. public function svipUpdate($id, $data,$adminId)
  1321. {
  1322. $user = app()->make(UserRepository::class)->get($id);
  1323. if (!$user) throw new ValidateException('用户不存在');
  1324. if ($user['is_svip'] < 1 && ($data['is_svip'] == 0 || !$data['type']))
  1325. throw new ValidateException('该用户还不是付费会员');
  1326. if ($user['is_svip'] == 3 && $data['is_svip'] == 1)
  1327. throw new ValidateException('该用户已是永久付费会员');
  1328. if ($data['is_svip']) {
  1329. $day = ($data['type'] == 1 ? '+ ' : '- ').$data['add_time'];
  1330. $endtime = ($user['svip_endtime'] && $user['is_svip'] != 0) ? $user['svip_endtime'] : date('Y-m-d H:i:s',time());
  1331. $is_svip = 1;
  1332. $svip_endtime = date('Y-m-d H:i:s',strtotime("$endtime $day day" ));
  1333. //结束时间小于当前 就关闭付费会员
  1334. if (strtotime($svip_endtime) <= time()) {
  1335. $is_svip = 0;
  1336. }
  1337. } else {
  1338. $is_svip = 0;
  1339. $svip_endtime = date('Y-m-d H:i:s', time());
  1340. }
  1341. $make = app()->make(UserOrderRepository::class);
  1342. $res = [
  1343. 'title' => $data['is_svip'] == 0 ? '平台取消会员资格' : ($data['type'] ? '平台赠送' : '平台扣除'),
  1344. 'link_id' => 0,
  1345. 'order_sn' => $make->setOrderSn(),
  1346. 'pay_price' => 0,
  1347. 'order_info' => json_encode($data,JSON_UNESCAPED_UNICODE),
  1348. 'uid' => $id,
  1349. 'order_type' => UserOrderRepository::TYPE_SVIP . $is_svip,
  1350. 'pay_type' => 'sys',
  1351. 'status' => 1,
  1352. 'pay_time' => date('Y-m-d H:i:s',time()),
  1353. 'admin_id' => $adminId,
  1354. 'end_time' => $svip_endtime,
  1355. 'other' => $user->is_svip == -1 ? 'first' : '',
  1356. ];
  1357. Db::transaction(function () use($user, $res, $is_svip, $svip_endtime,$make) {
  1358. $make->create($res);
  1359. $user->is_svip = $is_svip;
  1360. $user->svip_endtime = $svip_endtime;
  1361. $user->save();
  1362. });
  1363. }
  1364. public function updateBaseInfo($data, $user)
  1365. {
  1366. Db::transaction(function() use($data, $user){
  1367. $user->save(array_filter([
  1368. 'nickname' => $data['nickname'] ?? '',
  1369. 'avatar' => $data['avatar'] ?? '',
  1370. ]));
  1371. if (isset($user->wechat) ) {
  1372. $user->wechat->save(array_filter([
  1373. 'nickname' => $data['nickname'] ?? '',
  1374. 'headimgurl' => $data['avatar'] ?? '',
  1375. ]));
  1376. }
  1377. });
  1378. }
  1379. }