StoreServiceUserRepository.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2016~2024 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\store\service;
  12. use app\common\dao\store\service\StoreServiceUserDao;
  13. use app\common\model\store\service\StoreServiceLog;
  14. use app\common\repositories\BaseRepository;
  15. use think\exception\ValidateException;
  16. /**
  17. * Class StoreServiceRepository
  18. * @package app\common\repositories\store\service
  19. * @author xaboy
  20. * @day 2020/5/29
  21. * @mixin StoreServiceUserDao
  22. */
  23. class StoreServiceUserRepository extends BaseRepository
  24. {
  25. /**
  26. * StoreServiceRepository constructor.
  27. * @param StoreServiceUserDao $dao
  28. */
  29. public function __construct(StoreServiceUserDao $dao)
  30. {
  31. $this->dao = $dao;
  32. }
  33. /**
  34. * 更新服务信息。
  35. *
  36. * 本函数用于根据提供的服务日志对象更新相关服务用户的信息。如果该服务用户不存在,则创建新记录;
  37. * 如果存在,则根据是否为服务人员更新未读消息计数,并更新最后一条日志ID和时间戳。
  38. *
  39. * @param StoreServiceLog $log 服务日志对象,包含服务ID、用户ID和商家ID等信息。
  40. * @param bool $isService 指示当前操作是否为服务人员的操作,用于区分更新哪一方的未读消息计数。
  41. * @return StoreServiceLog 返回更新后的服务用户对象。
  42. */
  43. public function updateInfo(StoreServiceLog $log, $isService)
  44. {
  45. // 根据服务日志信息尝试获取已存在的服务用户记录
  46. $serviceUser = $this->dao->getWhere(['service_id' => $log->service_id, 'uid' => $log->uid, 'mer_id' => $log->mer_id]);
  47. // 如果服务用户不存在,则创建新记录,并初始化相关字段
  48. if (!$serviceUser) {
  49. $serviceUser = $this->dao->create([
  50. 'service_id' => $log->service_id,
  51. 'uid' => $log->uid,
  52. 'mer_id' => $log->mer_id,
  53. 'service_unread' => $isService ? 1 : 0,
  54. 'user_unread' => $isService ? 0 : 1,
  55. 'is_online' => 1,
  56. 'last_log_id' => $log->service_log_id,
  57. 'last_time' => date('Y-m-d H:i:s')
  58. ]);
  59. } else {
  60. // 如果服务用户已存在,根据$isService的值更新服务人员或用户的未读消息计数
  61. $isService ? $serviceUser->service_unread++ : $serviceUser->user_unread++;
  62. // 更新最后一条日志ID和时间戳
  63. $serviceUser->last_log_id = $log->service_log_id;
  64. $serviceUser->last_time = date('Y-m-d H:i:s');
  65. // 设置在线状态为1
  66. $serviceUser->is_online = 1;
  67. // 保存更新后的服务用户信息
  68. $serviceUser->save();
  69. }
  70. // 返回更新或创建后的服务用户对象
  71. return $serviceUser;
  72. }
  73. /**
  74. * 读取消息方法
  75. * 该方法用于标记指定用户的消息为已读。它可以处理用户消息和客服消息两种类型。
  76. *
  77. * @param string $merId 商户ID,用于确定消息所属的商户。
  78. * @param string $uid 用户ID,用于确定要标记已读消息的用户。
  79. * @param bool $isService 是否为客服消息,默认为null,表示用户消息。如果设置为true,则表示处理客服消息。
  80. */
  81. public function read($merId, $uid, $isService = null)
  82. {
  83. // 根据$isService的值决定更新user_unread还是service_unread字段
  84. $field = $isService ? 'service_unread' : 'user_unread';
  85. // 查询满足条件的记录并更新相应的未读消息字段为0,表示已读
  86. $this->dao->search([
  87. 'mer_id' => $merId,
  88. 'uid' => $uid,
  89. ])->update([$field => 0]);
  90. }
  91. /**
  92. * 获取用户的商家列表
  93. *
  94. * 根据用户ID($uid)获取该用户关注的商家列表,支持分页和数量限制。
  95. * 商家列表按照最后更新时间降序排列。同时,还包括每个商家的未读消息总数。
  96. *
  97. * @param int $uid 用户ID
  98. * @param int $page 当前页码
  99. * @param int $limit 每页显示数量
  100. * @return array 包含商家总数和商家列表的数组
  101. */
  102. public function userMerchantList($uid, $page, $limit)
  103. {
  104. // 构建查询条件,筛选出属于用户$uid的商家,按最后更新时间降序排列
  105. $query = $this->dao->search(['uid' => $uid])->group('mer_id')->order('last_time DESC');
  106. // 计算符合条件的商家总数
  107. $count = $query->count();
  108. // 查询商家列表,包括商家基本信息和最新的消息信息
  109. // 使用with语法加载关联数据,简化查询并优化性能
  110. $list = $query->with(['merchant' => function ($query) {
  111. // 仅加载商家ID、头像和名称,优化数据库查询性能
  112. $query->field('mer_id,mer_avatar,mer_name');
  113. }, 'last'])->page($page, $limit)->setOption('field', [])->field('*,max(last_log_id) as last_log_id,sum(user_unread) as num')->select()->toArray();
  114. // 加载系统配置,用于后续设置默认商家头像和名称
  115. $config = systemConfig(['site_logo', 'site_name']);
  116. // 遍历商家列表,对于默认商家(mer_id为0)设置系统默认头像和名称
  117. foreach ($list as &$item) {
  118. if ($item['mer_id'] == 0) {
  119. $item['merchant'] = [
  120. 'mer_avatar' => $config['site_logo'],
  121. 'mer_name' => $config['site_name'],
  122. 'mer_id' => 0,
  123. ];
  124. }
  125. }
  126. unset($item);
  127. // 返回商家总数和商家列表的数组
  128. return compact('count', 'list');
  129. }
  130. /**
  131. * 获取商家用户列表
  132. * 该方法用于根据商家ID和用户ID,以及分页信息,获取特定商家的用户列表。
  133. * 这是通过验证商家服务状态,并查询相应的用户列表来实现的。
  134. *
  135. * @param int $merId 商家ID,用于确定要查询的商家。
  136. * @param int $uid 用户ID,用于确定要查询的用户。
  137. * @param int $page 当前页码,用于分页查询。
  138. * @param int $limit 每页数量,用于分页查询。
  139. * @return array 返回符合查询条件的商家用户列表。
  140. * @throws ValidateException 如果没有查询权限或商家服务状态不在线,则抛出异常。
  141. */
  142. public function merUserList($merId, $uid, $page, $limit)
  143. {
  144. // 通过商家ID和用户ID获取商家服务实例
  145. $service = app()->make(StoreServiceRepository::class)->getService($uid, $merId);
  146. // 验证是否有查询权限,如果没有则抛出异常
  147. if (!$service)
  148. throw new ValidateException('没有权限');
  149. // 验证商家服务是否在线,如果离线则抛出异常
  150. if (!$service['status'])
  151. throw new ValidateException('客服已离线,请开启客服状态');
  152. // 调用内部方法查询商家用户列表,并返回结果
  153. return $this->serviceUserList(['service_id' => $service->service_id], $merId, $page, $limit);
  154. }
  155. /**
  156. * 获取服务人员列表
  157. * 根据给定的条件、分页和限制,查询服务人员列表及其相关信息。
  158. *
  159. * @param string $where 查询条件
  160. * @param int $merId 商家ID
  161. * @param int $page 当前页码
  162. * @param int $limit 每页记录数
  163. * @return array 返回包含总数和列表的数组
  164. */
  165. public function serviceUserList($where, $merId, $page, $limit)
  166. {
  167. // 构建查询语句,根据条件进行搜索,并按最后活跃时间降序排列
  168. $query = $this->dao->search($where)->group('uid')->order('last_time DESC');
  169. // 计算满足条件的总记录数
  170. $count = $query->count();
  171. // 分页查询,并加载关联数据,包括用户信息、标记信息和最后一条消息
  172. $list = $query->page($page, $limit)->with([
  173. 'user' => function ($query) {
  174. // 加载用户详细信息,包括用户类型、性别、是否推广员等,并加载推广人信息
  175. $query->field('uid,avatar,nickname,user_type,sex,is_promoter,phone,now_money,phone,birthday,spread_uid')->with([
  176. 'spread' => function ($query) {
  177. // 加载推广人的基本信息
  178. $query->field('uid,avatar,nickname,cancel_time');
  179. }
  180. ]);
  181. },
  182. 'mark' => function ($query) use ($merId) {
  183. // 根据商家ID加载标记信息
  184. $query->where('mer_id', $merId);
  185. },
  186. 'last'
  187. ])->setOption('field', [])->field('*,max(last_log_id) as last_log_id,sum(service_unread) as num')->select()->toArray();
  188. foreach ($list as &$item) {
  189. $m = $item['mark']['extend_value'] ?? '';
  190. unset($item['mark']);
  191. $item['mark'] = $m;
  192. }
  193. // 如果列表中第一个元素的服务用户ID为null,则说明查询结果不正常,返回空列表
  194. if (count($list) && is_null($list[0]['service_user_id'])) {
  195. $list = [];
  196. }
  197. // 返回包含总数和列表的数组
  198. return compact('count', 'list');
  199. }
  200. /**
  201. * 更新用户在线状态
  202. *
  203. * 本函数用于根据用户ID更新用户的在线状态。它首先通过搜索找到特定用户,然后更新该用户的在线状态。
  204. * 在线状态通常是一个布尔值,表示用户当前是否在线。
  205. *
  206. * @param int $uid 用户ID。这是用于唯一标识用户的数值。
  207. * @param bool $online 用户的在线状态。true表示用户在线,false表示用户不在线。
  208. * @return bool 更新操作的结果。成功返回true,失败返回false。
  209. */
  210. public function online($uid, $online)
  211. {
  212. // 根据$uid搜索用户,并更新is_online字段为$online值
  213. return $this->dao->search(['uid' => $uid])->update(['is_online' => $online]);
  214. }
  215. /**
  216. * 将在线状态设置为离线
  217. *
  218. * 本函数用于更新指定记录的在线状态,将 `is_online` 字段的值从 1 更改为 0。
  219. * 它不接受任何参数,直接调用 DAO(数据访问对象)进行查询和更新操作。
  220. * 查询条件是 `is_online` 等于 1,这意味着只会影响之前处于在线状态的记录。
  221. *
  222. * @return int 返回影响的行数,这可以帮助判断操作是否成功。
  223. */
  224. public function onlineDown()
  225. {
  226. // 使用DAO的search方法初始化查询,然后通过where方法指定查询条件。
  227. // 最后,通过update方法更新查询结果集中的`is_online`字段为0,即将在线状态改为离线。
  228. return $this->dao->search([])->where(['is_online' => 1])->update(['is_online' => 0]);
  229. }
  230. }