Activity.php 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753
  1. <?php
  2. /**
  3. * 活动
  4. */
  5. namespace app\weixin\service;
  6. use app\weixin\model\Activity as ActivityModel;
  7. use app\weixin\model\Books;
  8. use app\weixin\model\HeartMatch;
  9. use app\weixin\model\Member;
  10. use app\weixin\model\UserLog;
  11. use app\weixin\model\Wechat;
  12. use think\Db;
  13. class Activity
  14. {
  15. /**
  16. * 获取活动列表
  17. * @param $params 参数
  18. * @param int $pageSize 分页大小
  19. * @param string $field 字段
  20. * @param string $order 排序
  21. * @return mixed
  22. */
  23. public static function getList($params, $pageSize = 15, $field = '', $order = '')
  24. {
  25. $where = ['status' => 1, 'is_test'=> 0];
  26. /*$type = isset($params['type']) ? intval($params['type']) : 0;
  27. if ($type) {
  28. $where['type'] = $type;
  29. }*/
  30. $closeConfig = cmf_get_option('close_config');
  31. $closeConfig = $closeConfig? $closeConfig : config('weixin.site');
  32. $accessIp = isset($closeConfig['access_ip'])? $closeConfig['access_ip'] : '';
  33. $accessIp = $accessIp? explode(',', $accessIp) : [];
  34. if($accessIp && !in_array(get_client_ip(),$accessIp)){
  35. unset($where['is_test']);
  36. }
  37. $order = $order ? $order : 'is_top desc,is_sort desc,starttime desc,id desc';
  38. $field = $field ? $field : 'id,title,cover_img as thumb,price,act_nums,addtime,starttime,address,endtime';
  39. return ActivityModel::where($where)
  40. ->where('addtime','<=',time())
  41. ->field($field)
  42. ->order($order)
  43. ->paginate($pageSize)
  44. ->each(function ($item, $k) {
  45. $startTime = isset($item['starttime']) ? $item['starttime'] : 0;
  46. $endTime = isset($item['endtime']) ? $item['endtime'] : 0;
  47. $addTime = isset($item['addtime']) ? $item['addtime'] : 0;
  48. if ($startTime <= time() && $endTime >= time()) {
  49. $item['act_status'] = 1; // 进行中
  50. } else if ($endTime < time()) {
  51. $item['act_status'] = 2; // 已结束
  52. } else if ($startTime > time()) {
  53. $item['act_status'] = 0; // 未开始
  54. }
  55. $item['join_at'] = '';
  56. if(date('Y-m-d',$endTime) == date('Y-m-d', $startTime)){
  57. $item['join_at'] = date('Y.m.d H:i',$startTime).'~'.date('H:i', $endTime);
  58. }
  59. $item['thumb'] = isset($item['thumb']) ? cmf_get_image_preview_url($item['thumb']) : '';
  60. $item['publish_at'] = $addTime ? date('Y-m-d H:i:s', $addTime) : date('Y-m-d H:i:s');
  61. $item['start_at'] = $startTime ? date('Y.m.d H:i', $startTime) : date('Y.m.d H:i');
  62. $item['end_at'] = $endTime ? date('Y.m.d H:i', $endTime) : date('Y.m.d H:i');
  63. // 报名人列表和人数
  64. $showNum = config('activity.showNum');
  65. $showNum = $showNum ? $showNum : 6;
  66. $id = isset($item['id']) ? $item['id'] : 0;
  67. $result = Books::getBookList($id, $showNum);
  68. $item['book_num'] = isset($result['total']) ? intval($result['total']) : 0;
  69. $item['book_list'] = isset($result['data']) ? $result['data'] : [];
  70. return $item;
  71. });
  72. }
  73. /**
  74. * 获取用户活动
  75. * @param $params 参数
  76. * @param int $pageSize 分页大小
  77. * @param string $field 字段
  78. * @param string $order 排序
  79. * @return $this
  80. * @throws \think\exception\DbException
  81. */
  82. public static function getMemberActivityList($params, $pageSize = 15, $field = '', $order = '')
  83. {
  84. $order = $order ? $order : 'a.starttime desc,a.id desc';
  85. $userId = isset($params['user_id']) ? intval($params['user_id']) : 0;
  86. $type = isset($params['type']) ? intval($params['type']) : 0;
  87. $order = $type == 1 ? $order : 'b.book_at desc,b.id desc';
  88. $where = ['a.status' => 1,'b.status'=> 3,'b.uid'=> $userId];
  89. $field = $field ? $field : 'a.id,a.title,a.cover_img as thumb,b.status,b.is_signin,a.price,a.act_nums,a.addtime,a.starttime,a.address,a.endtime,b.id as book_id';
  90. $dataList = ActivityModel::alias('a')
  91. ->join('books b', 'a.id=b.aid', 'inner')
  92. ->where('addtime','<=',time())
  93. ->where($where)
  94. ->where(function($query) use($type){
  95. if ($type == 2) {
  96. return $query->where('b.is_signin','=', 1);
  97. } else if ($type == 3) {
  98. return $query->where('b.is_signin','in', [2,3]);
  99. }
  100. })
  101. ->field($field)
  102. ->order($order)
  103. ->group('a.id')
  104. ->paginate($pageSize)
  105. ->each(function ($item, $k) {
  106. $startTime = isset($item['starttime']) ? $item['starttime'] : 0;
  107. $endTime = isset($item['endtime']) ? $item['endtime'] : 0;
  108. $addTime = isset($item['addtime']) ? $item['addtime'] : 0;
  109. if ($startTime <= time() && $endTime >= time()) {
  110. $item['act_status'] = 1; // 进行中
  111. } else if ($endTime < time()) {
  112. $item['act_status'] = 2; // 已结束
  113. } else if ($startTime > time()) {
  114. $item['act_status'] = 0; // 未开始
  115. }
  116. $item['join_at'] = '';
  117. if(date('Y-m-d',$endTime) == date('Y-m-d', $startTime)){
  118. $item['join_at'] = date('Y.m.d H:i',$startTime).'~'.date('H:i', $endTime);
  119. }
  120. $item['thumb'] = isset($item['thumb']) ? cmf_get_image_preview_url($item['thumb']) : '';
  121. $item['publish_at'] = $addTime ? date('Y-m-d H:i:s', $addTime) : date('Y-m-d H:i:s');
  122. $item['start_at'] = $startTime ? date('Y-m-d H:i', $startTime) : date('Y-m-d H:i');
  123. $item['end_at'] = $endTime ? date('Y-m-d H:i', $endTime) : date('Y-m-d H:i');
  124. // 报名人列表和人数
  125. $showNum = config('activity.showNum');
  126. $showNum = $showNum ? $showNum : 6;
  127. $id = isset($item['id']) ? $item['id'] : 0;
  128. $result = Books::getBookList($id, $showNum);
  129. $item['book_num'] = isset($result['total']) ? intval($result['total']) : 0;
  130. $item['book_list'] = isset($result['data']) ? $result['data'] : [];
  131. return $item;
  132. });
  133. return $dataList;
  134. }
  135. /**
  136. * 获取详情
  137. * @param $where
  138. * @param string $field
  139. * @return array|null|\PDOStatement|string|\think\Model
  140. */
  141. public static function getInfo($where, $field = '')
  142. {
  143. $field = $field ? $field : 'id,title,cover_img as thumb,price,market_price,market_time,member_discount,credit,act_nums,url,addtime,starttime,endtime,description,address';
  144. $info = ActivityModel::where($where)
  145. ->where('addtime','<=',time())
  146. ->where('id', '>', 0)
  147. ->field($field)
  148. ->find();
  149. if ($info) {
  150. $addTime = isset($info['addtime']) ? $info['addtime'] : 0;
  151. $startTime = isset($info['starttime']) ? $info['starttime'] : 0;
  152. $endTime = isset($info['endtime']) ? $info['endtime'] : 0;
  153. if ($startTime <= time() && $endTime >= time()) {
  154. $info['act_status'] = 1; // 进行中
  155. } else if ($endTime < time()) {
  156. $info['act_status'] = 2; // 已结束
  157. } else if ($startTime > time()) {
  158. $info['act_status'] = 0; // 未开始
  159. }
  160. $info['join_at'] = '';
  161. if(date('Y-m-d',$endTime) == date('Y-m-d', $startTime)){
  162. $info['join_at'] = date('Y.m.d H:i',$startTime).'~'.date('H:i', $endTime);
  163. }
  164. if($startTime==0 && $endTime == 0){
  165. $info['act_status'] = 1; // 进行中
  166. }
  167. $isHide = floor((time()-$endTime)/86400)>=3? 1 : 0;
  168. $info['publish_at'] = $addTime ? date('Y-m-d H:i:s', $addTime) : date('Y-m-d H:i:s');
  169. $info['publish_format_at'] = getFormatTime($info['publish_at']);
  170. $info['start_at'] = $startTime ? date('Y.m.d H:i', $startTime) : date('Y.m.d H:i');
  171. $info['end_at'] = $endTime ? date('Y.m.d H:i', $endTime) : date('Y.m.d H:i');
  172. $info['thumb'] = isset($info['thumb']) ? cmf_get_image_preview_url($info['thumb']) : '';
  173. $info['is_hide'] = $isHide;
  174. if (isset($info['content'])) {
  175. $info['content'] = htmlspecialchars_decode($info['content']);
  176. }
  177. }
  178. return $info;
  179. }
  180. /**
  181. * 报名
  182. * @param $userId
  183. * @param $aid
  184. * @return array|int
  185. */
  186. public static function catchBook($userId, $aid)
  187. {
  188. // 验证活动是否存在
  189. $field = 'id,starttime,endtime,price,market_price,market_time,member_discount,addtime,is_top,credit,act_nums';
  190. $activityInfo = Activity::getInfo(['id' => $aid, 'status' => 1], $field);
  191. if (empty($activityInfo)) {
  192. return 5001;
  193. }
  194. // 验证报名时间
  195. $startTime = isset($activityInfo['starttime']) ? intval($activityInfo['starttime']) : 0;
  196. $endTime = isset($activityInfo['endtime']) ? intval($activityInfo['endtime']) : 0;
  197. $addTime = isset($activityInfo['addtime']) ? intval($activityInfo['addtime']) : 0;
  198. $isTop = isset($activityInfo['is_top']) ? intval($activityInfo['is_top']) : 0;
  199. if($addTime > time()){
  200. return 5000;
  201. }
  202. if ($endTime && time() > $endTime) {
  203. return 5002;
  204. }
  205. /*if ($startTime && time() < $startTime) {
  206. return 5003;
  207. }*/
  208. // 活动截止前多久不允许报名
  209. $siteInfo = cmf_get_site_info();
  210. $bookTime = isset($siteInfo['book_time']) ? intval($siteInfo['book_time']) : 0;
  211. if ($isTop==0 && $startTime && $bookTime) {
  212. if(time() > $startTime){
  213. return 5026;
  214. }
  215. if(time() + $bookTime*3600 > $startTime){
  216. return lang('book_end', ['time' => $bookTime]);
  217. }
  218. }
  219. // 验证当前用户是否已经报名
  220. if (Books::checkUserBook($userId, $aid)) {
  221. return 5004;
  222. }
  223. // 验证操作频繁
  224. $lockCache = "books:lock:" . $userId . "_" . $aid;
  225. if (PRedis::get($lockCache)) {
  226. return 1013;
  227. }
  228. // 验证报名人数
  229. $sex = Member::where(['id' => $userId])->value('sex');
  230. $limitNum = isset($activityInfo['act_nums']) ? intval($activityInfo['act_nums']) : 0;
  231. $limitNum = floor($limitNum/2);
  232. $bookNum = Books::getBookCount($aid, $sex, [2,3]); // 已报名人数
  233. if ($limitNum && $bookNum >= $limitNum) {
  234. $sexText = $isTop? '' : ($sex==1? '男生' : '女生');
  235. return lang('book_limit',['sex'=> $sexText]);
  236. }
  237. // 验证价格
  238. $price = isset($activityInfo['price']) ? floatval($activityInfo['price']) : 0; // 活动价格
  239. $marketPrice = isset($activityInfo['market_price']) ? floatval($activityInfo['market_price']) : 0; // 早市价
  240. $marketTime = isset($activityInfo['market_time']) ? intval($activityInfo['market_time']) : 0;
  241. $payPrice = $marketTime >= time() && $marketPrice>0? $marketPrice : $price;
  242. $credit = isset($activityInfo['credit']) ? floatval($activityInfo['credit']) : 0;
  243. if (empty($payPrice)) {
  244. return 1012;
  245. }
  246. // 验证VIP折扣价
  247. $memberInfo = Member::where(['id' => $userId])->field('vip_auth,vip_expire')->find();
  248. $vipAuth = isset($memberInfo['vip_auth']) ? intval($memberInfo['vip_auth']) : 0;
  249. $vipExpire = isset($memberInfo['vip_expire']) ? intval($memberInfo['vip_expire']) : 0;
  250. // VIP有效期内
  251. $oldPrice = $payPrice;
  252. $memberDiscount = isset($activityInfo['member_discount']) ? floatval($activityInfo['member_discount']) : 0;
  253. if($vipAuth && $vipExpire > time() && $memberDiscount && $memberDiscount < 1){
  254. $payPrice = floatval($memberDiscount * $payPrice);
  255. }
  256. // 报名数据
  257. $orderSn = makeTradeNo('BK', $userId);
  258. $bookData = [
  259. 'book_num' => '',
  260. 'uid' => $userId,
  261. 'aid' => $aid,
  262. 'order_sn' => $orderSn,
  263. 'money' => $payPrice,
  264. 'credit' => $credit,
  265. 'created_at' => date('Y-m-d H:i:s'),
  266. 'remark' => "活动报名:原价{$oldPrice},折扣{$memberDiscount}折",
  267. 'status' => 1,
  268. ];
  269. // 写入记录
  270. Db::startTrans();
  271. $logData = ['info' => $activityInfo, 'bookData' => $bookData, 'date' => date('Y-m-d H:i:s')];
  272. PRedis::set($lockCache, $logData, 3);
  273. PRedis::set('books:logs:' . $userId . '_' . $aid, $logData, 600);
  274. if (!$bookId = Books::insertGetId($bookData)) {
  275. PRedis::del($lockCache);
  276. Db::rollback();
  277. return 5006;
  278. }
  279. // 用户操作记录
  280. UserLog::saveLog(['user_id' => $userId, 'type' => 4, 'content' => '报名下单:' . $orderSn]);
  281. Db::commit();
  282. PRedis::del($lockCache);
  283. return ['id' => $bookId];
  284. }
  285. /**
  286. * 报名审核
  287. * @param $bookId 报名记录ID
  288. * @param $checkStatus 审核状态:3-审核成功,5-审核失败退款
  289. * @param $failRemark 审核失败原因
  290. * @return int
  291. */
  292. public static function bookConfirm($bookId, $checkStatus, $failRemark='')
  293. {
  294. try {
  295. $bookInfo = Books::getInfo(['id' => $bookId]);
  296. $status = isset($bookInfo['status']) ? intval($bookInfo['status']) : 0;
  297. $userId = isset($bookInfo['uid']) ? intval($bookInfo['uid']) : 0;
  298. $aid = isset($bookInfo['aid']) ? intval($bookInfo['aid']) : 0;
  299. if (empty($userId) || empty($aid)) {
  300. return 1012;
  301. }
  302. if ($status != 2) {
  303. return 5016;
  304. }
  305. if(!in_array($checkStatus, [3,5])){
  306. return 2129;
  307. }
  308. // 审核数据更新
  309. $bookNo = '';
  310. $updateData = ['status' => $checkStatus, 'remark' => $checkStatus==3? '审核成功':'审核失败'];
  311. if($checkStatus == 3){
  312. $sex = Member::where(['id' => $userId])->value('sex');
  313. $prefix = $sex == 1 ? 'G' : ($sex == 2 ? 'M' : '');
  314. $bookNo = Books::makeBookNo($aid, $prefix, $sex);
  315. $updateData['book_num'] = $bookNo;
  316. $updateData['book_num_val'] = str_replace(['M','G'],'', $bookNo);
  317. }
  318. $res = Books::saveData(['id' => $bookId], $updateData);
  319. if ($res) {
  320. // 更新加入单身推荐
  321. if($aid == 15 && $checkStatus == 3){
  322. Member::saveData(['id'=> $userId],['is_tuijian'=> 1,'tuijian_time'=> date('Y-m-d H:i:s')]);
  323. }
  324. $memberInfo = Member::getInfo(['id' => $userId]);
  325. $openid = isset($memberInfo['openid']) ? $memberInfo['openid'] : '';
  326. $nickname = isset($memberInfo['user_nickname']) ? $memberInfo['user_nickname'] : '';
  327. // 发送消息
  328. if ($openid) {
  329. $activityInfo = ActivityModel::where(['id' => $aid])
  330. ->field('id,starttime,title,join_address')
  331. ->find();
  332. $title = isset($activityInfo['title']) ? trim($activityInfo['title']) : '无';
  333. $address = isset($activityInfo['join_address']) ? trim($activityInfo['join_address']) : '无';
  334. $startTime = isset($activityInfo['starttime']) ? intval($activityInfo['starttime']) : 0;
  335. $startTime = $startTime ? date('Y.m.d H:i', $startTime) : '详情查看';
  336. $startTime = $aid==15? date('Y.m.d H:i') : $startTime;
  337. $orderSn = isset($bookInfo['order_sn']) ? trim($bookInfo['order_sn']) : '';
  338. $money = isset($bookInfo['money']) ? floatval($bookInfo['money']) : 0;
  339. $credit = isset($bookInfo['credit']) ? floatval($bookInfo['credit']) : 0;
  340. if($checkStatus==3){
  341. $url = $aid==15? url('/weixin/activity/book?id=' . $aid, '', '', true) : url('/weixin/activity/bookdetail?id=' . $aid, '', '', true);
  342. $params = [
  343. 'title' => "恭喜!您报名的活动已经通过审核!请提前安排好时间,准时参加!风雨无阻,真诚第一\n\n姓名:\t{$nickname}(昵称)\n\n支付金额:\t{$money}\n\n报名编号:\t{$bookNo}\n\n当前进度:\t待参加",
  344. 'remark' => "亲,记得安排好时间哦!",
  345. 'type' => 'book_confirm',
  346. 'keywords' => [
  347. 'keyword1' => [
  348. 'value' => $title,
  349. 'color' => '#173177',
  350. ],
  351. 'keyword2' => [
  352. 'value' => $startTime,
  353. 'color' => '#173177',
  354. ],
  355. 'keyword3' => [
  356. 'value' => $address,
  357. 'color' => '#173177',
  358. ],
  359. /* 'keyword4' => [
  360. 'value' => "其中支付守时金{$credit}元,请准时签到,否则不予退还",
  361. 'color' => '#173177',
  362. ],*/
  363. ],
  364. 'url' => $url,
  365. ];
  366. }else{
  367. $params = [
  368. 'title' => ($failRemark? $failRemark : '报名审核失败')."\n\n姓名:\t{$nickname}(昵称)\n\n支付金额:\t{$money}",
  369. 'remark' => "转发积姻缘,把活动分享给身边的朋友,一起来脱单哦!",
  370. 'type' => 'book',
  371. 'keywords' => [
  372. 'keyword1' => [
  373. 'value' => $title,
  374. 'color' => '#173177',
  375. ],
  376. 'keyword2' => [
  377. 'value' => $startTime,
  378. 'color' => '#173177',
  379. ],
  380. 'keyword3' => [
  381. 'value' => '审核失败',
  382. 'color' => '#173177',
  383. ],
  384. 'keyword4' => [
  385. 'value' => "...",
  386. 'color' => '#173177',
  387. ],
  388. ],
  389. 'url' => url('/weixin/activity/book?id=' . $aid, '', '', true),
  390. ];
  391. }
  392. PRedis::set('payments:books:confirmMessage_' . $orderSn, ['book' => $bookInfo, 'params' => $params], 600);
  393. Wechat::sendTplMsg($openid, $params);
  394. }
  395. return ['id' => $bookId];
  396. } else {
  397. return 5015;
  398. }
  399. } catch (\Exception $exception){
  400. return 1015;
  401. }
  402. }
  403. /**
  404. * 互选匹配
  405. * @param $aid 活动ID
  406. * @return int
  407. */
  408. public static function heartMatch($aid)
  409. {
  410. try {
  411. // 验证活动是否有效
  412. $activityInfo = ActivityModel::where(['id' => $aid, 'status' => 1])
  413. ->field('id,starttime,title,address,status,is_match')
  414. ->find();
  415. if (empty($activityInfo)) {
  416. return 5001;
  417. }
  418. // 验证状态和匹配状态
  419. $isMatch = isset($activityInfo['is_match']) ? intval($activityInfo['is_match']) : 0;
  420. if ($isMatch == 1) {
  421. return 6002;
  422. }
  423. // 活动开始时间
  424. $startTime = isset($activityInfo['starttime']) ? intval($activityInfo['starttime']) : 0;
  425. if (time() < $startTime) {
  426. return 5003;
  427. }
  428. // 互选模式匹配
  429. $siteInfo = $siteInfo = cmf_get_site_info();
  430. $contactType = isset($siteInfo['contact_type']) ? $siteInfo['contact_type'] : 1;
  431. if($contactType == 3){
  432. // 更新匹配状态
  433. ActivityModel::where(['id'=> $aid])->update(['is_match'=> 1]);
  434. // 获取用户列表
  435. // 处理互选
  436. return ['result'=> $aid];
  437. }
  438. // 获取匹配互选列表
  439. $matchList = Books::getMatchUserList($aid);
  440. if (empty($matchList)) {
  441. return 6003;
  442. }
  443. // 更新匹配状态
  444. ActivityModel::where(['id'=> $aid])->update(['is_match'=> 1]);
  445. // 用户匹配列表处理
  446. $results = [];
  447. PRedis::set('matchs:activity_' . $aid.':users', $matchList, 600);
  448. foreach ($matchList as $k => $userData) {
  449. $userId = isset($userData['uid']) ? intval($userData['uid']) : 0;
  450. $heartUids = isset($userData['heart_uids'])? $userData['heart_uids'] : '';
  451. $heartUids = $heartUids? explode(',', $heartUids) : [];
  452. if(empty($heartUids)){
  453. continue;
  454. }
  455. foreach ($heartUids as $kk => $uid) {
  456. $matchData = isset($matchList[$uid]) ? $matchList[$uid] : [];
  457. $uids = isset($matchData['heart_uids']) ? $matchData['heart_uids'] : '';
  458. $uids = $uids? explode(',', $uids) : [];
  459. $index = array_search($userId, $uids);
  460. if ($index !== false && $index >= 0) {
  461. $dvalue = abs($kk - $index)+1;
  462. if(($kk + 1)>= ($index + 1)){
  463. $key = ($kk + 1) . '_' . $dvalue . '_' . ($index + 1);
  464. }else{
  465. $key = ($index + 1) . '_' . $dvalue . '_' . ($kk + 1);
  466. }
  467. $results[$key] = isset($results[$key]) ? $results[$key] : [];
  468. $results[$key][] = [$userData, $matchData];
  469. }
  470. }
  471. }
  472. ksort($results, 1);
  473. $successArr = $successId = [];
  474. foreach ($results as $result) {
  475. foreach ($result as $val) {
  476. // 匹配用户数据
  477. $userData = isset($val[0]) ? $val[0] : 0;
  478. $matchData = isset($val[1]) ? $val[1] : 0;
  479. $mid = isset($userData['id'])? intval($userData['id']) : 0;
  480. $userId = isset($userData['uid'])? intval($userData['uid']) : 0;
  481. $matchId = isset($matchData['id']) ? intval($matchData['id']) : 0;
  482. $matchUid = isset($matchData['uid']) ? intval($matchData['uid']) : 0;
  483. // 验证用户是否已经被匹配,若是则不需要再次匹配
  484. if (!$userId || !$matchUid || PRedis::get('matchs:activity_' . $aid . ':lock:u_' . $userId) || PRedis::get('matchs:activity_' . $aid . ':lock:u_' . $matchUid)) {
  485. PRedis::set('matchs:activity_' . $aid . ':error:u_' . $userId.'_'.$matchUid, ['data' => $userData, 'match'=> $matchData, 'error' => '当前匹配用户已被匹配过'], 600);
  486. continue;
  487. }
  488. // 更新匹配数据
  489. Db::startTrans();
  490. $matchAt = time();
  491. $updateData = [
  492. 'match_uid' => $matchUid,
  493. 'match_at' => date('Y-m-d H:i:s', $matchAt),
  494. 'status' => 2,
  495. ];
  496. PRedis::set('matchs:activity_' . $aid . ':update:u_' . $userId, ['data' => $updateData, 'match' => $matchData], 600);
  497. if (!HeartMatch::where(['id' => $mid])->update($updateData)) {
  498. Db::rollback();
  499. continue;
  500. }
  501. $updateData = [
  502. 'match_uid' => $userId,
  503. 'match_at' => date('Y-m-d H:i:s', $matchAt),
  504. 'status' => 2,
  505. ];
  506. PRedis::set('matchs:activity_' . $aid . ':update:u_' . $matchUid, ['data' => $updateData, 'match' => $userData], 600);
  507. if (!HeartMatch::where(['id' => $matchId])->update($updateData)) {
  508. Db::rollback();
  509. continue;
  510. }
  511. // 提交
  512. Db::commit();
  513. $successArr[] = $userId.' 匹配 '.$matchUid;
  514. //echo $userId.' 匹配 '.$matchUid."\n";
  515. $successId[] = $userId;
  516. $successId[] = $matchUid;
  517. // 匹配加锁
  518. PRedis::set('matchs:activity_' . $aid . ':lock:u_' . $userId, $matchData, 24 * 3600);
  519. PRedis::set('matchs:activity_' . $aid . ':lock:u_' . $matchUid, $userData, 24 * 3600);
  520. // 推送匹配成功消息
  521. $openid = isset($userData['openid']) ? trim($userData['openid']) : '';
  522. if ($openid) {
  523. $bookNo = isset($userData['book_no']) ? trim($userData['book_no']) : '无';
  524. $matchName = isset($matchData['user_nickname']) ? $matchData['user_nickname'] : '';
  525. $matchNo = isset($matchData['book_no']) ? trim($matchData['book_no']) : '无';
  526. $matchWechatCode = isset($matchData['wechat_code']) ? trim($matchData['wechat_code']) : '无';
  527. $matchSex = isset($matchData['sex']) ? intval($matchData['sex']) : 0;
  528. $matchSex = $matchSex == 1 ? '男' : '女';
  529. $title = isset($activityInfo['title']) ? trim($activityInfo['title']) : '无';
  530. $matchTime = $matchAt ? date('Y.m.d H:i', $matchAt) : date('Y.m.d H:i');
  531. $params = [
  532. 'title' => "恭喜!活动缘分互选匹配成功,已为您匹配到缘分用户!\n\n活动主题:\t{$title}\n\n您的编号:\t{$bookNo}\n\n对方编号:\t{$matchNo}\n\n匹配时间:\t{$matchTime}\n\n对方微信号:\t{$matchWechatCode}",
  533. 'remark' => "感谢您的使用,点击详情查看互选信息",
  534. 'type' => 'match',
  535. 'keywords' => [
  536. 'name' => [
  537. 'value' => $matchName.'(昵称)',
  538. 'color' => '#173177',
  539. ],
  540. 'sex' => [
  541. 'value' => $matchSex,
  542. 'color' => '#173177',
  543. ],
  544. 'tel' => [
  545. 'value' => '隐私信息不显示',
  546. 'color' => '#173177',
  547. ],
  548. ],
  549. 'url' => url('/weixin/activity/match?id=' . $aid . '&type=2', '', '', true),
  550. ];
  551. PRedis::set('matchs:activity_' . $aid . ':message:' . $userId, ['result' => $matchData, 'params' => $params], 600);
  552. Wechat::sendTplMsg($openid, $params);
  553. }
  554. // 通知被匹配的用户
  555. $matchOpenId = isset($matchData['openid'])? trim($matchData['openid']) : '';
  556. if ($matchOpenId) {
  557. $bookNo = isset($matchData['book_no']) ? trim($matchData['book_no']) : '无';
  558. $matchName = isset($userData['real_name']) ? $userData['real_name'] : '';
  559. $matchNo = isset($userData['book_no']) ? trim($userData['book_no']) : '无';
  560. $matchWechatCode = isset($userData['wechat_code']) ? trim($userData['wechat_code']) : '无';
  561. $matchSex = isset($userData['sex']) ? intval($userData['sex']) : 0;
  562. $matchSex = $matchSex == 1 ? '男' : '女';
  563. $title = isset($activityInfo['title']) ? trim($activityInfo['title']) : '无';
  564. $matchTime = $matchAt ? date('Y.m.d H:i', $matchAt) : date('Y.m.d H:i', time());
  565. $params = [
  566. 'title' => "活动缘分互选匹配成功,已为您匹配到缘分用户!\n\n活动主题:\t{$title}\n\n您的编号:\t{$bookNo}\n\n对方编号:\t{$matchNo}\n\n匹配时间:\t{$matchTime}\n\n对方微信号:\t{$matchWechatCode}",
  567. 'remark' => "感谢您的使用,点击详情查看报名活动信息",
  568. 'type' => 'match',
  569. 'keywords' => [
  570. 'name' => [
  571. 'value' => $matchName.'(昵称)',
  572. 'color' => '#173177',
  573. ],
  574. 'sex' => [
  575. 'value' => $matchSex,
  576. 'color' => '#173177',
  577. ],
  578. 'tel' => [
  579. 'value' => '隐私信息不展示',
  580. 'color' => '#173177',
  581. ],
  582. ],
  583. 'url' => url('/weixin/activity/match?id=' . $aid . '&type=2', '', '', true),
  584. ];
  585. PRedis::set('matchs:activity_' . $aid . ':message:' . $matchUid, ['result' => $userData, 'params' => $params], 600);
  586. Wechat::sendTplMsg($matchOpenId, $params);
  587. }
  588. }
  589. }
  590. // 更新匹配错误或失败用户数据
  591. PRedis::set('matchs:activity_'.$aid.':result', ['list'=> $matchList, 'results'=> $results, 'success'=> $successArr,'successId'=> $successId,'sorts'=> array_keys($results)], 600);
  592. if ($successId) {
  593. $updateData = ['updated_at' => date('Y-m-d H:i:s'), 'status' => 3];
  594. HeartMatch::where(['aid'=> $aid])->where('uid', 'not in', $successId)->update($updateData);
  595. }
  596. //var_dump($successArr);
  597. return $successArr ? $successArr : 6004;
  598. } catch (\Exception $exception){
  599. return 1015;
  600. }
  601. }
  602. /**
  603. * 推送活动消息
  604. * @param $aid
  605. * @param int $type 类型:默认1活动即将开始,2-活动开始前一天提醒
  606. * @return array|int
  607. */
  608. public static function sendMessage($aid, $type=1){
  609. try {
  610. $field = 'id,title,cover_img as thumb,price,credit,act_nums,addtime,starttime,endtime,description,address,alert_time1,alert_remark1,alert_time2,alert_remark2';
  611. $activityInfo = Activity::getInfo(['id'=> $aid], $field);
  612. if(empty($activityInfo)){
  613. return 5001;
  614. }
  615. // 验证3天之内是否已经发过
  616. if(PRedis::get('activity:pushStatus:'.$aid.'_'.$type)){
  617. return 2115;
  618. }
  619. // 准备开始
  620. $title = isset($activityInfo['title']) ? trim($activityInfo['title']) : '';
  621. $signTime = isset($activityInfo['alert_time'.$type]) ? trim($activityInfo['alert_time'.$type]) : '';
  622. $remark = isset($activityInfo['alert_remark'.$type]) ? trim($activityInfo['alert_remark'.$type]) : '无';
  623. if(empty($signTime)){
  624. return 5021;
  625. }
  626. // 报名的用户列表
  627. $bookList = Books::getPushUserList($aid);
  628. $title = $type == 2? "您报名了明天的“{$title}”记得安排好时间,风雨无阻,准时参加,真诚第一" : "亲,您报名的“{$title}”即将开始,赶快收拾妥当,准时参加!";
  629. $params = [
  630. 'title' => $title,
  631. 'type' => 'activity_start',
  632. 'keywords' => [
  633. 'keyword1' => [
  634. 'value' => '待参加活动',
  635. 'color' => '#173177',
  636. ],
  637. 'keyword2' => [
  638. 'value' => $signTime,
  639. 'color' => '#173177',
  640. ],
  641. 'keyword3' => [
  642. 'value' => $remark,
  643. 'color' => '#173177',
  644. ],
  645. ],
  646. 'url' => url('/weixin/activity/bookdetail?id=' . $aid, '', '', true),
  647. ];
  648. $count = 0;
  649. if(empty($bookList)){
  650. return 5022;
  651. }
  652. // var_dump($bookList);
  653. foreach($bookList as $userData){
  654. $userId = isset($userData['uid'])? intval($userData['uid']) : 0;
  655. $openid = isset($userData['openid'])? trim($userData['openid']) : '';
  656. if($openid){
  657. PRedis::set('activity:pushMessage:' . $aid . '_' . $userId, ['result' => $userData, 'params' => $params], 600);
  658. $result = Wechat::sendTplMsg($openid, $params);
  659. if(is_array($result)){
  660. $count++;
  661. }
  662. }
  663. }
  664. if($count){
  665. PRedis::set('activity:pushStatus:'.$aid.'_'.$type, ['info'=> $activityInfo,'pushList'=> $bookList], 5 * 24 * 3600);
  666. return ['id'=> $aid, 'count'=> $count];
  667. } else {
  668. return 2116;
  669. }
  670. } catch (\Exception $exception){
  671. return 1015;
  672. }
  673. }
  674. }