UserController.php 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679
  1. <?php
  2. /**
  3. * 用户管理
  4. * @author x.b
  5. */
  6. declare(strict_types=1);
  7. namespace Modules\Manage\Controllers;
  8. use App\Constants\ChangeLogConstant;
  9. use App\Exception\ApiException;
  10. use App\Model\Mongo\SendCardHistoryModel;
  11. use App\Model\VipOrderModel;
  12. use App\Repositories\Service\QueueService;
  13. use App\Repositories\UserRepository as UserRepository;
  14. use App\Model\CoinsLogModel;
  15. use App\Model\VipCardModel;
  16. use App\Model\UserModel as Model;
  17. use Carbon\Carbon;
  18. use Hyperf\DbConnection\Db;
  19. use Hyperf\Validation\Contract\ValidatorFactoryInterface;
  20. use App\Repositories\MessageRepository;
  21. class UserController extends BaseController
  22. {
  23. /**
  24. * 详细
  25. * @param yes id int $id 用户ID 如 100
  26. * @return mixed
  27. * @example param_json_data string: {"handshake":"","data":{"id":14550388}}
  28. */
  29. public function detail(ValidatorFactoryInterface $validatorFactory)
  30. {
  31. $inputData = $this->getJsonData();
  32. $rules = [
  33. 'id' => 'required|numeric',
  34. ];
  35. $validator = $validatorFactory->make($inputData, $rules);
  36. if ($validator->fails()) {
  37. return json_fail($validator->errors()->first());
  38. }
  39. $id = $inputData['id'];
  40. $select = ['*'];
  41. $model = Model::query();
  42. $result = $model->select($select)
  43. ->where('id', $id)
  44. ->first();
  45. if (!$result) {
  46. return json_fail('用户不存在');
  47. }
  48. // 查他的上级邀请人的名字
  49. $result['parent_nick'] = '';
  50. if ($result['parent_uid']) {
  51. $select = ['nick'];
  52. $r = Model::query()->select($select)
  53. ->where('code', $result['parent_uid'])
  54. ->first();
  55. if ($r) {
  56. $result['parent_nick'] = $r['nick'];
  57. }
  58. }
  59. $userRepo = make(UserRepository::class);
  60. $userDataInfo = $userRepo->getUserInfoData($result['code']);
  61. $result['qrcode'] = $userDataInfo['account_qrcode_content'];
  62. $orderCount = VipOrderModel::where(['user_code' => $result['code']])->count();
  63. $payCount = VipOrderModel::where(['user_code' => $result['code']])->where(['status' => 1])->count();
  64. $result['order_count'] = $orderCount;
  65. $result['pay_count'] = $payCount;
  66. return json_success($result);
  67. }
  68. /**
  69. * 列表
  70. * @param ValidatorFactoryInterface $validatorFactory
  71. * @return mixed
  72. * @example param_json_data string: {"handshake":"","data":{"page":1,"page_size":5,"search":{"nick":"用户CH3J30","stime":"","otime":""},"order":"created_at","order_sort":"desc"}}
  73. */
  74. public function list(ValidatorFactoryInterface $validatorFactory)
  75. {
  76. $inputData = $this->getJsonData();
  77. $page = isset($inputData['page']) ? (int)$inputData['page'] : 1;
  78. $page_size = isset($inputData['page_size']) ? (int)$inputData['page_size'] : 20;
  79. $select = ['*'];
  80. $model = Model::query();
  81. $order_key = isset($inputData['order']) ? $inputData['order'] : 'id';
  82. $order_value = isset($inputData['order_sort']) ? $inputData['order_sort'] : 'desc';
  83. if (!$order_key) {
  84. $order_key='id'; //不要信任前端,他可能会传个空字符串过来!
  85. }
  86. if (!$order_value) {
  87. $order_value = 'desc';
  88. }
  89. $search = isset($inputData['search']) ? $inputData['search'] : array();
  90. if ($search) {
  91. foreach ($search as $k => $v) {
  92. if (!strlen((string)$v)) {
  93. continue;
  94. }
  95. $operator = '=';
  96. if ($k == 'channel_id' && $v == 'official') {
  97. // 官方代表空
  98. $v = "";
  99. }
  100. if ($k == 'max_view') {
  101. preg_match('/^(=|>|<)(\d{1,10})$/', $v, $matches);
  102. if (isset($matches[2])) {
  103. $operator = $matches[1];
  104. $v = $matches[2];
  105. }
  106. }
  107. switch ($k) {
  108. case "nick": // 用户名
  109. case "mobile": // 手机号
  110. $model->where($k, 'like', "{$v}%");
  111. break;
  112. case "stime": // 自定义-开始日期
  113. $model->where('created_at', '>=', $v);
  114. break;
  115. case "otime": // 自定义-结束日期
  116. $model->where('created_at', '<=', Carbon::parse($v)->endOfDay()->toDateTimeString());
  117. break;
  118. default:
  119. $model->where($k, $operator, $v);
  120. }
  121. }
  122. }
  123. $result = $model->select($select)
  124. ->orderBy((string)$order_key, (string)$order_value)
  125. ->paginate($page_size, ['*'], 'page', $page);
  126. return json_success($result);
  127. }
  128. /**
  129. * 删除
  130. */
  131. public function delete()
  132. {
  133. }
  134. /**
  135. * 更新
  136. * @return mixed
  137. * @example param_json_data string: {"handshake":"","data":{"id":14550388,"status":"1"}}
  138. */
  139. public function update(ValidatorFactoryInterface $validatorFactory)
  140. {
  141. $inputData = $this->getJsonData();
  142. $rules = [
  143. 'id' => 'required|numeric',
  144. ];
  145. $validator = $validatorFactory->make($inputData, $rules);
  146. if ($validator->fails()) {
  147. return json_fail($validator->errors()->first());
  148. }
  149. $id = $inputData['id'];
  150. $status = isset($inputData['status']) ? $inputData['status'] : '';
  151. if ($status) {
  152. if (!in_array($status, array(1,2,3))) {
  153. return json_fail('请按文档正确传参,用户的状态值');
  154. }
  155. }
  156. $user_info = Model::query()->where('id', $id)
  157. ->first();
  158. if (!$user_info) {
  159. return json_fail('用户不存在');
  160. }
  161. $data = array(
  162. // 更多支持编辑的字段,后续依业务进行迭代扩展 。。
  163. );
  164. if (isset($inputData['nick'])) {
  165. $data['nick'] = trim($inputData['nick']);
  166. }
  167. if (isset($inputData['avatar'])) {
  168. $data['avatar'] = trim($inputData['avatar']);
  169. }
  170. if (isset($inputData['bg_cover'])) {
  171. $data['bg_cover'] = trim($inputData['bg_cover']);
  172. }
  173. if (isset($inputData['intro'])) {
  174. $data['intro'] = rtrim($inputData['intro']);
  175. }
  176. if (isset($inputData['status'])) {
  177. $data['status'] = intval($inputData['status']);
  178. }
  179. if (isset($inputData['mobile'])) {
  180. $data['mobile'] = intval($inputData['mobile']);
  181. }
  182. $data = action_data($data);
  183. if ($data) {
  184. $result = Model::query()->where('id', $id)
  185. ->update($data);
  186. if (!$result) {
  187. return json_fail('更新失败');
  188. }
  189. }
  190. // 创建管理员日志
  191. $oldItem = clone $user_info;
  192. $newitem = Model::query()->where('id', $id)->first();
  193. $logSubject = '修改一个用户信息,名称:'. $user_info['nick'];
  194. $logSvalue = $oldItem->id;
  195. $logDbData = [
  196. 'after_items' => [
  197. $newitem->toArray(),
  198. ],
  199. 'before_items' => [
  200. $oldItem->toArray(),
  201. ],
  202. ];
  203. $this->log($logSubject, $logSvalue, $logDbData);
  204. make(UserRepository::class)->delUserCache($user_info['code']);
  205. return json_success('', '更新成功');
  206. }
  207. /**
  208. * 发放金币
  209. * @param int yes $id 用户ID, 如 14550388
  210. * @param int yes $coins 金币数, 如 50 则是加; 如 -100 则是减少
  211. * @return mixed
  212. * @example param_json_data string: {"handshake":"","data":{"id":14550388,"coins":50}}
  213. */
  214. public function sendCoins(ValidatorFactoryInterface $validatorFactory)
  215. {
  216. $inputData = $this->getJsonData();
  217. $rules = [
  218. 'id' => 'required|numeric',
  219. 'coins' => 'required|numeric',
  220. ];
  221. $validator = $validatorFactory->make($inputData, $rules);
  222. if ($validator->fails()) {
  223. return json_fail($validator->errors()->first());
  224. }
  225. $id = $inputData['id'];
  226. $coins = $inputData['coins'];
  227. $user_info = Model::query()
  228. ->where('id', $id)
  229. ->first();
  230. if (!$user_info) {
  231. return json_fail('用户不存在');
  232. }
  233. if ($coins>0) {
  234. $result = Model::query()
  235. ->where('id', $id)
  236. ->increment('coins', $coins);
  237. } else {
  238. $_coins = abs((int)$coins); //取绝对值
  239. if ($user_info->coins < $_coins) {
  240. return json_fail('用户金币不够,不能扣减');
  241. }
  242. $result = Model::query()
  243. ->where('id', $id)
  244. ->decrement('coins', $_coins);
  245. }
  246. if (!$result) {
  247. return json_fail('处理失败');
  248. }
  249. make(UserRepository::class)->delUserCache($user_info['code']); //清除用户信息redis缓存
  250. if ($coins < 0) {
  251. $way = ChangeLogConstant::WAY_2;
  252. $type = ChangeLogConstant::TYPE_22;
  253. } else {
  254. $way = ChangeLogConstant::WAY_1;
  255. $type = ChangeLogConstant::TYPE_18;
  256. }
  257. // 记录帐变使用日志
  258. $changeData = [
  259. 'user_uid' => $user_info['code'],
  260. 'currency_type' => ChangeLogConstant::CHANGE_COIN,
  261. 'amount' => abs((int)$coins),
  262. 'way' => $way,
  263. 'type' => $type,
  264. ];
  265. // 帐变记录
  266. make(QueueService::class)->saveChangeLogJob($changeData);
  267. // 创建管理员日志
  268. $oldItem = clone $user_info;
  269. $newitem = Model::query()->where('id', $id)->first();
  270. $logSubject = '对一个用户发放金币,名称:'. $user_info['nick'];
  271. $logSvalue = $oldItem->id;
  272. $logDbData = [
  273. 'after_items' => [
  274. $newitem->toArray(),
  275. ],
  276. 'before_items' => [
  277. $oldItem->toArray(),
  278. ],
  279. ];
  280. $this->log($logSubject, $logSvalue, $logDbData);
  281. return json_success('', '处理成功');
  282. }
  283. /**
  284. * bindPhone 绑定老用户
  285. * 业务逻辑:
  286. * 1. 后台对指定新用户 输入 老用户对手机号
  287. * 2。查询出 老用户对设备号,设备类型
  288. * 3。将新/老用户的仅 设备号和设备类型,互换一下。
  289. * 4。调接口,退出新老用户(即 缓存中清理下 )
  290. * @param int yes $id 新用户的ID,如100
  291. * @param int yes $mobile 老用户的手机号
  292. * @return mixed
  293. * @example param_json_data string: {"handshake":"","data":{"id":14550389,"mobile":"13873840000"}}
  294. */
  295. public function bindPhone(ValidatorFactoryInterface $validatorFactory)
  296. {
  297. $inputData = $this->getJsonData();
  298. $rules = [
  299. 'id' => 'required|numeric',
  300. 'mobile' => 'required|numeric',
  301. ];
  302. $validator = $validatorFactory->make($inputData, $rules);
  303. if ($validator->fails()) {
  304. return json_fail($validator->errors()->first());
  305. }
  306. $id = $inputData['id'];
  307. $mobile = $inputData['mobile'];
  308. $user_info_new = Model::query()
  309. ->where('id', $id)
  310. ->first();
  311. if (!$user_info_new) {
  312. return json_fail('新用户不存在');
  313. }
  314. $user_info_old = Model::query()
  315. ->where('mobile', $mobile)
  316. ->first();
  317. if (!$user_info_old) {
  318. return json_fail('老用户对应的电话号码不存在');
  319. }
  320. // 交换更新用户设备号,设备类型
  321. Db::beginTransaction();
  322. try {
  323. $data = array(
  324. 'device_no' => $user_info_old['device_no'],
  325. 'device_type' => $user_info_old['device_type'],
  326. 'finger_hash' => $user_info_old['finger_hash'],
  327. );
  328. $r = Model::query()
  329. ->where('id', $id)
  330. ->update($data);
  331. if (!$r) {
  332. throw new ApiException('更新新用户设备信息失败');
  333. }
  334. $data = array(
  335. 'device_no' => $user_info_new['device_no'],
  336. 'device_type' => $user_info_new['device_type'],
  337. 'finger_hash' => $user_info_new['finger_hash'],
  338. );
  339. $r = Model::query()
  340. ->where('mobile', $mobile)
  341. ->update($data);
  342. if (!$r) {
  343. throw new ApiException('更新老用户设备信息失败');
  344. }
  345. // 清理新/旧用户缓存数据
  346. $m = make(UserRepository::class);
  347. $m->userLogout($user_info_new['code']);
  348. $m->userLogout($user_info_old['code']);
  349. Db::commit();
  350. } catch (\Exception $e) {
  351. Db::rollBack();
  352. }
  353. // 创建管理员日志
  354. $oldItem = clone $user_info_new;
  355. $oldItem2 = clone $user_info_old;
  356. $newitem = Model::query()->where('id', $id)->first();
  357. $newitem2 = Model::query()->where('id', $user_info_old['id'])->first();
  358. $logSubject = "绑定老用户,用户id:{$user_info_new['id']}->{$user_info_old['id']}";
  359. $logSvalue = $oldItem->id;
  360. $logDbData = [
  361. 'after_items' => [
  362. $newitem->toArray(),
  363. $newitem2->toArray(),
  364. ],
  365. 'before_items' => [
  366. $oldItem->toArray(),
  367. $oldItem2->toArray(),
  368. ],
  369. ];
  370. $this->log($logSubject, $logSvalue, $logDbData);
  371. return json_success('', '处理成功');
  372. }
  373. /**
  374. * 对指定用户发放会员卡
  375. * @param int yes $id 用户id
  376. * @param int yes $card_id 会员卡ID,来源会员卡列表的字段id
  377. * @return mixed
  378. * @example param_json_data string: {"handshake":"","data":{"id":424432,"card_id":1}}
  379. */
  380. public function sendCard(ValidatorFactoryInterface $validatorFactory)
  381. {
  382. $inputData = $this->getJsonData();
  383. $rules = [
  384. 'id' => 'required',
  385. 'card_id' => 'required',
  386. ];
  387. $validator = $validatorFactory->make($inputData, $rules);
  388. if ($validator->fails()) {
  389. return json_fail($validator->errors()->first());
  390. }
  391. $uid = $inputData['id'];
  392. $card_id = $inputData['card_id'];
  393. $card_info = VipCardModel::query()
  394. ->where('id', $card_id)
  395. ->first();
  396. if (!$card_info) {
  397. return json_fail('会员卡不存在');
  398. }
  399. if (!$card_info['status']) {
  400. return json_fail('会员卡未启动');
  401. }
  402. $user_info = Model::query()
  403. ->where('id', $uid)
  404. ->first();
  405. if (!$user_info) {
  406. return json_fail('用户不存在');
  407. }
  408. try {
  409. //加会员天数
  410. $userInfo = make(UserRepository::class)
  411. ->getUserInfoFromCache($user_info['code']);
  412. if ($userInfo['is_vip'] == 'y') {
  413. $vipTime = Carbon::parse($userInfo['vip_expired'])
  414. ->addDays($card_info['day'])
  415. ->toDateTimeString();
  416. } else {
  417. $vipTime = Carbon::now()
  418. ->addDays($card_info['day'])
  419. ->toDateTimeString();
  420. }
  421. $result = Model::query()
  422. ->where('id', $user_info['id'])
  423. ->update(['vip_expired' => $vipTime]);
  424. if (!$result) {
  425. return json_fail('添加用户会员卡时间失败');
  426. }
  427. make(UserRepository::class)->delUserCache($user_info['code']); //清除用户信息redis缓存
  428. } catch (\Exception $e) {
  429. return json_fail('处理失败');
  430. }
  431. //$managerInfo = $authService->getManagerInfo();
  432. // $roleId = $managerInfo['role_id'];
  433. // $managerId = $managerInfo['manager_id'];
  434. $managerInfo = $this->getCurrentManagerInfo();
  435. make(SendCardHistoryModel::class)->db()->insertOne(
  436. [
  437. 'mid_id' => $managerInfo['manager_id'],
  438. 'user_code' => $user_info['code'],
  439. 'vip_id' => $card_info['id'],
  440. 'vip_days' => $card_info['day']
  441. ]
  442. );
  443. // 创建管理员日志
  444. $oldItem = clone $user_info;
  445. $newitem = Model::query()->where('id', $user_info['id'])->first();
  446. $logSubject = "发放{$card_info['day']}天的会员卡,会员卡配置ID:{$card_info['id']},用户id:{$user_info['id']}";
  447. $logSvalue = $oldItem->id;
  448. $logDbData = [
  449. 'after_items' => [
  450. $newitem->toArray(),
  451. ],
  452. 'before_items' => [
  453. $oldItem->toArray(),
  454. ],
  455. ];
  456. $this->log($logSubject, $logSvalue, $logDbData);
  457. return json_success('', '处理成功');
  458. }
  459. /**
  460. * 指定用户的邀请详细
  461. * @param yes id int $id 用户ID 如 100
  462. * @return mixed
  463. * @example param_json_data string: {"handshake":"","page":1,"page_size":5,"data":{"id":30}}
  464. */
  465. public function inviteDetail(ValidatorFactoryInterface $validatorFactory)
  466. {
  467. $inputData = $this->getJsonData();
  468. $page = isset($inputData['page']) ? (int)$inputData['page'] : 1;
  469. $page_size = isset($inputData['page_size']) ? (int)$inputData['page_size'] : 20;
  470. $rules = [
  471. 'id' => 'required|numeric',
  472. ];
  473. $validator = $validatorFactory->make($inputData, $rules);
  474. if ($validator->fails()) {
  475. return json_fail($validator->errors()->first());
  476. }
  477. $order_key = isset($inputData['order']) ? $inputData['order'] : 'id';
  478. $order_value = isset($inputData['order_sort']) ? $inputData['order_sort'] : 'desc';
  479. if (!$order_key) {
  480. $order_key='id'; //不要信任前端,他可能会传个空字符串过来!
  481. }
  482. if (!$order_value) {
  483. $order_value = 'desc';
  484. }
  485. $id = $inputData['id'];
  486. $select = ['*'];
  487. $user_info = Model::query()->select($select)
  488. ->where('id', $id)
  489. ->first();
  490. if (!$user_info) {
  491. return json_fail('用户不存在');
  492. }
  493. $select = ['nick','id','mobile','created_at'];
  494. $invite_list = Model::query()->select($select)
  495. ->where('parent_uid', $user_info['code'])
  496. ->orderBy((string)$order_key, (string)$order_value)
  497. ->paginate($page_size, ['*'], 'page', $page);
  498. if (!$invite_list) {
  499. $invite_list = array();
  500. }
  501. $result = array(
  502. 'user_info' => $user_info,
  503. 'invite_list' => $invite_list
  504. );
  505. return json_success($result);
  506. }
  507. /**
  508. * 邀请列表
  509. * @param ValidatorFactoryInterface $validatorFactory
  510. * @return mixed
  511. * @example param_json_data string: {"handshake":"","data":{"page":1,"page_size":5,"search":{"nick":"用户CH3J30","id":"","mobile":"","code":"","stime":"","otime":""},"order":"invite","order_sort":"desc"}}
  512. */
  513. public function inviteList(ValidatorFactoryInterface $validatorFactory)
  514. {
  515. $inputData = $this->getJsonData();
  516. $page = isset($inputData['page']) ? (int)$inputData['page'] : 1;
  517. $page_size = isset($inputData['page_size']) ? (int)$inputData['page_size'] : 20;
  518. $select = ['id', 'nick', 'mobile', 'mobile', 'device_no', 'device_type', 'channel_id', 'code', 'status', 'invite', 'coins', 'ip'];
  519. $model = Model::query();
  520. $order_key = isset($inputData['order']) ? $inputData['order'] : 'id';
  521. $order_value = isset($inputData['order_sort']) ? $inputData['order_sort'] : 'desc';
  522. if (!$order_key) {
  523. $order_key='id'; //不要信任前端,他可能会传个空字符串过来!
  524. }
  525. if (!$order_value) {
  526. $order_value = 'desc';
  527. }
  528. $search = isset($inputData['search']) ? $inputData['search'] : array();
  529. if ($search) {
  530. foreach ($search as $k => $v) {
  531. if (!strlen((string)$v)) {
  532. continue;
  533. }
  534. switch ($k) {
  535. case "nick": // 用户名
  536. case "mobile": // 手机号
  537. case "code": // 邀请码
  538. $model->where($k, 'like', "{$v}%");
  539. break;
  540. case "stime": // 自定义-开始日期
  541. $model->where('created_at', '>=', $v);
  542. break;
  543. case "otime": // 自定义-结束日期
  544. $model->where('created_at', '<=', Carbon::parse($v)->endOfDay()->toDateTimeString());
  545. break;
  546. default:
  547. $model->where($k, $v);
  548. }
  549. }
  550. }
  551. $model->where('invite', '>', '0'); //仅查询有邀请人数的
  552. $invite_all_select = [Db::raw('count(*) as id_all'), Db::raw('sum(invite) as invite_all')];
  553. $invite_all = $model->select($invite_all_select)->first();
  554. if ($invite_all) {
  555. if (!$invite_all['id_all']) {
  556. $invite_all['average'] = 0;
  557. } else {
  558. $invite_all['average'] = round(($invite_all['invite_all'] / $invite_all['id_all']), 1);
  559. }
  560. } else {
  561. $invite_all = array(
  562. "id_all" => 0,
  563. "invite_all" => 0,
  564. 'average' => 0,
  565. );
  566. }
  567. $invite_list = $model->select($select)
  568. ->orderBy((string)$order_key, (string)$order_value)
  569. ->paginate($page_size, ['*'], 'page', $page);
  570. $result = array(
  571. 'invite_all' => $invite_all,
  572. 'invite_list' => $invite_list,
  573. );
  574. return json_success($result);
  575. }
  576. /**
  577. * 发送系统消息给单个用户
  578. */
  579. public function sendMessageToUser(ValidatorFactoryInterface $validatorFactory)
  580. {
  581. $inputData = $this->getJsonData();
  582. $rules = [
  583. 'subject' => 'required|string|max:255',
  584. 'receive_uid' => 'required|max:32',
  585. 'content' => 'required|string',
  586. ];
  587. $validator = $validatorFactory->make($inputData, $rules);
  588. if ($validator->fails()) {
  589. // 如果有错误(可能是多个信息),这里只取第一个错误信息返回.
  590. return json_fail($validator->errors()->first());
  591. }
  592. $receiveUid = data_get($inputData, 'receive_uid', '');
  593. $content = data_get($inputData, 'content', '');
  594. $subject = data_get($inputData, 'subject', '');
  595. $msgRepo = make(MessageRepository::class);
  596. $msgRepo->sendTextFromSys($receiveUid, $content, $subject);
  597. return json_success(['result' => 'success']);
  598. }
  599. }