Chat.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. <?php
  2. namespace app\controller\v2;
  3. use app\extra\basic\Base;
  4. use app\extra\tools\UploadExtend;
  5. use app\middleware\AuthMiddleware;
  6. use app\model\saas\SaasChatMsg;
  7. use app\model\saas\SaasChatStore;
  8. use app\model\saas\SaasService;
  9. use app\model\saas\SaasStore;
  10. use app\model\saas\SaasUserOpen;
  11. use app\model\system\SystemUser;
  12. use app\service\saas\ChatStoreService;
  13. use DI\Attribute\Inject;
  14. use LinFly\Annotation\Attributes\Route\Controller;
  15. use LinFly\Annotation\Attributes\Route\GetMapping;
  16. use LinFly\Annotation\Attributes\Route\Middleware;
  17. use LinFly\Annotation\Attributes\Route\PostMapping;
  18. use support\Request;
  19. use support\Response;
  20. use Webman\Push\Api;
  21. #[Controller("/v2/chat"),Middleware(AuthMiddleware::class)]
  22. class Chat extends Base
  23. {
  24. #[Inject]
  25. protected ChatStoreService $service;
  26. /**
  27. * 获取客服列表-已聊过的
  28. * @param Request $request
  29. * @return Response
  30. */
  31. #[GetMapping("list")]
  32. public function getServiceList(Request $request): Response
  33. {
  34. try {
  35. $param = $request->all();
  36. if (!empty($param['size'])) {
  37. $param['pageSize'] = $param['size'];
  38. }
  39. $param['openid'] = $request->user['openid'];
  40. $list = $this->service->setModel()->getList($param,null,true,['last','avatar'],['last' => function($data,$resp) use($param){
  41. $last = (new SaasChatMsg)->where(['poi_id' => $resp['poi_id'],'openid' => $param['openid']])->order("create_at","desc")->field("content,create_at,type")->findOrEmpty();
  42. if ($last->isEmpty()) {
  43. return ['type' => "text","content"=>"-",'num' => 0,"create_at"=> formatTime(date("Y-m-d H:i:s",time()))];
  44. }
  45. return ["content"=> str_cut_ellipsis($last['content'],12),'num' => 0,"create_at"=> formatTime($last['create_at']),'type' => $last['type']];
  46. },'avatar' => function(){
  47. return sConf("service.logo");
  48. }]);
  49. $user = (new SaasUserOpen)->where(['openid' => $param['openid']])->findOrEmpty();
  50. if ($user->isEmpty()) return error("数据错误");
  51. $userState = 1;
  52. if (empty($user['avatar'])) {
  53. $userState = 0;
  54. }
  55. return successTrans("success.data",['data' => pageFormat($list),'user' => $userState]);
  56. } catch (\Throwable $throwable) {
  57. return error($throwable->getMessage());
  58. }
  59. }
  60. /**
  61. * 获取基础客服消息
  62. */
  63. #[GetMapping("service")]
  64. public function getChatStore(Request $request): Response
  65. {
  66. try {
  67. $param = $this->_valid([
  68. "poi.require" => "参数错误",
  69. "size.require" => "参数错误",
  70. "page.require" => "参数错误",
  71. "goods.default" => "",
  72. "order.default" => "",
  73. ],$request->method());
  74. if (!is_array($param)) return error($param);
  75. $store = (new SaasStore)->where("poi_id",$param['poi'])->findOrEmpty();
  76. if ($store->isEmpty()) return error("店铺不存在");
  77. $userAvatar = $request->user['avatar'];
  78. // 获取最新的10条聊天记录
  79. $msg = (new SaasChatMsg)->where(['openid' => $request->user['openid'],'poi_id' => $store['poi_id']])
  80. ->append(['time','userType','msgType'])
  81. ->withAttr(['time' => function($resp,$data){
  82. return strtotime($data['create_at']) * 1000;
  83. },'userType' => function($resp,$data){
  84. if ($data['source'] == 1) {
  85. return "self";
  86. } else {
  87. return "friend";
  88. }
  89. },'msgType' => function($resp,$data){
  90. return $data['type'];
  91. }])
  92. ->order("id","desc")
  93. ->paginate([
  94. "list_rows" => $param['size'],
  95. "page" => 1
  96. ]);
  97. $serviceAvatar = sConf("service.logo");
  98. $star = (new SaasService)->where("poi_id",$param['poi'])->with(['quick'])->findOrEmpty();
  99. // 获取在线客服
  100. $service = (new SystemUser)->where(['store_id' => $param['poi'],"type" => 3,"is_line" => 1])->order("last_msg_at","asc")->findOrEmpty();
  101. print_r($service->toArray());
  102. if ($service->isEmpty()) { // 无客服在线
  103. return success("ok",[
  104. "avatar" => $userAvatar,
  105. "userId" => md5($request->user['openid']),
  106. "msg" => $msg,
  107. "service" => $serviceAvatar,
  108. "store" => [
  109. "shopName" => $store['poi_name'],
  110. "shopId" => $store['poi_id'],
  111. ],
  112. "quick" => $star,
  113. "chat_id" => 0, // 客服ID
  114. ]);
  115. }
  116. $chatStore = (new SaasChatStore)->where(['poi_id'=> $store['poi_id'],"openid" => $request->user['openid']])->findOrEmpty();
  117. if ($chatStore->isEmpty()) {
  118. $chatStore->insertGetId([
  119. "poi_id" => $store['poi_id'],
  120. "poi_name" => $store['poi_name'],
  121. "openid" => $request->user['openid'],
  122. "nickname" => $request->user['nickname'],
  123. "service_id" => $service['id'],
  124. "order" => $param['order']??'',
  125. "goods" => $param['goods']??'',
  126. "last_at" => getDateFull()
  127. ]);
  128. } else {
  129. $chatStore->service_id = $service['id'];
  130. $chatStore->order = $param['order']??'';
  131. $chatStore->nickname = $request->user['nickname'];
  132. $chatStore->goods = $param['goods']??'';
  133. $chatStore->last_at = getDateFull();
  134. $chatStore->save();
  135. }
  136. return success("ok",[
  137. "avatar" => $userAvatar,
  138. "userId" => md5($request->user['openid']),
  139. "msg" => $msg,
  140. "service" => $serviceAvatar,
  141. "store" => [
  142. "shopName" => $store['poi_name'],
  143. "shopId" => $store['poi_id'],
  144. ],
  145. "quick" => $star,
  146. "chat_id" => $service['id'], // 客服ID
  147. ]);
  148. } catch (\Throwable $throwable) {
  149. return error($throwable->getMessage());
  150. }
  151. }
  152. /**
  153. * 历史聊天列表
  154. * @param Request $request
  155. * @return Response
  156. */
  157. #[GetMapping("msg")]
  158. public function getMsgList(Request $request): Response
  159. {
  160. try {
  161. $param = $this->_valid([
  162. "poi.require" => "参数错误",
  163. "size.require" => "参数错误",
  164. "page.require" => "参数错误",
  165. ],$request->method());
  166. if (!is_array($param)) return error($param);
  167. $store = (new SaasStore)->where("poi_id",$param['poi'])->findOrEmpty();
  168. if ($store->isEmpty()) return error("店铺不存在");
  169. $msg = (new SaasChatMsg)->where(['openid' => $request->user['openid'],'poi_id' => $store['poi_id']])
  170. ->append(['time','userType','msgType'])
  171. ->withAttr(['time' => function($resp,$data){
  172. return strtotime($data['create_at']) * 1000;
  173. },'userType' => function($resp,$data){
  174. if ($data['source'] == 1) {
  175. return "self";
  176. } else {
  177. return "friend";
  178. }
  179. },'msgType' => function($resp,$data){
  180. return $data['type'];
  181. }])
  182. ->order("id","desc")
  183. ->paginate([
  184. "list_rows" => $param['size'],
  185. "page" => $param['page']
  186. ]);
  187. return success("ok",['data' => $msg]);
  188. } catch (\Throwable $throwable) {
  189. return error($throwable->getMessage());
  190. }
  191. }
  192. /**
  193. * 转人工
  194. * @return Response|void
  195. */
  196. public function checkServiceUser()
  197. {
  198. try {
  199. } catch (\Throwable $throwable) {
  200. return error($throwable->getMessage());
  201. }
  202. }
  203. /**
  204. * 发送文字消息
  205. * @param Request $request
  206. * @return Response
  207. */
  208. #[PostMapping("text")]
  209. public function sendTextMsg(Request $request): Response
  210. {
  211. try {
  212. $param = $this->_valid([
  213. "content.require" => trans("empty.require"),
  214. "groupId.require" => trans("empty.require"),
  215. "chatId.require" => trans("empty.require"),
  216. "type.require" => trans("empty.require")
  217. ],"post");
  218. if (!is_array($param)) return error($param);
  219. (new SaasChatMsg)->insertGetId([
  220. "source" => 1,
  221. "openid" => $request->user['openid'],
  222. "content" => is_array($param['content'])?json_encode($param['content']):$param['content'],
  223. "type" => $param['type'],
  224. "msgId" => time(),
  225. "poi_id" => $param['groupId'],
  226. "service_id" => $param['chatId'], // 客服ID
  227. ]);
  228. $chatStore = (new SaasChatStore)->where(['openid' => $request->user['openid'],"service_id" => $param['chatId']])->with(['user' => function($query){
  229. $query->field("openid,nickname,avatar,mobile,create_at");
  230. }])->append(['avatar'])->withAttr(['avatar' => function () {
  231. return sConf("service.logo");
  232. }])->findOrEmpty();
  233. $total = (new SaasChatMsg)->where(["poi_id" => $chatStore['poi_id'],"service_id" => $param['chatId'],"openid" => $chatStore['openid'],'is_read' => 0])->count();
  234. if (!$chatStore->isEmpty()) {
  235. $chatStore->last_at = getDateFull();
  236. $chatStore->save();
  237. $chatStore['lastTime'] = formatTime(getDateFull());
  238. $chatStore['last'] = [
  239. "content" => is_array($param['content'])?json_encode($param['content']):str_cut_ellipsis($param['content']),
  240. "type" => $param['type'],
  241. "num" => $total
  242. ];
  243. }
  244. // 推送消息
  245. $api = new Api('http://127.0.0.1:3232', config('plugin.webman.push.app.app_key'),config('plugin.webman.push.app.app_secret'));
  246. $api->trigger("service-{$param['chatId']}","message",[
  247. "type" => $param['type'],
  248. "content" => is_array($param['content'])?json_encode($param['content']):$param['content'],
  249. "openid" => $request->user['openid'],
  250. "nick" => [],
  251. "user" => [],
  252. "userType" => "friend",
  253. "avatar" => $request->user['avatar'],
  254. "time" => time() * 1000,
  255. "msgId" => md5($request->user['openid'].time()),
  256. "item" => $chatStore->toArray()
  257. ]);
  258. return successTrans("success.data");
  259. } catch (\Throwable $throwable) {
  260. return error($throwable->getMessage());
  261. }
  262. }
  263. /**
  264. * 发送图片消息
  265. * @param Request $request
  266. * @return Response
  267. */
  268. #[PostMapping("image")]
  269. public function sendImageMsg(Request $request): Response
  270. {
  271. try {
  272. $param = $this->_valid([
  273. "groupId.require" => trans("empty.require"),
  274. "type.require" => trans("empty.require"),
  275. "chatId.require" => trans("empty.require"),
  276. ],"post");
  277. if (!is_array($param)) return error($param);
  278. $resp = UploadExtend::uploadFile();
  279. if (!isset($resp[0]['url'])) return error("发送失败");
  280. $param['content'] = $resp[0]['url'];
  281. (new SaasChatMsg)->insertGetId([
  282. "source" => 1,
  283. "openid" => $request->user['openid'],
  284. "content" => is_array($param['content'])?json_encode($param['content']):$param['content'],
  285. "type" => $param['type'],
  286. "msgId" => time(),
  287. "poi_id" => $param['groupId'],
  288. "service_id" => $param['chatId'], // 客服ID
  289. ]);
  290. $chatStore = (new SaasChatStore)->where(['openid' => $request->user['openid'],"service_id" => $param['chatId']])->with(['user' => function($query){
  291. $query->field("openid,nickname,avatar,mobile,create_at");
  292. }])->append(['avatar'])->withAttr(['avatar' => function () {
  293. return sConf("service.logo");
  294. }])->findOrEmpty();
  295. $total = (new SaasChatMsg)->where(["poi_id" => $chatStore['poi_id'],"service_id" => $param['chatId'],"openid" => $chatStore['openid'],'is_read' => 0])->count();
  296. if (!$chatStore->isEmpty()) {
  297. $chatStore->last_at = getDateFull();
  298. $chatStore->save();
  299. $chatStore['lastTime'] = formatTime(getDateFull());
  300. $chatStore['last'] = [
  301. "content" => is_array($param['content'])?json_encode($param['content']):str_cut_ellipsis($param['content']),
  302. "type" => $param['type'],
  303. "num" => $total
  304. ];
  305. }
  306. // 推送消息
  307. $api = new Api('http://127.0.0.1:3232', config('plugin.webman.push.app.app_key'),config('plugin.webman.push.app.app_secret'));
  308. $api->trigger("service-{$param['chatId']}","message",[
  309. "type" => $param['type'],
  310. "content" => is_array($param['content'])?json_encode($param['content']):$param['content'],
  311. "openid" => $request->user['openid'],
  312. "nick" => [],
  313. "user" => [],
  314. "userType" => "friend",
  315. "avatar" => $request->user['avatar'],
  316. "time" => time() * 1000,
  317. "msgId" => md5($request->user['openid'].time()),
  318. "item" => $chatStore->toArray()
  319. ]);
  320. } catch (\Throwable $throwable) {
  321. return error($throwable->getMessage());
  322. }
  323. }
  324. }