ChatLogic.php 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | likeshop开源商城系统
  4. // +----------------------------------------------------------------------
  5. // | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
  6. // | gitee下载:https://gitee.com/likeshop_gitee
  7. // | github下载:https://github.com/likeshop-github
  8. // | 访问官网:https://www.likeshop.cn
  9. // | 访问社区:https://home.likeshop.cn
  10. // | 访问手册:http://doc.likeshop.cn
  11. // | 微信公众号:likeshop技术社区
  12. // | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
  13. // | likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
  14. // | 禁止对系统程序代码以任何目的,任何形式的再发布
  15. // | likeshop团队版权所有并拥有最终解释权
  16. // +----------------------------------------------------------------------
  17. // | author: likeshop.cn.team
  18. // +----------------------------------------------------------------------
  19. namespace app\common\logic;
  20. use app\common\cache\ChatCache;
  21. use app\common\enum\{ChatGoodsEnum, ChatMsgEnum, ChatEnum};
  22. use app\common\model\{ChatRelation, Goods, Kefu, User};
  23. use app\common\service\ConfigService;
  24. /**
  25. * 通用聊天逻辑
  26. * Class ChatLogic
  27. * @package app\common\logic
  28. */
  29. class ChatLogic extends BaseLogic
  30. {
  31. /**
  32. * @notes 获取在线客服
  33. * @return array|bool
  34. * @author 段誉
  35. * @date 2021/12/14 12:07
  36. */
  37. public static function getOnlineKefu()
  38. {
  39. $key = config('project.websocket_prefix') . 'kefu';
  40. return (new ChatCache())->getSmembersArray($key);
  41. }
  42. /**
  43. * @notes 在线用户
  44. * @return array|bool
  45. * @author 段誉
  46. * @date 2021/12/14 12:11
  47. */
  48. public static function getOnlineUser()
  49. {
  50. $key = config('project.websocket_prefix') . 'user';
  51. return (new ChatCache())->getSmembersArray($key);
  52. }
  53. /**
  54. * @notes 格式化聊天记录
  55. * @param $records
  56. * @return array
  57. * @author 段誉
  58. * @date 2022/3/14 15:05
  59. */
  60. public static function formatChatRecords($records) : array
  61. {
  62. if (empty($records)) {
  63. return [];
  64. }
  65. $kefu = [];
  66. $user = [];
  67. // 获取到客服和用户不同的两组id
  68. foreach ($records as $item) {
  69. if ($item['from_type'] == ChatEnum::TYPE_KEFU) {
  70. $kefu[] = $item['from_id'];
  71. } else {
  72. $user[] = $item['from_id'];
  73. }
  74. }
  75. $kefu = array_unique($kefu);
  76. $user = array_unique($user);
  77. $kefu = Kefu::where('id', 'in', $kefu)->column('nickname, avatar', 'id');
  78. $user = User::where('id', 'in', $user)->column('nickname, avatar', 'id');
  79. foreach ($records as &$item) {
  80. $item['from_nickname'] = '';
  81. $item['from_avatar'] = '';
  82. if ($item['from_type'] == ChatEnum::TYPE_KEFU) {
  83. $kefuId = $item['from_id'];
  84. if (isset($kefu[$kefuId])) {
  85. $item['from_nickname'] = $kefu[$kefuId]['nickname'] ?? '';
  86. $item['from_avatar'] = $kefu[$kefuId]['avatar'] ?? '';
  87. }
  88. }
  89. if ($item['from_type'] == ChatEnum::TYPE_USER) {
  90. $userId = $item['from_id'];
  91. if (isset($user[$userId])) {
  92. $item['from_nickname'] = $user[$userId]['nickname'] ?? '';
  93. $item['from_avatar'] = $user[$userId]['avatar'] ?? '';
  94. }
  95. }
  96. $item['goods'] = [];
  97. if ($item['msg_type'] == ChatMsgEnum::TYPE_GOODS) {
  98. $item['goods'] = json_decode($item['msg'], true);
  99. }
  100. $item['create_time_stamp'] = strtotime($item['create_time']);
  101. }
  102. return array_reverse($records);
  103. }
  104. /**
  105. * @notes 绑定关系
  106. * @param $userId
  107. * @param $kefuId
  108. * @param $data
  109. * @param int $isRead
  110. * @return mixed
  111. * @author 段誉
  112. * @date 2022/3/14 15:06
  113. */
  114. public static function bindRelation($userId, $kefuId, $data, $isRead = 0)
  115. {
  116. $relation = ChatRelation::where(['user_id' => $userId])->findOrEmpty();
  117. $user = User::where(['id' => $userId])->findOrEmpty();
  118. if ($relation->isEmpty()) {
  119. $relation = ChatRelation::create([
  120. 'user_id' => $userId,
  121. 'kefu_id' => $kefuId,
  122. 'nickname' => $user['nickname'],
  123. 'avatar' => $user['avatar'],
  124. 'terminal' => $data['terminal'] ?? 0,
  125. 'msg' => $data['msg'] ?? '',
  126. 'msg_type' => $data['msg_type'] ?? ChatMsgEnum::TYPE_TEXT,
  127. 'is_read' => 1, // 新创建关系都算已读
  128. 'create_time' => time(),
  129. 'update_time' => time(),
  130. ]);
  131. } else {
  132. ChatRelation::update(
  133. [
  134. 'kefu_id' => $kefuId,
  135. 'nickname' => $user['nickname'],
  136. 'avatar' => $user['avatar'],
  137. 'terminal' => $data['terminal'] ?? 0,
  138. 'msg' => $data['msg'] ?? '',
  139. 'msg_type' => $data['msg_type'] ?? ChatMsgEnum::TYPE_TEXT,
  140. 'update_time' => time(),
  141. 'is_read' => $isRead
  142. ],
  143. ['id' => $relation['id']]
  144. );
  145. }
  146. return $relation['id'];
  147. }
  148. /**
  149. * @notes 配置
  150. * @return array
  151. * @author 段誉
  152. * @date 2021/12/17 11:24
  153. * @remark code => 0时显示人工客服页,code => 1时显示在线客服页
  154. */
  155. public static function getConfig(): array
  156. {
  157. // 在线客服状态 0->关闭; 1->开启
  158. if (self::getConfigSetting() != 1) {
  159. return ['code' => 0, 'msg' => ''];
  160. }
  161. // 缓存配置
  162. if ('redis' != self::getCacheDrive()) {
  163. return ['code' => 0, 'msg' => '请参考部署文档配置在线客服'];
  164. }
  165. // 当前在线客服
  166. // $online = self::getOnlineKefu();
  167. // if (empty($online)) {
  168. // return ['code' => 0, 'msg' => '当前客服不在线,有问题请联系人工客服'];
  169. // }
  170. return ['code' => 1, 'msg' => ''];
  171. }
  172. /**
  173. * @notes 检查配置
  174. * @return bool
  175. * @author 段誉
  176. * @date 2021/12/20 14:11
  177. */
  178. public static function checkConfig(): bool
  179. {
  180. try {
  181. if (self::getConfigSetting() != 1) {
  182. throw new \Exception('请联系管理员开启在线客服');
  183. }
  184. if ('redis' != self::getCacheDrive()) {
  185. throw new \Exception('请参考部署文档配置在线客服');
  186. }
  187. return true;
  188. } catch (\Exception $e) {
  189. self::$error = $e->getMessage();
  190. return false;
  191. }
  192. }
  193. /**
  194. * @notes 后台客服配置
  195. * @return array|int|mixed|string|null
  196. * @author 段誉
  197. * @date 2021/12/20 11:51
  198. */
  199. public static function getConfigSetting()
  200. {
  201. // 后台在线客服状态 0-关闭 1-开启
  202. // return ConfigService::get('service', 'status', 0);
  203. return 1;
  204. }
  205. /**
  206. * @notes 当前缓存驱动
  207. * @return mixed
  208. * @author 段誉
  209. * @date 2021/12/20 11:51
  210. */
  211. public static function getCacheDrive()
  212. {
  213. return config('cache.default');
  214. }
  215. /**
  216. * @notes 聊天商品信息
  217. * @param $params
  218. * @return array
  219. * @author 段誉
  220. * @date 2022/3/24 14:23
  221. */
  222. public static function getChatGoodsDetail($params)
  223. {
  224. switch ($params['type']) {
  225. case ChatGoodsEnum::GOODS_SECKILL:
  226. $goods = Goods::alias('g')
  227. ->join('seckill_goods s', 's.goods_id = g.id')
  228. ->where(['g.id' => $params['goods_id'], 's.id' => $params['activity_id']])
  229. ->field(['g.id', 'g.image', 'g.name','s.min_seckill_price' => 'min_price'])
  230. ->findOrEmpty();
  231. break;
  232. case ChatGoodsEnum::GOODS_TEAM:
  233. $goods = Goods::alias('g')
  234. ->join('team_goods t', 't.goods_id = g.id')
  235. ->where(['g.id' => $params['goods_id'], 't.id' => $params['activity_id']])
  236. ->field(['g.id', 'g.image', 'g.name','t.min_team_price' => 'min_price'])
  237. ->findOrEmpty();
  238. break;
  239. default:
  240. $goods = Goods::where(['id' => $params['goods_id']])
  241. ->field([
  242. 'id', 'image', 'min_price', 'name'
  243. ])
  244. ->findOrEmpty();
  245. }
  246. return $goods->toArray();
  247. }
  248. /**
  249. * @notes 禁用客服
  250. * @param $kefu_id
  251. * @author 段誉
  252. * @date 2022/4/14 17:42
  253. */
  254. public static function setChatDisable($kefu_id)
  255. {
  256. $cache = new ChatCache();
  257. $prefix = config('project.websocket_prefix');
  258. $key = $prefix .'kefu';
  259. $result = $cache->getSmembersArray($key);
  260. $fds = $cache->getSmembersArray($prefix . 'kefu_' . $kefu_id);
  261. if (in_array($kefu_id, $result) && $fds) {
  262. $cache->srem($key, $kefu_id);
  263. foreach ($fds as $fd) {
  264. $cache->srem($prefix . 'kefu_' . $kefu_id, $fd);
  265. $cache->del($prefix . 'fd_' . $fd);
  266. }
  267. }
  268. }
  269. }