StoreServiceLogRepository.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  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\StoreServiceLogDao;
  13. use app\common\model\store\service\StoreServiceLog;
  14. use app\common\repositories\BaseRepository;
  15. use app\common\repositories\store\order\StoreOrderRepository;
  16. use app\common\repositories\store\order\StoreRefundOrderRepository;
  17. use app\common\repositories\store\product\ProductGroupRepository;
  18. use app\common\repositories\store\product\ProductPresellRepository;
  19. use app\common\repositories\store\product\ProductRepository;
  20. use think\exception\ValidateException;
  21. use think\facade\Cache;
  22. /**
  23. * 客户用户对话记录
  24. */
  25. class StoreServiceLogRepository extends BaseRepository
  26. {
  27. /**
  28. * StoreServiceLogRepository constructor.
  29. * @param StoreServiceLogDao $dao
  30. */
  31. public function __construct(StoreServiceLogDao $dao)
  32. {
  33. $this->dao = $dao;
  34. }
  35. /**
  36. * 获取用户列表
  37. *
  38. * 本函数用于根据商家ID(merId)、用户ID(uid)、页码(page)和每页数量(limit)
  39. * 查询用户的详细信息列表。列表数据按照服务日志ID降序排列。
  40. * 同时,本函数还会处理首次加载时的数据标记读取操作,以更新数据的读取状态。
  41. * 最后,函数返回包含用户列表数量和详细信息的数据结构。
  42. *
  43. * @param string $merId 商家ID,用于限定查询的商家范围
  44. * @param string $uid 用户ID,用于限定查询的用户范围
  45. * @param int $page 当前页码,用于分页查询
  46. * @param int $limit 每页数量,用于分页查询
  47. * @return array 返回包含用户列表数量和详细信息的数据结构
  48. */
  49. public function userList($merId, $uid, $page, $limit)
  50. {
  51. // 根据商家ID和用户ID查询符合条件的记录,并按照服务日志ID降序排列
  52. $query = $this->search(['mer_id' => $merId, 'uid' => $uid])->order('service_log_id DESC');
  53. // 统计查询结果的总数量
  54. $count = $query->count();
  55. // 分页查询用户详细信息,并加载关联数据(用户、服务信息),同时追加发送时间和日期字段
  56. $list = $query->page($page, $limit)->with(['user', 'service'])->select()->append(['send_time', 'send_date']);
  57. // 如果是第一页,则标记数据为已读,更新读取状态
  58. if ($page == 1) {
  59. $this->dao->userRead($merId, $uid);
  60. app()->make(StoreServiceUserRepository::class)->read($merId, $uid);
  61. }
  62. // 反转列表顺序,可能是为了满足特定的展示需求
  63. $list = array_reverse($this->getSendDataList($list)->toArray());
  64. // 返回查询结果的总数量和分页后的用户详细信息列表
  65. return compact('count', 'list');
  66. }
  67. /**
  68. * 获取服务商列表
  69. *
  70. * 本函数用于根据指定的条件获取服务商列表。它首先验证当前用户是否有权限访问指定的服务商,
  71. * 然后调用内部函数获取满足条件的服务商列表。
  72. *
  73. * @param int $merId 商家ID,用于指定要查询的服务商所属的商家。
  74. * @param int $toUid 接收方用户ID,表示列表是为这个用户展示的。
  75. * @param int $uid 当前操作的用户ID,用于权限验证和查询条件。
  76. * @param int $page 当前页码,用于分页查询。
  77. * @param int $limit 每页记录数,用于分页查询。
  78. * @return array 返回符合查询条件的服务商列表。
  79. * @throws ValidateException 如果当前用户无权访问指定的服务商,则抛出异常。
  80. */
  81. public function merList($merId, $toUid, $uid, $page, $limit)
  82. {
  83. // 通过商家ID和用户ID获取服务商信息,并验证服务商是否存在且处于激活状态
  84. $service = app()->make(StoreServiceRepository::class)->getService($uid, $merId);
  85. if (!$service || !$service['status']) {
  86. throw new ValidateException('没有权限');
  87. }
  88. // 调用内部函数获取服务商列表,传入商家ID、服务商ID、接收方用户ID、当前页码和每页记录数
  89. return $this->serviceList($merId, $service->service_id, $toUid, $page, $limit);
  90. }
  91. /**
  92. * 获取服务列表
  93. *
  94. * 根据商家ID、服务ID、接收用户ID、页码和每页数量,查询服务记录。
  95. * 可选地,可以通过最后一个ID来获取新的服务记录,以实现分页和数据流的无限滚动。
  96. * 对于第一页的数据查询,会标记服务为已读,以更新用户和商家的服务状态。
  97. * 返回服务记录的总数和分页后的服务列表。
  98. *
  99. * @param string $merId 商家ID
  100. * @param int $service_id 服务ID
  101. * @param int $toUid 接收服务的用户ID
  102. * @param int $page 当前页码
  103. * @param int $limit 每页数量
  104. * @param string $last_id 上一次查询的最后一条ID,用于获取新数据
  105. * @return array 返回包含服务总数和列表的数据数组
  106. */
  107. public function serviceList($merId, $service_id, $toUid, $page, $limit, $last_id = '')
  108. {
  109. // 根据条件构造查询
  110. $query = $this->search(['mer_id' => $merId, 'uid' => $toUid, 'last_id' => $last_id])->order('service_log_id DESC');
  111. // 计算满足条件的服务总数
  112. $count = $query->count();
  113. // 执行分页查询,并加载关联数据(用户和服务信息)
  114. $list = $query->page($page, $limit)->with(['user', 'service'])->select()->append(['send_time', 'send_date']);
  115. // 如果是第一页,标记服务为已读
  116. if ($page == 1) {
  117. $this->dao->serviceRead($merId, $toUid, $service_id);
  118. app()->make(StoreServiceUserRepository::class)->read($merId, $toUid, true);
  119. }
  120. // 反转服务列表顺序,通常用于展示最新的服务在列表顶部
  121. $list = array_reverse($this->getSendDataList($list)->toArray());
  122. // 返回服务总数和列表的数组
  123. return compact('count', 'list');
  124. }
  125. /**
  126. * 根据不同的类型检查MSN的有效性。
  127. *
  128. * 该方法用于在不同的业务场景下,验证给定的MSN(可能代表商品ID、订单ID、退款单ID等)是否有效。
  129. * 通过传入的类型参数来决定检查的逻辑,如果MSN无效,则抛出ValidateException异常。
  130. *
  131. * @param string $merId 商家ID,用于限定查询的范围。
  132. * @param string $uid 用户ID,用于限定查询的范围。
  133. * @param int $type 类型标识,决定后续检查的逻辑和对应的业务实体。
  134. * @param string $msn 待检查的MSN,根据类型的不同,可能代表不同的ID。
  135. * @throws ValidateException 如果MSN无效,则抛出该异常。
  136. */
  137. public function checkMsn($merId, $uid, $type, $msn)
  138. {
  139. // 检查类型为4时,对应的商品是否存在
  140. if ($type == 4 && !app()->make(ProductRepository::class)->merExists($merId, $msn))
  141. throw new ValidateException('商品不存在');
  142. // 检查类型为5时,对应的订单是否存在
  143. else if ($type == 5 && !app()->make(StoreOrderRepository::class)->existsWhere(['uid' => $uid, 'mer_id' => $merId, 'order_id' => $msn]))
  144. throw new ValidateException('订单不存在');
  145. // 检查类型为6时,对应的退款单是否存在
  146. else if ($type == 6 && !app()->make(StoreRefundOrderRepository::class)->existsWhere(['uid' => $uid, 'mer_id' => $merId, 'refund_order_id' => $msn]))
  147. throw new ValidateException('退款单不存在');
  148. // 检查类型为7时,对应的预售商品是否存在
  149. else if ($type == 7 && !app()->make(ProductPresellRepository::class)->existsWhere(['product_presell_id' => $msn, 'mer_id' => $merId]))
  150. throw new ValidateException('商品不存在');
  151. // 检查类型为8时,对应的拼团商品是否存在
  152. else if ($type == 8 && !app()->make(ProductGroupRepository::class)->existsWhere(['product_group_id' => $msn, 'mer_id' => $merId]))
  153. throw new ValidateException('商品不存在');
  154. }
  155. /**
  156. * 根据日志的类型获取相应的发送数据。
  157. *
  158. * 本函数旨在根据服务日志中记录的不同类型(msn_type),提取出相应的数据。
  159. * msn_type 的不同值对应着不同的数据对象,包括产品、订单、退款订单、预售和产品组等信息。
  160. * 通过判断日志的类型,直接返回对应类型的数据对象,便于后续处理和使用。
  161. *
  162. * @param StoreServiceLog $log 服务日志对象,包含各种类型的数据信息。
  163. * @return StoreServiceLog 返回经过筛选后的服务日志对象,数据对象根据日志类型有所不同。
  164. */
  165. public function getSendData(StoreServiceLog $log)
  166. {
  167. // 根据日志的类型,提取相应的数据对象
  168. if ($log->msn_type == 4) {
  169. $log->product;
  170. } else if ($log->msn_type == 5) {
  171. $log->orderInfo;
  172. } else if ($log->msn_type == 6) {
  173. $log->refundOrder;
  174. } else if ($log->msn_type == 7) {
  175. $log->presell;
  176. } else if ($log->msn_type == 8) {
  177. $log->productGroup;
  178. }
  179. return $log;
  180. }
  181. /**
  182. * 根据日志列表中的MSN类型和号码,将相关数据存储在缓存中,以减少重复数据的存储。
  183. * 对于特定类型的日志,将其相关数据设置到日志对象中。
  184. *
  185. * @param array $list 日志对象的列表。
  186. * @return array 处理后的日志对象列表。
  187. */
  188. public function getSendDataList($list)
  189. {
  190. // 初始化缓存数组,用于存储按MSN类型和号码组合的唯一数据。
  191. $cache = [];
  192. foreach ($list as $log) {
  193. // 忽略非指定类型的日志,以减少后续处理的负担。
  194. if (!in_array($log->msn_type, [4, 5, 6, 7, 8])) continue;
  195. // 创建键,用于根据MSN类型和号码查找缓存数据。
  196. $key = $log->msn_type . $log->msn;
  197. // 如果缓存中已存在该键的数据,则直接从缓存中获取数据并设置到日志对象中。
  198. if (isset($cache[$key])) {
  199. if ($log->msn_type == 4)
  200. $log->set('product', $cache[$key]);
  201. else if ($log->msn_type == 5)
  202. $log->set('orderInfo', $cache[$key]);
  203. else if ($log->msn_type == 6)
  204. $log->set('refundOrder', $cache[$key]);
  205. else if ($log->msn_type == 8)
  206. $log->set('productGroup', $cache[$key]);
  207. else
  208. $log->set('presell', $cache[$key]);
  209. } else {
  210. // 如果缓存中不存在该键的数据,则从日志对象中获取数据并存储到缓存中。
  211. if ($log->msn_type == 4)
  212. $cache[$key] = $log->product;
  213. else if ($log->msn_type == 5)
  214. $cache[$key] = $log->orderInfo;
  215. else if ($log->msn_type == 6)
  216. $cache[$key] = $log->refundOrder;
  217. else if ($log->msn_type == 8)
  218. $cache[$key] = $log->productGroup;
  219. else
  220. $cache[$key] = $log->presell;
  221. }
  222. }
  223. return $list;
  224. }
  225. /**
  226. * 根据用户ID和是否为服务聊天获取聊天记录
  227. *
  228. * 本函数用于从缓存中获取指定用户的聊天记录。它可以根据用户是否是服务聊天来选择不同的缓存键,
  229. * 这样可以区分普通用户聊天记录和服务聊天记录,避免混淆。
  230. *
  231. * @param int $uid 用户ID,用于指定要获取聊天记录的用户。
  232. * @param bool $isService 指示是否为服务聊天,用于区分普通聊天和服务聊天。
  233. * @return mixed 返回从缓存中获取的聊天记录,如果不存在则返回null。
  234. */
  235. public function getChat($uid, $isService = false)
  236. {
  237. // 根据$isService的值决定缓存键的前缀,如果是服务聊天则为's_chat',否则为'u_chat'。
  238. // 然后拼接上$uid作为完整的缓存键。
  239. $key = ($isService ? 's_chat' : 'u_chat') . $uid;
  240. // 使用Cache类的get方法尝试获取缓存中存储的聊天记录。
  241. return Cache::get($key);
  242. }
  243. /**
  244. * 获取某个客服的用户列表
  245. * @param $service_id
  246. * @param $page
  247. * @param $limit
  248. * @return array
  249. * @author Qinii
  250. * @day 2020-06-18
  251. */
  252. public function getServiceUserList($service_id, $page, $limit)
  253. {
  254. $query = $this->dao->getUserListQuery($service_id)->with(['user'])->group('uid');
  255. $count = $query->count();
  256. $list = $query->setOption('field', [])->field('uid,mer_id,create_time,type')
  257. ->page($page, $limit)
  258. ->select();
  259. return compact('count', 'list');
  260. }
  261. /**
  262. * 获取商户的聊天用户列表
  263. * @param $merId
  264. * @param $page
  265. * @param $limit
  266. * @return array
  267. * @author Qinii
  268. * @day 2020-06-19
  269. */
  270. public function getMerchantUserList($merId, $page, $limit)
  271. {
  272. $query = $this->dao->getMerchantUserList($merId)->with(['user'])->group('uid');
  273. $count = $query->count();
  274. $list = $query->setOption('field', [])->field('uid,mer_id,create_time,type')->page($page, $limit)->select();
  275. return compact('count', 'list');
  276. }
  277. /**
  278. * 根据用户ID和条件获取用户的MSN信息
  279. *
  280. * 本函数用于查询指定用户ID的MSN相关信息。支持根据商家ID和服務ID进行过滤查询,
  281. * 提供分页功能,以满足前端或业务需求的分批获取数据。
  282. *
  283. * @param int $uid 用户ID,用于指定查询哪个用户的MSN信息。
  284. * @param string $page 分页参数,指定当前页码。
  285. * @param string $limit 分页参数,指定每页显示的记录数。
  286. * @param int|null $merId 商家ID,可选参数,用于过滤属于特定商家的MSN信息。
  287. * @param int|null $serviceId 服务ID,可选参数,用于过滤属于特定服务的MSN信息。
  288. * @return array 返回包含记录总数和用户MSN信息列表的数组。
  289. */
  290. public function getUserMsn(int $uid, $page, $limit, ?int $merId = null, ?int $serviceId = null)
  291. {
  292. // 初始化查询条件
  293. $where['uid'] = $uid;
  294. // 如果提供了商家ID,则添加到查询条件中
  295. if ($merId) $where['mer_id'] = $merId;
  296. // 如果提供了服务ID,则添加到查询条件中
  297. if ($serviceId) $where['service_id'] = $serviceId;
  298. // 构建查询对象,并设置排序方式
  299. $query = $this->search($where)->order('service_log_id DESC');
  300. // 计算符合条件的记录总数
  301. $count = $query->count();
  302. // 执行分页查询,并加载关联数据(用户、服务信息)以及附加MSN信息
  303. $list = $query->page($page, $limit)->with(['user', 'service'])->append(['msn_info'])->select();
  304. // 返回记录总数和查询结果列表
  305. return compact('count', 'list');
  306. }
  307. }