'bc', 'operate_type' => $operate_type, 'data_type' => 'cart', 'method' => 'sendToGroup', 'send_id' => self::$shop_id, 'send_num' => 0, 'status' => $data_arr['status'], 'msg_id' => 'broadcast' . Random::build(), 'data' => !empty($data_arr['data'])?$data_arr['data']:[] ]; $new_clientid_group = ''; if(!empty(self::$shop_id) && !empty($broadcast_arr['data']['table_code'])) { if($operate_type == 'init') { // 如果是转桌操作,发广播初始化购物车 转出桌和转入桌都需要发通知 $new_clientid_group = self::get_shopping_save_uid(self::$shop_id, $broadcast_arr['data']['new_table_code']); } $clientid_group = self::get_shopping_save_uid(self::$shop_id, $broadcast_arr['data']['table_code']); // 如果有在线的 再发 if($onl = Gateway::getClientIdCountByGroup($clientid_group)){ // 发送广播并将 self::$client_id 排除在外 // 排除收银机重复的client_id $table_arr = []; if(!empty(self::$table_code) && !empty($data_arr['type']) && $data_arr['type'] == 'shopping') { // 是客户端小程序才排除同桌子的 $table_arr = Gateway::getClientIdByUid(self::$table_code); } // 排除自己 $new_client_id = array_merge($table_arr, [self::$client_id]); // 去重 $new_client_id = array_unique($new_client_id); $broadcast_arr['no_client_id'] = $new_client_id; $broadcast_json = json_encode($broadcast_arr); Gateway::sendToGroup($clientid_group, $broadcast_json, $new_client_id); // 如果是转桌,新桌码和旧桌码都发广播 if($new_clientid_group) { Gateway::sendToGroup($new_clientid_group, $broadcast_json, $new_client_id); } } } } } if(!empty($data_arr['type']) && $data_arr['type'] == 'onboc') { print_r( "\r\n"); } return call_user_func_array([Gateway::class, $method], [$clientIdOrUid, $data]); } // 支付锁单操作 public static function paylock(string $client_id, array $params) { $msg_id = self::get_shopping_save_lockname($params['shop_id'], $params['table_code']); // 加入锁单分组 Gateway::joinGroup($client_id, $msg_id); $time = time(); $_SESSION[$msg_id] = $time; //找到锁单分组中其他的人 $all = Gateway::getClientSessionsByGroup($msg_id); foreach ($all as $g_client_id => $g_client_id_data ) { $session = Gateway::getSession($g_client_id); $session[$msg_id] = $time; Gateway::setSession($g_client_id, $session); $redis_name = $g_client_id . '_lock'; $result = Redis::get($redis_name); if($result) { }else { Redis::setEx($redis_name, 3600, $msg_id); } } print_r('锁单的key-----' . $msg_id . "\r\n"); // 直接保存锁定 $rand = 'pay_lock' . Random::build(); $snd_data = [ 'msg' => '支付锁单', 'operate_type' => 'pay_lock', 'status' => 1, 'msg_id' => $rand, 'type' => $params['type'], ]; Gateway::sendToClient($client_id, json_encode($snd_data)); } // 支付解锁操作 public static function payunlock(string $client_id, array $params) { $msg_id = self::get_shopping_save_lockname($params['shop_id'], $params['table_code']); // 自己先解锁 $_SESSION[$msg_id] = ''; // 找到他人并解锁 $all = Gateway::getClientSessionsByGroup($msg_id); foreach ($all as $g_client_id => $g_client_id_data ) { $session = Gateway::getSession($g_client_id); unset($session[$msg_id]); Gateway::setSession($g_client_id, $session); $redis_name = $g_client_id . '_lock'; $result = Redis::get($redis_name); if($result) { Redis::del($redis_name); } } print_r('解锁的key-----' . $msg_id . "\r\n"); $rand = 'pay_unlock' . Random::build(); $snd_data = [ 'msg' => '支付解锁', 'operate_type' => 'pay_unlock', 'msg_id' => $rand, 'status' => 1, 'type' => $params['type'], ]; Gateway::sendToClient($client_id, json_encode($snd_data)); } // 查询支付锁单 public static function searchpaylock(string $client_id, array $params) { $rand = 'search_pay_lock' . Random::build(); $snd_data = [ 'msg' => '锁单查询', 'operate_type' => 'search_pay_lock', 'msg_id' => $rand, 'type' => $params['type'], ]; $lock_name = self::get_shopping_save_lockname($params['shop_id'], $params['table_code']); // 先加入锁单分组 Gateway::joinGroup($client_id, $lock_name); print_r('查询的key-----' . $lock_name . "\r\n"); if(!empty($_SESSION[$lock_name])) { print_r('查询的session-----' . $_SESSION[$lock_name] . "\r\n"); $snd_data['status'] = 0; }else { $other_clinet = false; // 如果本人没锁单,查找有没有其他小伙伴锁单了 $all = Gateway::getClientSessionsByGroup($lock_name); foreach ($all as $g_client_id => $g_client_id_data ) { $session = Gateway::getSession($g_client_id); if($session && isset($session[$lock_name])) { $other_clinet = true; break; } } if($other_clinet) { $snd_data['status'] = 0; }else { $snd_data['status'] = 1; } } Gateway::sendToClient($client_id, json_encode($snd_data)); } // 添加redis public static function setredis(string $msg_id, string $data) { $redis_name = 'shop' . date('Ymd'); $redis = self::$redis; $redis->get($redis_name, function ($result, $redis) use ($msg_id, $data, $redis_name){ if($result) { $msg_id_arr = json_decode($result, true); array_push($msg_id_arr, $msg_id); $result = json_encode($msg_id_arr); }else { $result = json_encode([$msg_id]); } // 分天时添加消息ID $redis->set($redis_name, $result, 3600); // 添加消息内容 $redis->set($msg_id, $data, 3600); }); } // 添加redis 新 public static function setredis_new(string $data, string $client_id) { print_r('redis保存client_id---->' . $client_id . "\r\n"); print_r('redis保存值---->' . $data . "\r\n"); print_r('redis保存时间---->' . self::REDIS_TIME . "\r\n"); $res = Redis::setex($client_id, self::REDIS_TIME, $data); print_r('redis保存结果---->' . $res . "\r\n"); } // 消息回执 public static function delredis_new(string $client_id, string $msg_id) { // 处理普通消息 Redis::del($client_id); print_r('回执---》' . $msg_id . date('Y-m-d H:i:s') . "\r\n"); // 如果是订单打印回执,直接删除 if(strstr($msg_id, 'cashier_order')) { print_r('打印回执---》' . $msg_id . date('Y-m-d H:i:s') . "\r\n"); $uid = Gateway::getUidByClientId($client_id); print_r('UID---》' . $uid . date('Y-m-d H:i:s') . "\r\n"); Redis::del($uid); } } // 定时器处理消息回执/在线列表 public static function geteventredis_new() { print_r('定时器' . "\r\n"); $gateway = Gateway::class; // 处理消息(包含推送) $redis_name = Gateway::getAllClientSessions(); foreach ($redis_name as $client_id => $client_id_data) { if(Gateway::isOnline($client_id)) { $result = Redis::get($client_id); // 处理普通消息 if($result) { $msg_info_arr = json_decode($result, true); if($msg_info_arr['send_num'] < self::RETRYCOUNT) { // 推送类型 $method = ''; switch ($msg_info_arr['method']) { case 'sendToClient': $method = 'isOnline'; break; case 'sendToUid': $method = 'isUidOnline'; break; } // 如果在线就推送 if($method && call_user_func_array([$gateway, $method], [$msg_info_arr['send_id']])) { // 再次推送 call_user_func_array([$gateway, $msg_info_arr['method']], [$msg_info_arr['send_id'], $result]); print_r('推送了-----' . "\r\n"); // 推送以后新增推送次数 $msg_info_arr['send_num'] += 1; Redis::setex($client_id, self::REDIS_TIME, json_encode($msg_info_arr), ); return true; } } self::add_log_file('----无回执--' .date('Y-m-d H:i:s'). '--->' . $result); } $r_name = $client_id . '_lock'; // 处理锁单消息 $result = Redis::get($r_name); if($result) { $session = $gateway::getSession($client_id); print_r('session的内容-----' . json_encode($session) . "\r\n"); if($session && isset($session[$result])) { // 如果大于五秒没有更新,解除锁定 if(time() - $session[$result] > 10) { unset($session[$result]); $gateway::setSession($client_id, $session); Redis::del($r_name); print_r('解除锁定了-----' . json_encode($session) . "\r\n"); return true; } } } $uid = $gateway::getUidByClientId($client_id); if($uid) { $result = Redis::get($uid); // 处理打印消息 if($result) { $msg_info_arr = json_decode($result, true); foreach ($msg_info_arr as $k => $v) { if($v['send_num'] < self::RETRYCOUNT) { $msg_info_arr[$k]['send_num'] += 1; $v_json = json_encode($v); call_user_func_array([$gateway, $v['method']], [$v['send_id'], $v_json]); // 推送以后新增推送次数 self::add_log_file('推送收银机订单打印(重试第' . $v['send_num'] . '次)--->' . $v_json, 'cashier'); // $redis->set($uid, json_encode($v), self::REDIS_TIME); // array_push($new_arr, $v); }else { unset($msg_info_arr[$k]); $msg_info_arr = array_values($msg_info_arr); self::add_log_file('----推送收银机订单打印无回执--->' . $result, 'cashier'); } if(empty($msg_info_arr)) { Redis::del($uid); }else { Redis::setex($uid, self::REDIS_TIME, json_encode($msg_info_arr), ); } return true; } } } } Redis::del($client_id); Redis::del($uid); } // 处理在线列表 self::saveonlinelist($redis_name); } public static function saveonlinelist(array $client_id_list) { if(is_array($client_id_list)) { $redis_name = date('Y-m-d') . '_online_number'; $result = Redis::get($redis_name); if($result) { $result = json_decode($result, true); $client_id_arr = []; foreach ($client_id_list as $client_id => $client_id_info) { $client_id_arr[] = $client_id; } foreach ($result as $type => $redis_client_list) { $s_arr = array_values(array_intersect($client_id_arr, $redis_client_list)); $result[$type] = $s_arr; } Redis::setex($redis_name, 60 * 60 * 24, json_encode($result)); } } } // 消息回执 public static function delredis(string $msg_id, string $error = null) { $redis = self::$redis; $redis_name = 'shop' . date('Ymd'); $redis->get($redis_name, function ($result, $redis) use ($redis_name, $msg_id){ if($result) { $result = json_decode($result, true); $key = array_search($msg_id, $result); if($key === false) { }else { unset($result[$key]); $result = array_values($result); if(empty($result)) { $redis->del($redis_name); }else { $redis->set($redis_name, json_encode($result), 3600); } } } }); // 收银机打印回执 if(strstr($msg_id,'cashier_order') && $error) { $db = self::$db; $redis->get($msg_id, function ($result) use ($redis_name, $msg_id, $error, $db){ $result = json_decode($result, true); $serviceLog = [ 'queue' => 'test-order.print.queue', 'msg' => $result['data'], 'type' => 'orderPrint', 'plat' => 'Cashier', 'create_time' => date('Y-m-d H:i:s'), 'fail_time' => date('Y-m-d H:i:s'), 'err_info' => $error, ]; $db->insert('mq_log')->cols($serviceLog)->query(); }); } $redis->del($msg_id); } // 定时器处理消息回执 public static function geteventredis() { $redis_name = 'shop' . date('Ymd'); $gateway = Gateway::class; $redis = self::$redis; // 找到本时候的数据msg_id $result = Redis::get($redis_name); if($result) { $msg_id_arr = json_decode($result, true); foreach ($msg_id_arr as $k => $msg) { $redis->get($msg, function ($result, $redis) use($gateway, $k, $msg, $redis_name, $msg_id_arr){ if($result) { $msg_info_arr = json_decode($result, true); if($msg_info_arr['send_num'] < self::RETRYCOUNT) { // 推送类型 $method = ''; switch ($msg_info_arr['method']) { case 'sendToClient': $method = 'isOnline'; break; case 'sendToUid': $method = 'isUidOnline'; break; } if($msg_info_arr['method'] == 'sendToGroup') { // 发送广播并将 self::$client_id 排除在外 Gateway::sendToGroup($msg_info_arr['send_id'], $result, !empty($msg_info_arr['no_client_id'])?$msg_info_arr['no_client_id']:[]); // 推送以后新增推送次数 $msg_info_arr['send_num'] += 1; }else { // 如果在线就推送 if($method && call_user_func_array([$gateway, $method], [$msg_info_arr['send_id']])) { // 再次推送 call_user_func_array([$gateway, $msg_info_arr['method']], [$msg_info_arr['send_id'], $result]); // 推送以后新增推送次数 $msg_info_arr['send_num'] += 1; } } $redis->set($msg, json_encode($msg_info_arr), 3600); }else { // 失败,重发次数达到最大限度值。记录日志并删除数据 $text = '------>无回执----->'. $result . "\r\n"; self::add_log_file($text); if(strstr($msg,'cashier_order')) { $serviceLog = [ 'queue' => 'test-order.print.queue', 'msg' => $msg_info_arr['data'], 'type' => 'orderPrint', 'plat' => 'Cashier', 'create_time' => date('Y-m-d H:i:s'), 'fail_time' => date('Y-m-d H:i:s'), 'err_info' => '无回执', ]; Db::table('mq_log')->insert($serviceLog); } // 删除redis $redis->del($msg); print_r('msg---->' . $msg . '已经删除' . date('Y-m-d H:i:s') . "\r\n"); $redis->get($redis_name, function ($result, $redis) use ($redis_name, $msg) { $result = json_decode($result, true); if($result) { $key = array_search($msg, $result); if($key === false) { }else { print_r('删除前---->' . json_encode($result) . date('Y-m-d H:i:s') . "\r\n"); unset($result[$key]); print_r('删除后---->' . json_encode($result). date('Y-m-d H:i:s') ."\r\n"); $result = array_values($result); print_r('排序后---->' . json_encode($result). date('Y-m-d H:i:s') . "\r\n"); if(empty($result)) { $redis->del($redis_name); }else { print_r('保存了---->' . json_encode($result). date('Y-m-d H:i:s') . "\r\n"); $redis->set($redis_name, json_encode($result), 3600, function ($r) { }); } } } }); } } }); sleep(1); } } } // 购物车 多端同步 UID public static function get_shopping_save_uid($shop_id, $table_code) { return 'cart_update' . $shop_id . '_' . $table_code; } public static function get_shopping_save_lockname($shop_id, $table_code) { return 'lock' . $shop_id . '_' . $table_code; } // 购物车 send_id public static function get_shopping_send_id($message) { self::$table_code = $message['shop_id'] . $message['table_code']; return self::$table_code; } // 增加数量 public static function savenumber($car, $message) { $number = $message['number']; // $number = $car['number'] + $message['number']; if(!empty($message['is_temporary']) && $message['is_temporary'] == 1) { $cols = [ 'number' => $number, 'is_temporary' => !empty($message['is_temporary'])?$message['is_temporary']:0, 'discount_sale_amount' => !empty($message['discount_sale_amount'])?$message['discount_sale_amount']:0, 'product_name' => !empty($message['is_temporary'])?$message['product_name']:'', 'sku_name' => !empty($message['is_temporary'])?(!empty($message['sku_name'])?$message['sku_name']:""):'', 'is_print' => !empty($message['is_print'])?$message['is_print']:0, 'remark' => !empty($message['remark'])?$message['remark']:'', ]; }else { $cols = ['number' => $number]; } if($number <= 0) { return Db::table('tb_cashier_cart')->where('id' , $car['id'])->delete(); }else { return Db::table('tb_cashier_cart')->where('id' , $car['id'])->update($cols); } } // 新增购物车 public static function add_data($message) { if(!empty($message['pro_group_info']) && is_array($message['pro_group_info'])) { $message['pro_group_info'] = json_encode($message['pro_group_info']); } $serviceLog = [ 'shop_id' => $message['shop_id'], 'sku_id' => !empty($message['sku_id'])?$message['sku_id']:0, 'product_id' => !empty($message['is_temporary'])?'-' . Random::build('numeric'):$message['product_id'], 'number' => $message['number'], 'table_code' => $message['table_code'], 'is_gift' => !empty($message['is_gift'])?$message['is_gift']:0, 'is_temporary' => !empty($message['is_temporary'])?$message['is_temporary']:0, 'discount_sale_amount' => !empty($message['discount_sale_amount'])?$message['discount_sale_amount']:0, 'discount_sale_note' => !empty($message['discount_sale_note'])?$message['discount_sale_note']:'', 'product_name' => !empty($message['is_temporary'])?$message['product_name']:'', 'sku_name' => !empty($message['is_temporary'])?$message['sku_name']:'', 'product_type' => !empty($message['product_type'])?$message['product_type']:'', 'is_print' => !empty($message['is_print'])?$message['is_print']:0, 'is_wait_call' => !empty($message['is_wait_call'])?$message['is_wait_call']:0, 'pack_number' => !empty($message['pack_number'])?$message['pack_number']:0, 'remark' => !empty($message['remark'])?$message['remark']:'', 'pro_group_info' => !empty($message['pro_group_info'])?$message['pro_group_info']:'', 'create_time' => date('Y-m-d H:i:s'), ]; $res = Db::table('tb_cashier_cart')->insertGetId($serviceLog); return $res; } // 修改购物车 public static function edit_data($message) { $id = $message['id']; // 需要过滤的字段 $arr = [ 'type', 'operate_type', 'account', 'active', 'create_time', 'goods_type', 'group_type', 'id', 'selectSpecInfo', 'isStock', 'stockNumber', 'group_text', 'skuList', 'update_time', 'lowPrice', 'salePrice', 'coverImg', 'name', 'packFee', 'unitName', 'suitNum', 'memberPrice', 'tableCode', 'num', ]; foreach ($message as $k => $v) { if(in_array($k, $arr)) { unset($message[$k]); } } if(!empty($message['pro_group_info']) && is_array($message['pro_group_info'])) { $message['pro_group_info'] = json_encode($message['pro_group_info']); } $serviceLog = $message; $serviceLog['update_time'] = date('Y-m-d H:i:s'); if(isset($message['number']) && $message['number'] <= 0) { $res = Db::table('tb_cashier_cart')->where('id' , $id)->delete(); }else { $res = Db::table('tb_cashier_cart')->where('id' , $id)->update($serviceLog); } return $res; } // 转桌 public static function rottable($message) { $update_time = date('Y-m-d H:i:s'); if(!empty($message['cart_id'])) { if(is_string($message['cart_id'])) { $cart_id = json_decode($message['cart_id'], true); }else { $cart_id = implode(',', $message['cart_id']); } $sql = " UPDATE `tb_cashier_cart` SET `table_code`='{$message['new_table_code']}',`update_time`='" . $update_time . "' WHERE `id` IN (" . $cart_id . ") AND `table_code`= '{$message['table_code']}'"; }else { $sql = " UPDATE `tb_cashier_cart` SET `table_code`='{$message['new_table_code']}',`update_time`='" . $update_time . "' WHERE `table_code`= '{$message['table_code']}'"; } return Db::execute($sql); } // 批量操作(打包与不打包) public static function batch($message) { $update_time = date('Y-m-d H:i:s'); if($message['is_pack'] == 0) { $sql = " UPDATE `tb_cashier_cart` SET `pack_number`='0',`update_time`='" . $update_time . "' WHERE `table_code`= '{$message['table_code']}'"; $res = Db::execute($sql); return $res; }elseif($message['is_pack'] == 1) { // 如果是打包,并且是称重,做相应处理 $sql = " UPDATE `tb_cashier_cart` as cart1, `tb_cashier_cart` as cart2 SET cart1.`pack_number`= cart2.`number`, cart1.`update_time`='" . $update_time . "' WHERE cart1.`table_code`= '{$message['table_code']}' AND cart1.`product_type` != 'weight' AND cart2.`id` = cart1.`id`"; $res = Db::execute($sql); $sql1 = " UPDATE `tb_cashier_cart` as cart1, `tb_cashier_cart` as cart2 SET cart1.`pack_number`= '1', cart1.`update_time`='" . $update_time . "' WHERE cart1.`table_code`= '{$message['table_code']}' AND cart1.`product_type` = 'weight' AND cart2.`id` = cart1.`id`"; $res1 = Db::execute($sql1); if($res || $res1) { return true; } } } /** * 写入文件 * @param string $str 文件内容 * @param string $dir_name 文件名 * @param string $is_s 心跳 * @return void */ public static function add_log_file(string $str, string $dir_name = 'other', bool $is_s = false): void { if(!$is_s) { $file = 'runtime/worker/' . date('Ymd') . '.log'; }else { $file = 'runtime/worker/xt_' . date('Ymd') . '.log'; } switch ($dir_name) { case 'cashier': $str = '【收银机】-->' . $str; break; case 'onboc': $str = '【管理小程序】-->' . $str; break; case 'manage': $str = '【PC管理端】-->' . $str; break; case 'shopping': $str = '【用户小程序】-->' . $str; break; case 'pad': $str = '【PAD】-->' . $str; break; } $flags = FILE_APPEND | LOCK_EX; // 追加内容并加锁 file_put_contents($file, date('Y-m-d H:i:s') . '------>' . $str . "\r\n", $flags); } /** * 统计在线客户端数量 */ public static function add_total_number(string $client_id, string $type = null, $total = null) { $redis_name = date('Y-m-d') . '_online_number'; $result = Redis::get($redis_name); if($result) { $result_arr = json_decode($result, true); if($type) { if(isset($result_arr[$type])) { if (!in_array($client_id, $result_arr[$type])) { // 新增 array_push($result_arr[$type], $client_id); } }else { $result_arr[$type] = [$client_id]; } }else { foreach ($result_arr as $type_str => $client_arr) { $key = array_search($client_id, $client_arr); if($key !== false) { // 关闭 unset($result_arr[$type_str][$key]); $result_arr[$type_str] = array_values($result_arr[$type_str]); } } if(!empty($result_arr['total'])) { $key = array_search($client_id, $result_arr['total']); if($key !== false) { unset($result_arr['total'][$key]); $result_arr['total'] = array_values($result_arr['total']); } } } if($total) { if(isset($result_arr['total'])) { if (!in_array($client_id, $result_arr['total'])) { // 新增 array_push($result_arr['total'], $client_id); } }else { $result_arr['total'] = [$client_id]; } } }else { if($type) { $result_arr[$type] = [$client_id]; } if($total) { $result_arr['total'] = [$client_id]; } } if(isset($result_arr)) { Redis::setex($redis_name, 60 * 60 * 24, json_encode($result_arr)); } if(!$type) { Redis::del($client_id); } } }