购物车迁入

This commit is contained in:
ASUS 2025-10-13 14:25:05 +08:00
parent a7837bc337
commit d5f1b19829
25 changed files with 4184 additions and 4 deletions

108
app/command/LogAddZip.php Normal file
View File

@ -0,0 +1,108 @@
<?php
namespace app\command;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Output\OutputInterface;
use ZipArchive;
class LogAddZip extends Command
{
protected static $defaultName = 'LogAddZip';
protected static $defaultDescription = 'LogAddZip';
/**
* @return void
*/
protected function configure()
{
$this->addArgument('name', InputArgument::OPTIONAL, 'Name description');
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$dir = 'runtime/worker/';
$yesterday = date("Ymd", strtotime("-1 day"));
// worker 打包
$file = $dir . '/' . $yesterday . '.log';
$xt_file = $dir . '/xt_' . $yesterday . '.log';
$file_zip = $dir . '/' . $yesterday . '.zip';
$is_close = false;
$xt_is_close = false;
if(!file_exists($file_zip)) {
$zip = new ZipArchive();
if($zip->open($file_zip, ZipArchive::CREATE) === TRUE) {
if(file_exists($file)) {
if($zip->addFile($file, $yesterday . '.log')) {
$is_close = true;
print_r($yesterday . '.log' . "\r\n");
}
}
if(file_exists($xt_file)) {
if($zip->addFile($xt_file, 'xt_' . $yesterday . '.log')) {
$xt_is_close = true;
print_r('xt_' . $yesterday . '.log' . "\r\n");
}
}
if ($is_close || $xt_is_close) {
if($zip->close()) {
if($is_close) {
unlink($file);
}
if($xt_is_close) {
unlink($xt_file);
}
}
}
}
}
$dir_l = 'runtime/log/';
// 如果今天是1号
if(date('d') == '01') {
// 找到上个月以及最后一天
// 上个月
$lastmonth = date('Ym', strtotime('-1 month'));
// 最后一天
$day = date('t', strtotime('last month'));
$dir_log = $dir_l . $lastmonth . '/' . $day . '.log';
}else {
$day = date("d", strtotime("-1 day"));
$lastmonth = date('Ym');
$dir_log = $dir_l . $lastmonth . '/' . $day . '.log';
}
// log 打包
$file_log = $dir_log;
$file_log_zip = $dir_l . '/' . $lastmonth . '/' . $day . '.zip';
$is_log_close = false;
if(!file_exists($file_log_zip)) {
$zip = new ZipArchive();
if($zip->open($file_log_zip, ZipArchive::CREATE) === TRUE) {
if(file_exists($file_log)) {
if($zip->addFile($file_log, $day . '.log')) {
$is_log_close = true;
print_r($day . '.log' . "\r\n");
}
}
if ($is_log_close) {
if($zip->close()) {
unlink($file_log);
}
}
}
}
return self::SUCCESS;
}
}

View File

@ -0,0 +1,135 @@
<?php
namespace app\command;
use app\common\model\MqLog;
use app\common\model\OrderInfo;
use app\common\model\RabbitMqConfig;
use ba\Random;
use PhpAmqpLib\Connection\AMQPStreamConnection;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Output\OutputInterface;
use support\Log;
class RabbOrderPrint extends Command
{
protected static $defaultName = 'RabbOrderPrint';
protected static $defaultDescription = 'RabbOrderPrint';
/**
* @return void
*/
protected function configure()
{
$this->addArgument('name', InputArgument::OPTIONAL, 'Name description');
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$host = RabbitMqConfig::$host;
$port = RabbitMqConfig::$port;
$user = RabbitMqConfig::$user;
$password = RabbitMqConfig::$password;
$queue = RabbitMqConfig::$queue_t . '-order.print.queue';
// 防止空闲时间断线必须设置心跳
$connection = new AMQPStreamConnection($host, $port, $user, $password,
'/',
false,
'AMQPLAIN',
null,
'en_US',
60,
60,
null,
false,
30
);
$rabbit_channel = $connection->channel();
$rabbit_channel->queue_declare($queue, false, true, false, false, false, [
'x-message-ttl' => ['I', 180000]
]);
$callback = function ($msg){
$date_time = date('Y-m-d H:i:s');
$data = $msg->body;
Log::write('收到消息--->' . $data . '--->' . $date_time . "\n");
// 如果是数字。则打印订单
$is_log = false;
$curl_error = '';
print_r($data . "\r\n");
$order_id_t = strpos($data, '_');
print_r($order_id_t . "嘿嘿\r\n");
if($order_id_t !== false) {
print_r($order_id_t . "\r\n");
$order_id = substr($data, 0, $order_id_t);
}else {
print_r( "无下划线\r\n");
$order_id = $data;
}
print_r($order_id . "\r\n");
$order = OrderInfo::where(['id' => $order_id])->find();
if($order) {
$rand = 'cashier_order' . Random::build();
$send_id = 'cashier_'. $order['shop_id'];
// 收银机打印订单
$snd_data = [
'msg' => '收银机订单打印',
'type' => 'cashier',
'operate_type' => 'order_print',
'data_type' => 'order',
'status' => 1,
'method' => 'sendToUid',
'send_num' => 0,
'send_id' => $send_id,
'msg_id' => $rand,
'data' => $data
];
$snd_data_json = json_encode($snd_data);
// 内部给收银机推送打订单
$url = 'http://127.0.0.1:8686/?method=sendToUid&account='. $send_id .'&params=' . $snd_data_json; // 替换为你的服务地址和端口
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($ch);
if (curl_errno($ch)) {
$is_log = true;
$curl_error = 'Curl error: ' . curl_error($ch);
}
curl_close($ch);
Log::write('内部通讯结果(订单打印)--->' . $output . '通讯ID--->cashier_' .$order['shop_id']. '---' . date('Y-m-d H:i:s') . "\n");
}else {
$curl_error = 'order Data is empty';
$is_log = true;
}
if($is_log) {
MqLog::create([
'queue' => '',
'msg' => $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' => $curl_error,
]);
}
$msg->delivery_info['channel']->basic_ack($msg->delivery_info['delivery_tag']);
};
$rabbit_channel->basic_consume($queue, '', false, false, false, false, $callback);
while ($rabbit_channel->is_consuming()) {
$rabbit_channel->wait();
}
$rabbit_channel->close();
$connection->close();
return self::SUCCESS;
}
}

View File

@ -0,0 +1,118 @@
<?php
namespace app\command;
use app\common\model\MqLog;
use app\common\model\RabbitMqConfig;
use ba\Random;
use PhpAmqpLib\Connection\AMQPStreamConnection;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Output\OutputInterface;
use think\facade\Log;
class RabbProductUpdate extends Command
{
protected static $defaultName = 'RabbProductUpdate';
protected static $defaultDescription = 'RabbProductUpdate';
/**
* @return void
*/
protected function configure()
{
$this->addArgument('name', InputArgument::OPTIONAL, 'Name description');
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$host = RabbitMqConfig::$host;
$port = RabbitMqConfig::$port;
$user = RabbitMqConfig::$user;
$password = RabbitMqConfig::$password;
$queue = RabbitMqConfig::$queue_t . '-product.info.change.queue';
// 防止空闲时间断线必须设置心跳
$connection = new AMQPStreamConnection($host, $port, $user, $password,
'/',
false,
'AMQPLAIN',
null,
'en_US',
60,
60,
null,
false,
30
);
$rabbit_channel = $connection->channel();
$rabbit_channel->queue_declare($queue, false, true, false, false, false, [
// 'x-message-ttl' => ['I', 180000]
]);
$callback = function ($msg){
$date_time = date('Y-m-d H:i:s');
$data = $msg->body;
Log::write('收到商品更新消息--->' . $data . '--->' . $date_time . "\n");
// 如果是数字。则打印订单
$is_log = false;
$curl_error = '';
if(is_numeric($data)) {
$rand = 'product_update' . Random::build();
$send_id = 'product_update'. $data;
$method = 'sendToGroup';
$snd_data = [
'msg' => '商品更新',
'type' => 'product',
'operate_type' => 'product_update',
'data_type' => 'product_update',
'status' => 1,
'method' => $method,
'send_num' => 0,
'send_id' => $send_id,
'msg_id' => $rand,
'data' => $data
];
$snd_data_json = json_encode($snd_data);
$url = 'http://127.0.0.1:8686/?method=' . $method . '&account='. $send_id .'&params=' . $snd_data_json; // 替换为你的服务地址和端口
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($ch);
if (curl_errno($ch)) {
$is_log = true;
$curl_error = 'Curl error: ' . curl_error($ch);
}
curl_close($ch);
Log::write('内部通讯结果(商品更新)--->' . $output . '通讯ID--->shop_id-->' .$send_id. '---' . date('Y-m-d H:i:s') . "\n");
if($is_log) {
MqLog::create([
'queue' => '',
'msg' => $data,
'type' => 'product_update',
'plat' => 'product',
'create_time' => date('Y-m-d H:i:s'),
'fail_time' => date('Y-m-d H:i:s'),
'err_info' => $curl_error,
]);
}
}
$msg->delivery_info['channel']->basic_ack($msg->delivery_info['delivery_tag']);
};
$rabbit_channel->basic_consume($queue, '', false, false, false, false, $callback);
while ($rabbit_channel->is_consuming()) {
$rabbit_channel->wait();
}
$rabbit_channel->close();
$connection->close();
return self::SUCCESS;
}
}

14
app/common/MqLog.php Normal file
View File

@ -0,0 +1,14 @@
<?php
namespace app\common\model;
use ba\Random;
use think\Model;
/**
* 错误日志
*/
class MqLog extends Model
{
}

13
app/common/OrderInfo.php Normal file
View File

@ -0,0 +1,13 @@
<?php
namespace app\common\model;
use think\Model;
/**
* 订单
*/
class OrderInfo extends Model
{
}

View File

@ -0,0 +1,19 @@
<?php
namespace app\common\model;
use ba\Random;
use think\Model;
/**
* 错误日志
*/
class RabbitMqConfig extends Model
{
public static $host = '121.40.109.122';
public static $port = '5672';
public static $user = 'chaozg';
public static $password = 'chaozg123';
public static $queue_t = 'prod';
}

17
ba/Exception.php Normal file
View File

@ -0,0 +1,17 @@
<?php
namespace ba;
use think\Exception as E;
/**
* BuildAdmin通用异常类
* catch 到异常后可以直接 $this->error(__($e->getMessage()), $e->getData(), $e->getCode());
*/
class Exception extends E
{
public function __construct(protected $message, protected $code = 0, protected $data = [])
{
parent::__construct($message, $code);
}
}

54
ba/Random.php Normal file
View File

@ -0,0 +1,54 @@
<?php
namespace ba;
class Random
{
/**
* 获取全球唯一标识
* @return string
*/
public static function uuid(): string
{
return sprintf(
'%04x%04x-%04x-%04x-%04x-',
mt_rand(0, 0xffff),
mt_rand(0, 0xffff),
mt_rand(0, 0xffff),
mt_rand(0, 0x0fff) | 0x4000,
mt_rand(0, 0x3fff) | 0x8000
) . substr(md5(uniqid(mt_rand(), true)), 0, 12);
}
/**
* 随机字符生成
* @param string $type 类型 alpha/alnum/numeric/noZero/unique/md5/encrypt/sha1
* @param int $len 长度
* @return string
*/
public static function build(string $type = 'alnum', int $len = 8): string
{
switch ($type) {
case 'alpha':
case 'alnum':
case 'numeric':
case 'noZero':
$pool = match ($type) {
'alpha' => 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
'alnum' => '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
'numeric' => '0123456789',
'noZero' => '123456789',
default => '',
};
return substr(str_shuffle(str_repeat($pool, ceil($len / strlen($pool)))), 0, $len);
case 'unique':
case 'md5':
return md5(uniqid(mt_rand()));
case 'encrypt':
case 'sha1':
return sha1(uniqid(mt_rand(), true));
}
return '';
}
}

View File

@ -33,7 +33,10 @@
"webman/redis-queue": "^1.3",
"workerman/crontab": "^1.0",
"overtrue/wechat": "~5.0",
"alibabacloud/dysmsapi-20170525": "^3.1"
"alibabacloud/dysmsapi-20170525": "^3.1",
"webman/gateway-worker": "^1.0",
"webman/console": "^2.1",
"php-amqplib/php-amqplib": "^2.8"
},
"suggest": {
"ext-event": "For better performance. "

692
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "f17a2c567830784202ec94a787caa9c6",
"content-hash": "d1ae83f79dde128e3114d5e4f511a6f5",
"packages": [
{
"name": "adbario/php-dot-notation",
@ -2239,6 +2239,86 @@
"abandoned": "w7corp/easywechat",
"time": "2024-12-25T08:00:38+00:00"
},
{
"name": "php-amqplib/php-amqplib",
"version": "v2.8.0",
"source": {
"type": "git",
"url": "https://github.com/php-amqplib/php-amqplib.git",
"reference": "7df8553bd8b347cf6e919dd4a21e75f371547aa0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-amqplib/php-amqplib/zipball/7df8553bd8b347cf6e919dd4a21e75f371547aa0",
"reference": "7df8553bd8b347cf6e919dd4a21e75f371547aa0",
"shasum": "",
"mirrors": [
{
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
"preferred": true
}
]
},
"require": {
"ext-bcmath": "*",
"php": ">=5.4.0"
},
"replace": {
"videlalvaro/php-amqplib": "self.version"
},
"require-dev": {
"phpdocumentor/phpdocumentor": "^2.9",
"phpunit/phpunit": "^4.8",
"scrutinizer/ocular": "^1.1",
"squizlabs/php_codesniffer": "^2.5"
},
"suggest": {
"ext-sockets": "Use AMQPSocketConnection"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.8-dev"
}
},
"autoload": {
"psr-4": {
"PhpAmqpLib\\": "PhpAmqpLib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL-2.1-or-later"
],
"authors": [
{
"name": "Alvaro Videla",
"role": "Original Maintainer"
},
{
"name": "John Kelly",
"email": "johnmkelly86@gmail.com",
"role": "Maintainer"
},
{
"name": "Raúl Araya",
"email": "nubeiro@gmail.com",
"role": "Maintainer"
}
],
"description": "Formerly videlalvaro/php-amqplib. This library is a pure PHP implementation of the AMQP protocol. It's been tested against RabbitMQ.",
"homepage": "https://github.com/php-amqplib/php-amqplib/",
"keywords": [
"message",
"queue",
"rabbitmq"
],
"support": {
"issues": "https://github.com/php-amqplib/php-amqplib/issues",
"source": "https://github.com/php-amqplib/php-amqplib/tree/master"
},
"time": "2018-10-23T18:48:24+00:00"
},
{
"name": "pimple/pimple",
"version": "v3.5.0",
@ -3127,6 +3207,106 @@
],
"time": "2024-09-25T14:21:43+00:00"
},
{
"name": "symfony/console",
"version": "v7.3.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "66c1440edf6f339fd82ed6c7caa76cb006211b44"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/66c1440edf6f339fd82ed6c7caa76cb006211b44",
"reference": "66c1440edf6f339fd82ed6c7caa76cb006211b44",
"shasum": "",
"mirrors": [
{
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
"preferred": true
}
]
},
"require": {
"php": ">=8.2",
"symfony/deprecation-contracts": "^2.5|^3",
"symfony/polyfill-mbstring": "~1.0",
"symfony/service-contracts": "^2.5|^3",
"symfony/string": "^7.2"
},
"conflict": {
"symfony/dependency-injection": "<6.4",
"symfony/dotenv": "<6.4",
"symfony/event-dispatcher": "<6.4",
"symfony/lock": "<6.4",
"symfony/process": "<6.4"
},
"provide": {
"psr/log-implementation": "1.0|2.0|3.0"
},
"require-dev": {
"psr/log": "^1|^2|^3",
"symfony/config": "^6.4|^7.0",
"symfony/dependency-injection": "^6.4|^7.0",
"symfony/event-dispatcher": "^6.4|^7.0",
"symfony/http-foundation": "^6.4|^7.0",
"symfony/http-kernel": "^6.4|^7.0",
"symfony/lock": "^6.4|^7.0",
"symfony/messenger": "^6.4|^7.0",
"symfony/process": "^6.4|^7.0",
"symfony/stopwatch": "^6.4|^7.0",
"symfony/var-dumper": "^6.4|^7.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Symfony\\Component\\Console\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Eases the creation of beautiful and testable command line interfaces",
"homepage": "https://symfony.com",
"keywords": [
"cli",
"command-line",
"console",
"terminal"
],
"support": {
"source": "https://github.com/symfony/console/tree/v7.3.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2025-05-24T10:34:04+00:00"
},
{
"name": "symfony/deprecation-contracts",
"version": "v3.5.1",
@ -3451,6 +3631,262 @@
],
"time": "2025-05-11T15:36:20+00:00"
},
{
"name": "symfony/polyfill-ctype",
"version": "v1.32.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
"reference": "a3cc8b044a6ea513310cbd48ef7333b384945638"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638",
"reference": "a3cc8b044a6ea513310cbd48ef7333b384945638",
"shasum": "",
"mirrors": [
{
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
"preferred": true
}
]
},
"require": {
"php": ">=7.2"
},
"provide": {
"ext-ctype": "*"
},
"suggest": {
"ext-ctype": "For best performance"
},
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/polyfill",
"name": "symfony/polyfill"
}
},
"autoload": {
"files": [
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Ctype\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Gert de Pagter",
"email": "BackEndTea@gmail.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill for ctype functions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"ctype",
"polyfill",
"portable"
],
"support": {
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.32.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2024-09-09T11:45:10+00:00"
},
{
"name": "symfony/polyfill-intl-grapheme",
"version": "v1.32.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-grapheme.git",
"reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe",
"reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe",
"shasum": "",
"mirrors": [
{
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
"preferred": true
}
]
},
"require": {
"php": ">=7.2"
},
"suggest": {
"ext-intl": "For best performance"
},
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/polyfill",
"name": "symfony/polyfill"
}
},
"autoload": {
"files": [
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Intl\\Grapheme\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill for intl's grapheme_* functions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"grapheme",
"intl",
"polyfill",
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.32.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2024-09-09T11:45:10+00:00"
},
{
"name": "symfony/polyfill-intl-normalizer",
"version": "v1.32.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
"reference": "3833d7255cc303546435cb650316bff708a1c75c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c",
"reference": "3833d7255cc303546435cb650316bff708a1c75c",
"shasum": "",
"mirrors": [
{
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
"preferred": true
}
]
},
"require": {
"php": ">=7.2"
},
"suggest": {
"ext-intl": "For best performance"
},
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/polyfill",
"name": "symfony/polyfill"
}
},
"autoload": {
"files": [
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Intl\\Normalizer\\": ""
},
"classmap": [
"Resources/stubs"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill for intl's Normalizer class and related functions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"intl",
"normalizer",
"polyfill",
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.32.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2024-09-09T11:45:10+00:00"
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.32.0",
@ -3798,6 +4234,103 @@
],
"time": "2024-09-25T14:20:29+00:00"
},
{
"name": "symfony/string",
"version": "v7.3.3",
"source": {
"type": "git",
"url": "https://github.com/symfony/string.git",
"reference": "17a426cce5fd1f0901fefa9b2a490d0038fd3c9c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/string/zipball/17a426cce5fd1f0901fefa9b2a490d0038fd3c9c",
"reference": "17a426cce5fd1f0901fefa9b2a490d0038fd3c9c",
"shasum": "",
"mirrors": [
{
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
"preferred": true
}
]
},
"require": {
"php": ">=8.2",
"symfony/polyfill-ctype": "~1.8",
"symfony/polyfill-intl-grapheme": "~1.0",
"symfony/polyfill-intl-normalizer": "~1.0",
"symfony/polyfill-mbstring": "~1.0"
},
"conflict": {
"symfony/translation-contracts": "<2.5"
},
"require-dev": {
"symfony/emoji": "^7.1",
"symfony/error-handler": "^6.4|^7.0",
"symfony/http-client": "^6.4|^7.0",
"symfony/intl": "^6.4|^7.0",
"symfony/translation-contracts": "^2.5|^3.0",
"symfony/var-exporter": "^6.4|^7.0"
},
"type": "library",
"autoload": {
"files": [
"Resources/functions.php"
],
"psr-4": {
"Symfony\\Component\\String\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way",
"homepage": "https://symfony.com",
"keywords": [
"grapheme",
"i18n",
"string",
"unicode",
"utf-8",
"utf8"
],
"support": {
"source": "https://github.com/symfony/string/tree/v7.3.3"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://github.com/nicolas-grekas",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2025-08-25T06:35:40+00:00"
},
{
"name": "symfony/translation",
"version": "v7.3.1",
@ -4366,6 +4899,104 @@
],
"time": "2024-11-21T00:49:12+00:00"
},
{
"name": "webman/console",
"version": "v2.1.3",
"source": {
"type": "git",
"url": "https://github.com/webman-php/console.git",
"reference": "bbee274a5f091eaf90e7a257dd0fbfef47da9a17"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/webman-php/console/zipball/bbee274a5f091eaf90e7a257dd0fbfef47da9a17",
"reference": "bbee274a5f091eaf90e7a257dd0fbfef47da9a17",
"shasum": "",
"mirrors": [
{
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
"preferred": true
}
]
},
"require": {
"doctrine/inflector": "^2.0",
"symfony/console": ">=5.0"
},
"require-dev": {
"workerman/webman": "^1.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Webman\\Console\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "walkor",
"email": "walkor@workerman.net",
"homepage": "http://www.workerman.net",
"role": "Developer"
}
],
"description": "Webman console",
"homepage": "http://www.workerman.net",
"keywords": [
"webman console"
],
"support": {
"email": "walkor@workerman.net",
"forum": "http://www.workerman.net/questions",
"issues": "https://github.com/webman-php/console/issues",
"source": "https://github.com/webman-php/console",
"wiki": "http://www.workerman.net/doc/webman"
},
"time": "2025-03-06T08:23:07+00:00"
},
{
"name": "webman/gateway-worker",
"version": "v1.0.8",
"source": {
"type": "git",
"url": "https://github.com/webman-php/gateway-worker.git",
"reference": "0fc07316a755557128a30acca3507b42ec428c14"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/webman-php/gateway-worker/zipball/0fc07316a755557128a30acca3507b42ec428c14",
"reference": "0fc07316a755557128a30acca3507b42ec428c14",
"shasum": "",
"mirrors": [
{
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
"preferred": true
}
]
},
"require": {
"workerman/gateway-worker": ">=3.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Webman\\GatewayWorker\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"support": {
"issues": "https://github.com/webman-php/gateway-worker/issues",
"source": "https://github.com/webman-php/gateway-worker/tree/v1.0.8"
},
"time": "2023-07-20T09:10:10+00:00"
},
{
"name": "webman/redis",
"version": "v2.1.2",
@ -4589,6 +5220,65 @@
},
"time": "2025-01-15T07:20:50+00:00"
},
{
"name": "workerman/gateway-worker",
"version": "v3.1.4",
"source": {
"type": "git",
"url": "https://github.com/walkor/GatewayWorker.git",
"reference": "9b8803af0b22cbe8d0be51f7b207e10f141ba837"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/walkor/GatewayWorker/zipball/9b8803af0b22cbe8d0be51f7b207e10f141ba837",
"reference": "9b8803af0b22cbe8d0be51f7b207e10f141ba837",
"shasum": "",
"mirrors": [
{
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
"preferred": true
}
]
},
"require": {
"workerman/workerman": "^5.0.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.0-dev"
}
},
"autoload": {
"psr-4": {
"GatewayWorker\\": "./src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"homepage": "http://www.workerman.net",
"keywords": [
"communication",
"distributed"
],
"support": {
"issues": "https://github.com/walkor/GatewayWorker/issues",
"source": "https://github.com/walkor/GatewayWorker/tree/v3.1.4"
},
"funding": [
{
"url": "https://opencollective.com/walkor",
"type": "open_collective"
},
{
"url": "https://www.patreon.com/walkor",
"type": "patreon"
}
],
"time": "2023-12-08T00:54:08+00:00"
},
{
"name": "workerman/redis",
"version": "v2.0.4",

View File

@ -0,0 +1,24 @@
<?php
return [
'enable' => true,
'build_dir' => BASE_PATH . DIRECTORY_SEPARATOR . 'build',
'phar_filename' => 'webman.phar',
'bin_filename' => 'webman.bin',
'signature_algorithm'=> Phar::SHA256, //set the signature algorithm for a phar and apply it. The signature algorithm must be one of Phar::MD5, Phar::SHA1, Phar::SHA256, Phar::SHA512, or Phar::OPENSSL.
'private_key_file' => '', // The file path for certificate or OpenSSL private key file.
'exclude_pattern' => '#^(?!.*(composer.json|/.github/|/.idea/|/.git/|/.setting/|/runtime/|/vendor-bin/|/build/|/vendor/webman/admin/))(.*)$#',
'exclude_files' => [
'.env', 'LICENSE', 'composer.json', 'composer.lock', 'start.php', 'webman.phar', 'webman.bin'
],
'custom_ini' => '
memory_limit = 256M
',
];

View File

@ -0,0 +1,4 @@
<?php
return [
'enable' => true,
];

View File

@ -0,0 +1,37 @@
<?php
use Webman\GatewayWorker\Gateway;
use Webman\GatewayWorker\BusinessWorker;
use Webman\GatewayWorker\Register;
return [
'gateway' => [
'handler' => Gateway::class,
'listen' => 'websocket://0.0.0.0:2348',
'count' => cpu_count(),
'reloadable' => false,
'constructor' => ['config' => [
'lanIp' => '127.0.0.1',
'startPort' => 2300,
'pingInterval' => 25,
'pingData' => '{"type":"p","data_type":"p"}',
'registerAddress' => '127.0.0.1:1238',
'onConnect' => function(){},
]]
],
'worker' => [
'handler' => BusinessWorker::class,
'count' => cpu_count()*2,
'constructor' => ['config' => [
'eventHandler' => plugin\webman\gateway\Events::class,
'name' => 'ChatBusinessWorker',
'registerAddress' => '127.0.0.1:1238',
]]
],
'register' => [
'handler' => Register::class,
'listen' => 'text://127.0.0.1:1238',
'count' => 1, // Must be 1
'constructor' => []
],
];

View File

@ -14,7 +14,7 @@
return [
'default' => [
'password' => '',
'password' => '222222',
'host' => '127.0.0.1',
'port' => 6379,
'database' => 0,

View File

@ -7,7 +7,7 @@ return [
// 数据库类型
'type' => 'mysql',
// 服务器地址
'hostname' => '192.168.1.31',
'hostname' => '192.168.1.42',
// 数据库名
'database' => 'czg_cashier',
// 数据库用户名

37
extend/Config/Db.php Normal file
View File

@ -0,0 +1,37 @@
<?php
namespace Config;
/**
* mysql配置
* @author shmilylbelva
*/
$database = require_once __DIR__.'/../../config/think-orm.php';
// 正式
define('DB_HOST', $database['connections']['mysql']['hostname']); //数据库地址
define('DB_USER', $database['connections']['mysql']['username']); //用户名
define('DB_PWD', $database['connections']['mysql']['password']); //数据库密码
define('DB_NAME', $database['connections']['mysql']['database']); //库名
define('DB_CHARSET', $database['connections']['mysql']['charset']); //字符集
define('DB_PORT',3306); //端口
/**
* 数据库的一个实例配置,则使用时像下面这样使用
* $user_array = Db::instance('db1')->select('name,age')->from('users')->where('age>12')->query();print_r()exit
* 等价于
* $user_array = Db::instance('db1')->query('SELECT `name`,`age` FROM `users` WHERE `age`>12');
* @var array
*/
class Db
{
public static $db = array(
'host' => DB_HOST,
'user' => DB_USER,
'password' =>DB_PWD,
'dbname' => DB_NAME,
'port' => DB_PORT,
'charset' => DB_CHARSET,
);
}

View File

@ -0,0 +1,786 @@
<?php
namespace extend\workermans\model;
use ba\Exception;
use ba\Random;
use support\think\Db;
use GatewayWorker\Lib\Gateway;
use support\Log;
use think\Model;
/**
*
*/
class Base extends Model
{
public static $db = null;
public static $redis = null;
public static $client_id;
public static $shop_id;
public static $account;
public static $table_code;
public static $lock_name; // 锁单值
const RETRYCOUNT = 3;
const REDIS_TIME = 60 * 10; // redis 保存时间 10分钟
// 分组推送(广播)
public static function gateway_query(string $method, array $params)
{
list($clientIdOrUid, $data) = $params;
$data_arr = json_decode($data, true);
if(!empty($data_arr['msg_id'])) {
$data_arr['method'] = $method;
$data_arr['send_id'] = $clientIdOrUid;
$data_arr['send_num'] = 0;
self::setredis_new(json_encode($data_arr), self::$client_id);
}
if(!empty($data_arr['operate_type']) && !empty($data_arr['status'])) {
// 不包含初始化并且操作失败的
if(!strstr($data_arr['operate_type'], 'init') && $data_arr['status'] == 1) {
$operate_type = '';
if(strstr($data_arr['operate_type'], 'add')) {
$operate_type = 'add';
}elseif (strstr($data_arr['operate_type'], 'edit')) {
$operate_type = 'edit';
}elseif (strstr($data_arr['operate_type'], 'del')) {
$operate_type = 'del';
}elseif (strstr($data_arr['operate_type'], 'cleanup')) {
$operate_type = 'cleanup';
}elseif (strstr($data_arr['operate_type'], 'clearOrder')) {
$operate_type = 'clearOrder';
}elseif (strstr($data_arr['operate_type'], 'batch')) {
$operate_type = 'init';
}elseif (strstr($data_arr['operate_type'], 'rottable')) {
// 如果是转桌。发送init初始化
$operate_type = 'init';
}
// 所有在线端广播
$broadcast_arr = [
'type' => '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();
$redis = self::$redis;
$_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';
$redis->get($redis_name, function ($result, $redis) use ($msg_id, $redis_name){
if($result) {
}else {
$redis->set($redis_name, $msg_id, 3600);
}
});
}
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']);
// 直接保存锁定
$redis = self::$redis;
// 自己先解锁
$_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';
$redis->get($redis_name, function ($result, $redis) use ($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");
self::$redis->set($client_id, $data, self::REDIS_TIME, function ($result) {
print_r('redis保存结果---->' . $result . "\r\n");
});
}
// 消息回执
public static function delredis_new(string $client_id, string $msg_id)
{
// 处理普通消息
self::$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");
self::$redis->del($uid);
}
}
// 定时器处理消息回执/在线列表
public static function geteventredis_new()
{
print_r('定时器' . "\r\n");
$redis = self::$redis;
$gateway = Gateway::class;
// 处理消息(包含推送)
$redis_name = Gateway::getAllClientSessions();
foreach ($redis_name as $client_id => $client_id_data) {
$order_print_client_id = $client_id . '_orderPrint';
if(Gateway::isOnline($client_id)) {
// 处理普通消息
$redis->get($client_id, function ($result, $redis) use($gateway, $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->set($client_id, json_encode($msg_info_arr), self::REDIS_TIME);
return true;
}
}
self::add_log_file('----无回执--' .date('Y-m-d H:i:s'). '--->' . $result);
}
});
$r_name = $client_id . '_lock';
// 处理锁单消息
$redis->get($r_name, function ($result, $redis) use($client_id, $gateway, $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);
// 处理打印消息
$redis->get($uid, function ($result, $redis) use($gateway, $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->set($uid, json_encode($msg_info_arr), self::REDIS_TIME);
}
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 = self::$redis;
$redis_name = date('Y-m-d') . '_online_number';
$redis->get($redis_name, function ($result, $redis) use ($redis_name, $client_id_list){
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->set($redis_name, json_encode($result), 60 * 60 * 24);
}
});
}
}
// 消息回执
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
$redis->get($redis_name, function ($result, $redis) use ($gateway, $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 = self::$redis;
$redis_name = date('Y-m-d') . '_online_number';
$redis->get($redis_name, function ($result, $redis) use ($redis_name, $client_id, $type, $total) {
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->set($redis_name, json_encode($result_arr), 60 * 60 * 24);
}
});
if(!$type) {
$redis->del($client_id);
}
}
}

View File

@ -0,0 +1,376 @@
<?php
namespace extend\workermans\model;
use ba\Exception;
use ba\Random;
use support\think\Db;
use GatewayWorker\Lib\Gateway;
Use support\Log;
use think\Model;
/**
* 收银机
*/
class Cashier extends Base
{
/**
* @param string $client_id
* @param array $message
* @return void
*/
public static function handles(string $client_id, array $message):void
{
self::$client_id = $client_id;
self::$shop_id = $message['shop_id'];
// 验证 shop_id 和 table_code 是否存在
$shop = Db::query("
SELECT * FROM `tb_shop_info` WHERE
`id`={$message['shop_id']}
");
if (!$shop) {
self::gateway_query('sendToClient', [$client_id, json_encode(['msg' => '商户信息不存在'])]);
return;
}
// 处理购物车数据
switch ($message['operate_type']) {
// 初始化购物车
case 'init':
// 绑定商户账号(ID) 和 client_id 已便于收银机打小票
$message['account'] = 'cashier_' . $message['shop_id'];
Gateway::bindUid($client_id, $message['account']);
self::$account = $message['account'];
$rand = 'cashier_init' . Random::build();
$car = [];
if(empty($message['table_code'])) {
$message['table_code'] = 'PC' . Random::build('numeric');
}else {
$car = Db::query("
SELECT * FROM `tb_cashier_cart` WHERE
`shop_id`={$message['shop_id']} AND
`table_code`='{$message['table_code']}'
");
}
$snd_data = [
'msg' => '收银机初始化',
'type' => 'cashier',
'operate_type' => 'init',
'data_type' => 'cart',
'status' => 1,
'msg_id' => $rand,
'table_code' => $message['table_code'],
'data' => $car
];
self::gateway_query('sendToClient', [$client_id, json_encode($snd_data)]);
$uid = $message['account'];
$redis = self::$redis;
$gateway = Gateway::class;
// 处理打印消息
$redis->get($uid, function ($result, $redis) use($gateway, $uid){
if($result) {
$msg_info_arr = json_decode($result, true);
$arr_n = [];
foreach ($msg_info_arr as $k => $arr) {
if($arr['send_num'] < self::RETRYCOUNT) {
$arr['send_num'] += 1;
$arr_json = json_encode($arr);
call_user_func_array([$gateway, $arr['method']], [$arr['send_id'], $arr_json]);
// 推送以后新增推送次数
self::add_log_file('离线后推送收银机订单打印--->' .date('Y-m-d H:i:s'). '--->' . $arr_json, 'cashier');
}
self::add_log_file('----离线后推送收银机订单打印无回执--' .date('Y-m-d H:i:s'). '--->' . $arr_json, 'cashier');
$arr_n[] = $arr;
}
$redis->set($uid, json_encode($arr_n), self::REDIS_TIME);
}
});
break;
// 新增
case 'add':
if(
($message['is_temporary'] == 1 && !empty($message['number'])) ||
(!empty($message['product_id']) &&
!empty($message['sku_id']) &&
!empty($message['number']) )
) {
// 查询购物车是否有重复的商品,有则新增,无则累加 (有赠送品的除外)
try {
if(empty($message['goods_type']) || $message['goods_type'] != 'package') {
if($message['is_temporary'] == 1) {
$car = Db::query("
SELECT * FROM `tb_cashier_cart` WHERE
`shop_id`={$message['shop_id']} AND
`is_gift`={$message['is_gift']} AND
`product_name`='{$message['product_name']}' AND
`is_temporary`={$message['is_temporary']} AND
`table_code`= '{$message['table_code']}'
");
}else {
$car = Db::query("
SELECT * FROM `tb_cashier_cart` WHERE
`shop_id`={$message['shop_id']} AND
`sku_id`={$message['sku_id']} AND
`product_id`={$message['product_id']} AND
`is_gift`={$message['is_gift']} AND
`table_code`= '{$message['table_code']}'
");
}
}else {
// 如果是套餐商品,直接新增
$car[0] = [];
}
if(empty($car[0])) {
if($message['number'] <= 0) {
self::gateway_query('sendToClient', [$client_id, json_encode(['msg' => '数量不合法'])]);
return;
}
$res = $res_id = self::add_data($message);
}else {
$car = $car[0];
$res_id = $car['id'];
// 如果是新增套餐商品,硬新增
if(!empty($message['pro_group_info'])) {
$res = self::add_data($message);
}else {
// 是赠品,新增
if($car['is_gift'] == 1) {
// 如果原本的也是赠送的,则修改数量
if(!empty($message['is_gift']) && $message['is_gift'] == 1) {
$res = self::savenumber($car, $message);
}else {
$res = self::add_data($message);
}
}else {
// 如新增的也是赠送的
if(!empty($message['is_gift']) && $message['is_gift'] == 1) {
$res = self::add_data($message);
}else {
$res = self::savenumber($car, $message);
}
}
}
}
if($res) {
$status = 1;
}else {
$status = 0;
}
$rand = 'cashier_add' . Random::build();
$data = Db::query("
SELECT * FROM `tb_cashier_cart` WHERE
`id`={$res_id}");
// 向此桌码下面的 client_id 发送消息
$snd_data = [
'msg' => '购物车新增',
'type' => 'cashier',
'status' => $status,
'operate_type' => 'add',
'data_type' => 'cart',
'msg_id' => $rand,
'data' => $data[0]
];
self::gateway_query('sendToClient', [$client_id, json_encode($snd_data)]);
}catch (Exception $e){
Log::write('新增购物车时[error]->>>>>' . $e->getMessage(), 'error');
}
}
break;
// 修改
case 'edit':
if (empty($message['id'])) {
self::gateway_query('sendToClient', [$client_id, json_encode(['msg' => '购物车ID不存在'])]);
return;
}
try {
$data = Db::query("
SELECT * FROM `tb_cashier_cart` WHERE
`id`={$message['id']}");
if(!$data) {
self::gateway_query('sendToClient', [$client_id, json_encode(['msg' => '购物车不存在'])]);
return;
}
// $message['number'] += $data[0]['number'];
$res = self::edit_data($message);
if($res) {
$status = 1;
}else {
$status = 0;
}
$rand = 'cashier_edit' . Random::build();
if($res) {
$data = Db::query("
SELECT * FROM `tb_cashier_cart` WHERE
`id`={$message['id']}");
}else {
$data[0] = '';
}
$snd_data = [
'msg' => '购物车修改',
'type' => 'cashier',
'status' => $status,
'operate_type' => 'edit',
'data_type' => 'cart',
'msg_id' => $rand,
'data' => $data[0]
];
self::gateway_query('sendToClient', [$client_id, json_encode($snd_data)]);
}catch (Exception $e) {
Log::write('修改购物车时[error]->>>>>' . $e->getMessage(), 'error');
}
break;
// 删除
case 'del':
if (empty($message['id'])) {
self::gateway_query('sendToClient', [$client_id, json_encode(['msg' => '购物车ID不存在'])]);
return;
}
$data = Db::query("
SELECT * FROM `tb_cashier_cart` WHERE
`id`={$message['id']}");
if (empty($data)) {
self::gateway_query('sendToClient', [$client_id, json_encode(['msg' => '数据不存在'])]);
return;
}
try {
$res = Db::table('tb_cashier_cart')->where('id', $message['id'])->delete();
if($res) {
$status = 1;
}else {
$status = 0;
}
$rand = 'cashier_del' . Random::build();
$snd_data = [
'msg' => '购物车删除',
'type' => 'cashier',
'status' => $status,
'operate_type' => 'del',
'data_type' => 'cart',
'msg_id' => $rand,
'data' => $data[0]
];
self::gateway_query('sendToClient', [$client_id, json_encode($snd_data)]);
}catch (Exception $e) {
Log::write('删除购物车时[error]->>>>>' . $e->getMessage(), 'error');
}
break;
// 清除
case 'cleanup':
try {
$res = Db::table('tb_cashier_cart')
->where('table_code', $message['table_code'])
->delete();
if($res) {
$status = 1;
}else {
$status = 0;
}
$status = 1;
$rand = 'shopping_cleanup' . Random::build();
$snd_data = [
'msg' => '购物车清除',
'operate_type' => 'cleanup',
'msg_id' => $rand,
'type' => 'cashier',
'data_type' => 'cart',
'status' => $status,
'data' => [
'table_code' => $message['table_code'],
]
];
self::gateway_query('sendToClient', [$client_id, json_encode($snd_data)]);
}catch (Exception $e) {
Log::write('删除购物车时[error]->>>>>' . $e->getMessage(), 'error');
}
break;
// 转桌
case 'rottable':
if (empty($message['table_code']) || empty($message['new_table_code'])) {
self::gateway_query('sendToClient', [$client_id, json_encode(['msg' => '桌码或新桌码必填必填'])]);
return;
}
try {
$data = Db::query("
SELECT * FROM `tb_cashier_cart` WHERE
`table_code`= '{$message['table_code']}'");
if(!$data) {
self::gateway_query('sendToClient', [$client_id, json_encode(['msg' => '购物车不存在'])]);
return;
}
$res = self::rottable($message);
if($res) {
$status = 1;
}else {
$status = 0;
}
$rand = 'cashier_rottable' . Random::build();
$snd_data = [
'msg' => '购物车转桌',
'operate_type' => 'rottable',
'msg_id' => $rand,
'status' => $status,
'type' => 'cashier',
'data_type' => 'cart',
'data' => [
'table_code' => $message['table_code'],
'new_table_code' => $message['new_table_code'],
]
];
self::gateway_query('sendToClient', [$client_id, json_encode($snd_data)]);
}catch (Exception $e) {
Log::write('修改购物车时[error]->>>>>' . $e->getMessage(), 'error');
}
break;
// 批量操作(打包与不打包)
case 'batch':
try {
if (!isset($message['is_pack'])) {
self::gateway_query('sendToClient', [$client_id, json_encode(['msg' => 'is_pack必填'])]);
return;
}
$data = Db::query("
SELECT * FROM `tb_cashier_cart` WHERE
`table_code`= '{$message['table_code']}'");
if(!$data) {
self::gateway_query('sendToClient', [$client_id, json_encode(['msg' => '桌码不存在'])]);
return;
}
$res = self::batch($message);
if($res) {
$status = 1;
}else {
$status = 0;
}
$rand = 'cashier_batch' . Random::build();
$snd_data = [
'msg' => '购物车批量操作',
'operate_type' => 'batch',
'msg_id' => $rand,
'status' => $status,
'type' => 'cashier',
'data_type' => 'cart',
'data' => []
];
self::gateway_query('sendToClient', [$client_id, json_encode($snd_data)]);
}catch (Exception $e) {
Log::write('修改购物车时[error]->>>>>' . $e->getMessage(), 'error');
}
break;
// 锁单
case 'pay_lock':
self::paylock($client_id, $message);
break;
// 解锁
case 'pay_unlock':
self::payunlock($client_id, $message);
break;
// 查询是否锁单
case 'search_pay_lock':
self::searchpaylock($client_id, $message);
break;
}
}
}

View File

@ -0,0 +1,331 @@
<?php
namespace extend\workermans\model;
use ba\Exception;
use ba\Random;
use support\think\Db;
use GatewayWorker\Lib\Gateway;
use think\facade\Log;
use think\Model;
/**
* 管理端
*/
class Manage extends Base
{
public static function handles(string $client_id, array $message):void
{
self::$client_id = $client_id;
self::$shop_id = $message['shop_id'];
// 验证 shop_id 和 table_code 是否存在
$shop = Db::query("
SELECT * FROM `tb_shop_info` WHERE
`id`={$message['shop_id']}
");
if (!$shop) {
self::gateway_query('sendToClient', [$client_id, json_encode(['msg' => '商户信息不存在'])]);
return;
}
// 处理购物车数据
switch ($message['operate_type']) {
// 初始化购物车
case 'init':
$rand = 'manage_init' . Random::build();
$car = [];
if(empty($message['table_code'])) {
$message['table_code'] = 'APC' . Random::build('numeric');
}else {
$car = Db::query("
SELECT * FROM `tb_cashier_cart` WHERE
`shop_id`={$message['shop_id']} AND
`table_code`= '{$message['table_code']}'
");
}
$snd_data = [
'msg' => '管理端代客下单初始化',
'operate_type' => 'manage_init',
'msg_id' => $rand,
'table_code' => $message['table_code'],
'data' => $car
];
self::gateway_query('sendToClient', [$client_id, json_encode($snd_data)]);
break;
// 新增
case 'add':
if(
($message['is_temporary'] == 1 && !empty($message['number'])) ||
(!empty($message['product_id']) &&
!empty($message['sku_id']) &&
!empty($message['number']) )
) {
// 查询购物车是否有重复的商品,有则新增,无则累加 (有赠送品的除外)
try {
if(empty($message['goods_type']) || $message['goods_type'] != 'package') {
if($message['is_temporary'] == 1) {
$car = Db::query("
SELECT * FROM `tb_cashier_cart` WHERE
`shop_id`={$message['shop_id']} AND
`is_gift`={$message['is_gift']} AND
`product_name`='{$message['product_name']}' AND
`is_temporary`={$message['is_temporary']} AND
`table_code`='{$message['table_code']}'
");
}else {
$car = Db::query("
SELECT * FROM `tb_cashier_cart` WHERE
`shop_id`={$message['shop_id']} AND
`sku_id`={$message['sku_id']} AND
`product_id`={$message['product_id']} AND
`is_gift`={$message['is_gift']} AND
`table_code`='{$message['table_code']}'
");
}
}else {
// 如果是套餐商品,直接新增
$car[0] = [];
}
if(empty($car[0])) {
if($message['number'] <= 0) {
self::gateway_query('sendToClient', [$client_id, json_encode(['msg' => '数量不合法'])]);
return;
}
$res = $res_id = self::add_data($message);
}else {
$car = $car[0];
$res_id = $car['id'];
// 如果是新增套餐商品,硬新增
if(!empty($message['pro_group_info'])) {
$res = $res_id = self::add_data($message);
}else {
// 是赠品,新增
if($car['is_gift'] == 1) {
// 如果原本的也是赠送的,则修改数量
if(!empty($message['is_gift']) && $message['is_gift'] == 1) {
$res = self::savenumber($car, $message);
}else {
$res = $res_id = self::add_data($message);
}
}else {
// 如新增的也是赠送的
if(!empty($message['is_gift']) && $message['is_gift'] == 1) {
$res = $res_id = self::add_data($message);
}else {
$res = self::savenumber($car, $message);
}
}
}
}
if($res) {
$status = 1;
}else {
$status = 0;
}
$rand = 'manage_add' . Random::build();
$data = Db::query("
SELECT * FROM `tb_cashier_cart` WHERE
`id`={$res_id}");
// 向此桌码下面的 client_id 发送消息
$snd_data = [
'msg' => '购物车新增',
'operate_type' => 'manage_add',
'msg_id' => $rand,
'status' => $status,
'type' => 'manage',
'data' => $data[0]
];
self::gateway_query('sendToClient', [$client_id, json_encode($snd_data)]);
}catch (Exception $e){
Log::write('新增购物车时[error]->>>>>' . $e->getMessage(), 'error');
}
}
break;
// 修改
case 'edit':
if (empty($message['id'])) {
self::gateway_query('sendToClient', [$client_id, json_encode(['msg' => '购物车ID不存在'])]);
return;
}
try {
$data = Db::query("
SELECT * FROM `tb_cashier_cart` WHERE
`id`={$message['id']}");
if(!$data) {
self::gateway_query('sendToClient', [$client_id, json_encode(['msg' => '购物车不存在'])]);
return;
}
// $message['number'] += $data[0]['number'];
$res = self::edit_data($message);
if($res) {
$status = 1;
$data = Db::query("
SELECT * FROM `tb_cashier_cart` WHERE
`id`={$message['id']}");
}else {
$status = 0;
}
$rand = 'manage_edit' . Random::build();
$snd_data = [
'msg' => '购物车修改',
'operate_type' => 'manage_edit',
'msg_id' => $rand,
'status' => $status,
'type' => 'manage',
'data' => $data[0]
];
self::gateway_query('sendToClient', [$client_id, json_encode($snd_data)]);
}catch (Exception $e) {
Log::write('修改购物车时[error]->>>>>' . $e->getMessage(), 'error');
}
break;
// 删除
case 'del':
if (empty($message['id'])) {
self::gateway_query('sendToClient', [$client_id, json_encode(['msg' => '购物车ID不存在'])]);
return;
}
$data = Db::query("
SELECT * FROM `tb_cashier_cart` WHERE
`id`={$message['id']}");
if (empty($data)) {
self::gateway_query('sendToClient', [$client_id, json_encode(['msg' => '数据不存在'])]);
return;
}
try {
$res = Db::table('tb_cashier_cart')->where('id', $message['id'])->delete();
if($res) {
$status = 1;
}else {
$status = 0;
}
$rand = 'manage_del' . Random::build();
$snd_data = [
'msg' => '购物车删除',
'operate_type' => 'manage_del',
'msg_id' => $rand,
'status' => $status,
'type' => 'manage',
'data' => $data[0]
];
self::gateway_query('sendToClient', [$client_id, json_encode($snd_data)]);
}catch (Exception $e) {
Log::write('删除购物车时[error]->>>>>' . $e->getMessage(), 'error');
}
break;
// 清除
case 'cleanup':
try {
$res = Db::table('tb_cashier_cart')
->where('table_code', $message['table_code'])
->delete();
if($res) {
$status = 1;
}else {
$status = 0;
}
$status = 1;
$rand = 'manage_cleanup' . Random::build();
$snd_data = [
'msg' => '购物车清除',
'operate_type' => 'manage_cleanup',
'msg_id' => $rand,
'status' => $status,
'type' => 'manage',
'data' => [
'table_code' => $message['table_code'],
]
];
self::gateway_query('sendToClient', [$client_id, json_encode($snd_data)]);
}catch (Exception $e) {
Log::write('删除购物车时[error]->>>>>' . $e->getMessage(), 'error');
}
break;
// 转桌
case 'rottable':
if (empty($message['table_code']) || empty($message['new_table_code'])) {
self::gateway_query('sendToClient', [$client_id, json_encode(['msg' => '桌码或新桌码必填'])]);
return;
}
try {
$data = Db::query("
SELECT * FROM `tb_cashier_cart` WHERE
`table_code`='{$message['table_code']}'");
if(!$data) {
self::gateway_query('sendToClient', [$client_id, json_encode(['msg' => '购物车不存在'])]);
return;
}
$res = self::rottable($message);
if($res) {
$status = 1;
}else {
$status = 0;
}
$rand = 'manage_edit' . Random::build();
$snd_data = [
'msg' => '购物车转桌',
'operate_type' => 'rottable',
'msg_id' => $rand,
'status' => $status,
'type' => 'manage',
'data' => [
'table_code' => $message['table_code'],
'new_table_code' => $message['new_table_code'],
]
];
self::gateway_query('sendToClient', [$client_id, json_encode($snd_data)]);
}catch (Exception $e) {
Log::write('修改购物车时[error]->>>>>' . $e->getMessage(), 'error');
}
break;
// 批量操作(打包与不打包)
case 'batch':
try {
if (!isset($message['is_pack'])) {
self::gateway_query('sendToClient', [$client_id, json_encode(['msg' => 'is_pack必填'])]);
return;
}
$data = Db::query("
SELECT * FROM `tb_cashier_cart` WHERE
`table_code`= '{$message['table_code']}'");
if(!$data) {
self::gateway_query('sendToClient', [$client_id, json_encode(['msg' => '桌码不存在'])]);
return;
}
$res = self::batch($message);
if($res) {
$status = 1;
}else {
$status = 0;
}
$rand = 'manage_batch' . Random::build();
$snd_data = [
'msg' => '购物车批量操作',
'operate_type' => 'batch',
'msg_id' => $rand,
'status' => $status,
'type' => 'manage',
'data' => []
];
self::gateway_query('sendToClient', [$client_id, json_encode($snd_data)]);
}catch (Exception $e) {
Log::write('修改购物车时[error]->>>>>' . $e->getMessage(), 'error');
}
break;
// 锁单
case 'pay_lock':
self::paylock($client_id, $message);
break;
// 解锁
case 'pay_unlock':
self::payunlock($client_id, $message);
break;
// 查询是否锁单
case 'search_pay_lock':
self::searchpaylock($client_id, $message);
break;
}
}
}

View File

@ -0,0 +1,332 @@
<?php
namespace extend\workermans\model;
use ba\Exception;
use ba\Random;
use support\think\Db;
use GatewayWorker\Lib\Gateway;
use support\Log;
use think\Model;
/**
* 代客下单(管理端小程序)
*/
class Onboc extends Base
{
public static function handles(string $client_id, array $message):void
{
self::$client_id = $client_id;
self::$shop_id = $message['shop_id'];
// 验证 shop_id 和 table_code 是否存在
$shop = Db::query("
SELECT * FROM `tb_shop_info` WHERE
`id`={$message['shop_id']}
");
if (!$shop) {
self::gateway_query('sendToClient', [$client_id, json_encode(['msg' => '商户信息不存在'])]);
return;
}
// 处理购物车数据
switch ($message['operate_type']) {
// 初始化购物车1
case 'init':
$rand = 'onboc_init' . Random::build();
$car = [];
if(empty($message['table_code'])) {
$message['table_code'] = 'APP' . Random::build('numeric');
}else {
$car = Db::query("
SELECT * FROM `tb_cashier_cart` WHERE
`shop_id`={$message['shop_id']} AND
`table_code`= '{$message['table_code']}'
");
}
$snd_data = [
'msg' => '代客下单初始化',
'operate_type' => 'onboc_init',
'msg_id' => $rand,
'table_code' => $message['table_code'],
'data' => $car
];
self::gateway_query('sendToClient', [$client_id, json_encode($snd_data)]);
break;
// 新增
case 'add':
if(
($message['is_temporary'] == 1 && !empty($message['number'])) ||
(!empty($message['product_id']) &&
!empty($message['sku_id']) &&
!empty($message['number']) )
) {
// 查询购物车是否有重复的商品,有则新增,无则累加 (有赠送品的除外)
try {
if(empty($message['goods_type']) || $message['goods_type'] != 'package') {
if ($message['is_temporary'] == 1) {
$car = Db::query("
SELECT * FROM `tb_cashier_cart` WHERE
`shop_id`={$message['shop_id']} AND
`is_gift`={$message['is_gift']} AND
`product_name`='{$message['product_name']}' AND
`is_temporary`={$message['is_temporary']} AND
`table_code`='{$message['table_code']}'
");
} else {
$car = Db::query("
SELECT * FROM `tb_cashier_cart` WHERE
`shop_id`={$message['shop_id']} AND
`sku_id`={$message['sku_id']} AND
`product_id`={$message['product_id']} AND
`is_gift`={$message['is_gift']} AND
`table_code`='{$message['table_code']}'
");
}
}else {
// 如果是套餐商品,直接新增
$car[0] = [];
}
if(empty($car[0])) {
if($message['number'] <= 0) {
self::gateway_query('sendToClient', [$client_id, json_encode(['msg' => '数量不合法'])]);
return;
}
$res = $res_id = self::add_data($message);
}else {
$car = $car[0];
$res_id = $car['id'];
// 如果是新增套餐商品,硬新增
if(!empty($message['pro_group_info'])) {
$res = $res_id = self::add_data($message);
}else {
// 是赠品,新增
if($car['is_gift'] == 1) {
// 如果原本的也是赠送的,则修改数量
if(!empty($message['is_gift']) && $message['is_gift'] == 1) {
$res = self::savenumber($car, $message);
}else {
$res = $res_id = self::add_data($message);
}
}else {
// 如新增的也是赠送的
if(!empty($message['is_gift']) && $message['is_gift'] == 1) {
$res = $res_id = self::add_data($message);
}else {
$res = self::savenumber($car, $message);
}
}
}
}
if($res) {
$status = 1;
}else {
$status = 0;
}
$rand = 'onboc_add' . Random::build();
$data = Db::query("
SELECT * FROM `tb_cashier_cart` WHERE
`id`={$res_id}");
print_r('数据结果' . json_encode($data[0]) . "\r\n");
// 向此桌码下面的 client_id 发送消息
$snd_data = [
'msg' => '购物车新增',
'operate_type' => 'onboc_add',
'msg_id' => $rand,
'status' => $status,
'type' => 'onboc',
'data' => $data[0]
];
self::gateway_query('sendToClient', [$client_id, json_encode($snd_data)]);
}catch (Exception $e){
Log::write('新增购物车时[error]->>>>>' . $e->getMessage(), 'error');
}
}
break;
// 修改
case 'edit':
if (empty($message['id'])) {
self::gateway_query('sendToClient', [$client_id, json_encode(['msg' => '购物车ID不存在'])]);
return;
}
try {
$data = Db::query("
SELECT * FROM `tb_cashier_cart` WHERE
`id`={$message['id']}");
if(!$data) {
self::gateway_query('sendToClient', [$client_id, json_encode(['msg' => '购物车不存在'])]);
return;
}
// $message['number'] += $data[0]['number'];
$res = self::edit_data($message);
if($res) {
$status = 1;
$data = Db::query("
SELECT * FROM `tb_cashier_cart` WHERE
`id`={$message['id']}");
}else {
$status = 0;
}
$rand = 'onboc_edit' . Random::build();
$snd_data = [
'msg' => '购物车修改',
'operate_type' => 'onboc_edit',
'msg_id' => $rand,
'status' => $status,
'type' => 'onboc',
'data' => $data[0]
];
self::gateway_query('sendToClient', [$client_id, json_encode($snd_data)]);
}catch (Exception $e) {
Log::write('修改购物车时[error]->>>>>' . $e->getMessage(), 'error');
}
break;
// 删除
case 'del':
if (empty($message['id'])) {
self::gateway_query('sendToClient', [$client_id, json_encode(['msg' => '购物车ID不存在'])]);
return;
}
try {
$data = Db::query("
SELECT * FROM `tb_cashier_cart` WHERE
`id`={$message['id']}");
if (empty($data)) {
self::gateway_query('sendToClient', [$client_id, json_encode(['msg' => '数据不存在'])]);
return;
}
$res = Db::table('tb_cashier_cart')->where('id', $message['id'])->delete();
if($res) {
$status = 1;
}else {
$status = 0;
}
$rand = 'onboc_del' . Random::build();
$snd_data = [
'msg' => '购物车删除',
'operate_type' => 'onboc_del',
'msg_id' => $rand,
'status' => $status,
'type' => 'onboc',
'data' => $data[0]
];
self::gateway_query('sendToClient', [$client_id, json_encode($snd_data)]);
}catch (Exception $e) {
Log::write('删除购物车时[error]->>>>>' . $e->getMessage(), 'error');
}
break;
// 清除
case 'cleanup':
try {
$res = Db::table('tb_cashier_cart')
->where('table_code', $message['table_code'])
->delete();
if($res) {
$status = 1;
}else {
$status = 0;
}
$status = 1;
$rand = 'onboc_cleanup' . Random::build();
$snd_data = [
'msg' => '购物车清除',
'operate_type' => 'onboc_cleanup',
'msg_id' => $rand,
'status' => $status,
'type' => 'onboc',
'data' => [
'table_code' => $message['table_code'],
]
];
self::gateway_query('sendToClient', [$client_id, json_encode($snd_data)]);
}catch (Exception $e) {
Log::write('删除购物车时[error]->>>>>' . $e->getMessage(), 'error');
}
break;
case 'rottable':
if (empty($message['table_code']) || empty($message['new_table_code'])) {
self::gateway_query('sendToClient', [$client_id, json_encode(['msg' => '桌码或新桌码必填'])]);
return;
}
try {
$data = Db::query("
SELECT * FROM `tb_cashier_cart` WHERE
`table_code`='{$message['table_code']}'");
if(!$data) {
self::gateway_query('sendToClient', [$client_id, json_encode(['msg' => '购物车不存在'])]);
return;
}
$res = self::rottable($message);
if($res) {
$status = 1;
}else {
$status = 0;
}
$rand = 'onboc_edit' . Random::build();
$snd_data = [
'msg' => '购物车转桌',
'operate_type' => 'rottable',
'msg_id' => $rand,
'status' => $status,
'type' => 'onboc',
'data' => [
'table_code' => $message['table_code'],
'new_table_code' => $message['new_table_code'],
]
];
self::gateway_query('sendToClient', [$client_id, json_encode($snd_data)]);
}catch (Exception $e) {
Log::write('修改购物车时转桌[error]->>>>>' . $e->getMessage(), 'error');
}
break;
// 批量操作(打包与不打包)
case 'batch':
try {
if (!isset($message['is_pack'])) {
self::gateway_query('sendToClient', [$client_id, json_encode(['msg' => 'is_pack必填'])]);
return;
}
$data = Db::query("
SELECT * FROM `tb_cashier_cart` WHERE
`table_code`= '{$message['table_code']}'");
if(!$data) {
self::gateway_query('sendToClient', [$client_id, json_encode(['msg' => '桌码不存在'])]);
return;
}
$res = self::batch($message);
if($res) {
$status = 1;
}else {
$status = 0;
}
$rand = 'onboc_batch' . Random::build();
$snd_data = [
'msg' => '购物车批量操作',
'operate_type' => 'batch',
'msg_id' => $rand,
'status' => $status,
'type' => 'onboc',
'data' => []
];
self::gateway_query('sendToClient', [$client_id, json_encode($snd_data)]);
}catch (Exception $e) {
Log::write('修改购物车时[error]->>>>>' . $e->getMessage(), 'error');
}
break;
// 锁单
case 'pay_lock':
self::paylock($client_id, $message);
break;
// 解锁
case 'pay_unlock':
self::payunlock($client_id, $message);
break;
// 查询是否锁单
case 'search_pay_lock':
self::searchpaylock($client_id, $message);
break;
}
}
}

View File

@ -0,0 +1,346 @@
<?php
namespace extend\workermans\model;
use ba\Exception;
use ba\Random;
Use support\think\Db;
use support\Log;
/**
* Pad
*/
class Pad extends Base
{
/**
* @param string $client_id
* @param array $message
* @return void
*/
public static function handles(string $client_id, array $message):void
{
self::$client_id = $client_id;
self::$shop_id = $message['shop_id'];
// 验证 shop_id 和 table_code 是否存在
$shop = Db::query("
SELECT * FROM `tb_shop_info` WHERE
`id`={$message['shop_id']}
");
if (!$shop) {
self::gateway_query('sendToClient', [$client_id, json_encode(['msg' => '商户信息不存在'])]);
return;
}
// 处理购物车数据
switch ($message['operate_type']) {
// 初始化购物车
case 'init':
$rand = 'pad_init' . Random::build();
$car = [];
if(empty($message['table_code'])) {
$message['table_code'] = 'PAD' . Random::build('numeric');
}else {
$car = Db::query("
SELECT * FROM `tb_cashier_cart` WHERE
`shop_id`={$message['shop_id']} AND
`table_code`='{$message['table_code']}'
");
}
$snd_data = [
'msg' => 'pad初始化',
'type' => 'pad',
'operate_type' => 'pad_init',
'data_type' => 'cart',
'status' => 1,
'msg_id' => $rand,
'table_code' => $message['table_code'],
'data' => $car
];
self::gateway_query('sendToClient', [$client_id, json_encode($snd_data)]);
break;
// 新增
case 'add':
if(
($message['is_temporary'] == 1 && !empty($message['number'])) ||
(!empty($message['product_id']) &&
!empty($message['sku_id']) &&
!empty($message['number']) )
) {
// 查询购物车是否有重复的商品,有则新增,无则累加 (有赠送品的除外)
try {
if(empty($message['goods_type']) || $message['goods_type'] != 'package') {
if($message['is_temporary'] == 1) {
$car = Db::query("
SELECT * FROM `tb_cashier_cart` WHERE
`shop_id`={$message['shop_id']} AND
`is_gift`={$message['is_gift']} AND
`product_name`='{$message['product_name']}' AND
`is_temporary`={$message['is_temporary']} AND
`table_code`= '{$message['table_code']}'
");
}else {
$car = Db::query("
SELECT * FROM `tb_cashier_cart` WHERE
`shop_id`={$message['shop_id']} AND
`sku_id`={$message['sku_id']} AND
`product_id`={$message['product_id']} AND
`is_gift`={$message['is_gift']} AND
`table_code`= '{$message['table_code']}'
");
}
}else {
// 如果是套餐商品,直接新增
$car[0] = [];
}
if(empty($car[0])) {
if($message['number'] <= 0) {
self::gateway_query('sendToClient', [$client_id, json_encode(['msg' => '数量不合法'])]);
return;
}
$res = $res_id = self::add_data($message);
}else {
$car = $car[0];
$res_id = $car['id'];
// 如果是新增套餐商品,硬新增
if(!empty($message['pro_group_info'])) {
$res = self::add_data($message);
}else {
// 是赠品,新增
if($car['is_gift'] == 1) {
// 如果原本的也是赠送的,则修改数量
if(!empty($message['is_gift']) && $message['is_gift'] == 1) {
$res = self::savenumber($car, $message);
}else {
$res = self::add_data($message);
}
}else {
// 如新增的也是赠送的
if(!empty($message['is_gift']) && $message['is_gift'] == 1) {
$res = self::add_data($message);
}else {
$res = self::savenumber($car, $message);
}
}
}
}
if($res) {
$status = 1;
}else {
$status = 0;
}
$rand = 'pad_add' . Random::build();
$data = Db::query("
SELECT * FROM `tb_cashier_cart` WHERE
`id`={$res_id}");
// 向此桌码下面的 client_id 发送消息
$snd_data = [
'msg' => '购物车新增',
'type' => 'pad',
'status' => $status,
'operate_type' => 'pad_add',
'data_type' => 'cart',
'msg_id' => $rand,
'data' => $data[0]
];
self::gateway_query('sendToClient', [$client_id, json_encode($snd_data)]);
}catch (Exception $e){
Log::write('新增购物车时[error]->>>>>' . $e->getMessage(), 'error');
}
}
break;
// 修改
case 'edit':
if (empty($message['id'])) {
self::gateway_query('sendToClient', [$client_id, json_encode(['msg' => '购物车ID不存在'])]);
return;
}
try {
$data = Db::query("
SELECT * FROM `tb_cashier_cart` WHERE
`id`={$message['id']}");
if(!$data) {
self::gateway_query('sendToClient', [$client_id, json_encode(['msg' => '购物车不存在'])]);
return;
}
// $message['number'] += $data[0]['number'];
$res = self::edit_data($message);
if($res) {
$status = 1;
}else {
$status = 0;
}
$rand = 'pad_edit' . Random::build();
if($res) {
$data = Db::query("
SELECT * FROM `tb_cashier_cart` WHERE
`id`={$message['id']}");
}else {
$data[0] = '';
}
$snd_data = [
'msg' => '购物车修改',
'type' => 'pad',
'status' => $status,
'operate_type' => 'pad_edit',
'data_type' => 'cart',
'msg_id' => $rand,
'data' => $data[0]
];
self::gateway_query('sendToClient', [$client_id, json_encode($snd_data)]);
}catch (Exception $e) {
Log::write('修改购物车时[error]->>>>>' . $e->getMessage(), 'error');
}
break;
// 删除
case 'del':
if (empty($message['id'])) {
self::gateway_query('sendToClient', [$client_id, json_encode(['msg' => '购物车ID不存在'])]);
return;
}
$data = Db::query("
SELECT * FROM `tb_cashier_cart` WHERE
`id`={$message['id']}");
if (empty($data)) {
self::gateway_query('sendToClient', [$client_id, json_encode(['msg' => '数据不存在'])]);
return;
}
try {
$res = Db::table('tb_cashier_cart')->where('id', $message['id'])->delete();
if($res) {
$status = 1;
}else {
$status = 0;
}
$rand = 'pad_del' . Random::build();
$snd_data = [
'msg' => '购物车删除',
'type' => 'pad',
'status' => $status,
'operate_type' => 'pad_del',
'data_type' => 'cart',
'msg_id' => $rand,
'data' => $data[0]
];
self::gateway_query('sendToClient', [$client_id, json_encode($snd_data)]);
}catch (Exception $e) {
Log::write('删除购物车时[error]->>>>>' . $e->getMessage(), 'error');
}
break;
// 清除
case 'cleanup':
try {
$res = Db::table('tb_cashier_cart')
->where('table_code', $message['table_code'])
->delete();
if($res) {
$status = 1;
}else {
$status = 0;
}
$status = 1;
$rand = 'shopping_cleanup' . Random::build();
$snd_data = [
'msg' => '购物车清除',
'operate_type' => 'pad_cleanup',
'msg_id' => $rand,
'data_type' => 'cart',
'status' => $status,
'data' => [
'table_code' => $message['table_code'],
]
];
self::gateway_query('sendToClient', [$client_id, json_encode($snd_data)]);
}catch (Exception $e) {
Log::write('删除购物车时[error]->>>>>' . $e->getMessage(), 'error');
}
break;
// 转桌
case 'rottable':
if (empty($message['table_code']) || empty($message['new_table_code'])) {
self::gateway_query('sendToClient', [$client_id, json_encode(['msg' => '桌码或新桌码必填必填'])]);
return;
}
try {
$data = Db::query("
SELECT * FROM `tb_cashier_cart` WHERE
`table_code`= '{$message['table_code']}'");
if(!$data) {
self::gateway_query('sendToClient', [$client_id, json_encode(['msg' => '购物车不存在'])]);
return;
}
$res = self::rottable($message);
if($res) {
$status = 1;
}else {
$status = 0;
}
$rand = 'pad_rottable' . Random::build();
$snd_data = [
'msg' => '购物车转桌',
'operate_type' => 'pad_rottable',
'msg_id' => $rand,
'status' => $status,
'type' => 'pad',
'data_type' => 'cart',
'data' => [
'table_code' => $message['table_code'],
'new_table_code' => $message['new_table_code'],
]
];
self::gateway_query('sendToClient', [$client_id, json_encode($snd_data)]);
}catch (Exception $e) {
Log::write('修改购物车时[error]->>>>>' . $e->getMessage(), 'error');
}
break;
// 批量操作(打包与不打包)
case 'batch':
try {
if (!isset($message['is_pack'])) {
self::gateway_query('sendToClient', [$client_id, json_encode(['msg' => 'is_pack必填'])]);
return;
}
$data = Db::query("
SELECT * FROM `tb_cashier_cart` WHERE
`table_code`= '{$message['table_code']}'");
if(!$data) {
self::gateway_query('sendToClient', [$client_id, json_encode(['msg' => '桌码不存在'])]);
return;
}
$res = self::batch($message);
if($res) {
$status = 1;
}else {
$status = 0;
}
$rand = 'pad_batch' . Random::build();
$snd_data = [
'msg' => '购物车批量操作',
'operate_type' => 'pad_batch',
'msg_id' => $rand,
'status' => $status,
'type' => 'pad',
'data_type' => 'cart',
'data' => []
];
self::gateway_query('sendToClient', [$client_id, json_encode($snd_data)]);
}catch (Exception $e) {
Log::write('修改购物车时[error]->>>>>' . $e->getMessage(), 'error');
}
break;
// 锁单
case 'pay_lock':
self::paylock($client_id, $message);
break;
// 解锁
case 'pay_unlock':
self::payunlock($client_id, $message);
break;
// 查询是否锁单
case 'search_pay_lock':
self::searchpaylock($client_id, $message);
break;
}
}
}

View File

@ -0,0 +1,16 @@
<?php
namespace extend\workermans\model;
use support\Redis;
/**
* 购物车
*/
class RedisInit extends Base
{
public static function inits()
{
self::$redis = Redis::connection();
}
}

View File

@ -0,0 +1,311 @@
<?php
namespace extend\workermans\model;
use Exception;
use ba\Random;
use support\think\Db;
use GatewayWorker\Lib\Gateway;
use support\Log;
/**
* 购物车
*/
class Shopping extends Base
{
/**
* @param string $client_id
* @param array $message
* @return void
*/
public static function handles(string $client_id, array $message):void
{
self::$client_id = $client_id;
self::$shop_id = $message['shop_id'];
$db = self::$db;
// 验证 shop_id 和 table_code 是否存在
$shop = Db::query("
SELECT * FROM `tb_shop_info` WHERE
`id`={$message['shop_id']}
");
if (!$shop) {
self::gateway_query('sendToClient', [$client_id, json_encode(['msg' => '商户信息不存在'])]);
return;
}
if(!empty($message['new_table_code'])) {
$table_code = $message['new_table_code'];
}else {
$table_code = $message['table_code'];
}
// $table = Db::query("
// SELECT * FROM `tb_shop_table` WHERE
// `table_code`= '{$table_code}'
// ");
// if (!$table) {
// self::gateway_query('sendToClient', [$client_id, json_encode(['msg' => '桌台信息不存在'])]);
// return;
// }
if(empty($message['table_code'])) {
$message['table_code'] = 'PRO' . Random::build('numeric');
}
// 处理购物车数据
switch ($message['operate_type']) {
// 初始化购物车
case 'init':
// 商户ID 和桌码ID
$table_code = self::get_shopping_send_id($message);
// 绑定桌码和 client_id
Gateway::bindUid($client_id, $table_code);
$rand = 'shopping_init' . Random::build();
$car = Db::query("
SELECT * FROM `tb_cashier_cart` WHERE
`shop_id`={$message['shop_id']} AND
`table_code`='{$message['table_code']}'
");
$snd_data = [
'msg' => '购物车初始化',
'operate_type' => 'init',
'msg_id' => $rand,
'type' => 'shopping',
'table_code' => $message['table_code'],
'data' => $car
];
self::gateway_query('sendToClient', [$client_id, json_encode($snd_data)]);
break;
// 新增
case 'add':
if(
!empty($message['product_id']) &&
!empty($message['sku_id']) &&
!empty($message['number'])
) {
// 查询购物车是否有重复的商品,有则新增,无则累加 (有赠送品的除外)
try {
if(empty($message['goods_type']) || $message['goods_type'] != 'package') {
$car = Db::query("
SELECT * FROM `tb_cashier_cart` WHERE
`shop_id`={$message['shop_id']} AND
`sku_id`={$message['sku_id']} AND
`product_id`={$message['product_id']} AND
`table_code`='{$message['table_code']}'
");
}else {
// 如果是套餐商品,直接新增
$car[0] = [];
}
if(empty($car[0])) {
if($message['number'] <= 0) {
self::gateway_query('sendToClient', [$client_id, json_encode(['msg' => '数量不合法'])]);
return;
}
$res = $res_id = self::add_data($message);
}else {
$car = $car[0];
$res_id = $car['id'];
// 如果是新增套餐商品,硬新增
if(!empty($message['pro_group_info'])) {
$res = $res_id = self::add_data($message);
}else {
// 是赠品,新增
if($car['is_gift'] == 1) {
// 如果原本的也是赠送的,则修改数量
if(!empty($message['is_gift']) && $message['is_gift'] == 1) {
$res = self::savenumber($car, $message);
}else {
$res = $res_id = self::add_data($message);
}
}else {
// 如新增的也是赠送的
if(!empty($message['is_gift']) && $message['is_gift'] == 1) {
$res = $res_id = self::add_data($message);
}else {
$res = self::savenumber($car, $message);
}
}
}
}
if($res) {
$status = 1;
}else {
$status = 0;
}
$rand = 'shopping_add' . Random::build();
$data = Db::query("
SELECT * FROM `tb_cashier_cart` WHERE
`id`={$res_id}");
// 向此桌码下面的 client_id 发送消息
$snd_data = [
'msg' => '购物车新增',
'operate_type' => 'add',
'msg_id' => $rand,
'type' => 'shopping',
'status' => $status,
'data' => $data[0]
];
$s_id = self::get_shopping_send_id($message);
self::gateway_query('sendToUid', [$s_id, json_encode($snd_data)]);
}catch (Exception $e){
Log::write('新增购物车时[error]->>>>>' . $e->getMessage(), 'error');
}
}
break;
// 修改
case 'edit':
if (empty($message['id'])) {
self::gateway_query('sendToClient', [$client_id, json_encode(['msg' => '购物车ID必传'])]);
return;
}
try {
$data = Db::query("
SELECT * FROM `tb_cashier_cart` WHERE
`id`={$message['id']}");
if(!$data) {
self::gateway_query('sendToClient', [$client_id, json_encode(['msg' => '购物车不存在, 请检查购物车ID是否正确'])]);
return;
}
// $message['number'] += $data[0]['number'];
$message_edit = [
'number' => $message['number'],
'id' => $message['id'],
];
$res = self::edit_data($message_edit);
$s_id = self::get_shopping_send_id($message);
$rand = 'shopping_edit' . Random::build();
if($res) {
$status = 1;
$data = Db::query("
SELECT * FROM `tb_cashier_cart` WHERE
`id`={$message['id']}");
}else {
$status = 0;
}
$snd_data = [
'msg' => '购物车修改',
'operate_type' => 'edit',
'msg_id' => $rand,
'type' => 'shopping',
'status' => $status,
'data' => $data[0]
];
self::gateway_query('sendToUid', [$s_id, json_encode($snd_data)]);
}catch (Exception $e) {
Log::write('修改购物车时[error]->>>>>' . $e->getMessage(), 'error');
}
break;
// 删除
case 'del':
if (empty($message['id'])) {
self::gateway_query('sendToClient', [$client_id, json_encode(['msg' => '购物车ID不存在'])]);
return;
}
$data = Db::query("
SELECT * FROM `tb_cashier_cart` WHERE
`id`={$message['id']}");
if (empty($data)) {
self::gateway_query('sendToClient', [$client_id, json_encode(['msg' => '数据不存在'])]);
return;
}
try {
$res = Db::table('tb_cashier_cart')->where('id,', $message['id'])->delete();
if($res) {
$status = 1;
}else {
$status = 0;
}
$s_id = self::get_shopping_send_id($message);
$rand = 'shopping_del' . Random::build();
$snd_data = [
'msg' => '购物车删除',
'operate_type' => 'del',
'msg_id' => $rand,
'type' => 'shopping',
'status' => $status,
'data' => $data[0]
];
self::gateway_query('sendToUid', [$s_id, json_encode($snd_data)]);
}catch (\Exception $e) {
Log::write('删除购物车时[error]->>>>>' . $e->getMessage(), 'error');
}
break;
// 清除
case 'cleanup':
try {
$res = Db::table('tb_cashier_cart')->where('table_code', $message['table_code'])->delete();
if($res) {
$status = 1;
}else {
$status = 0;
}
$status = 1;
$s_id = self::get_shopping_send_id($message);
$rand = 'shopping_cleanup' . Random::build();
$snd_data = [
'msg' => '购物车清除',
'operate_type' => 'cleanup',
'msg_id' => $rand,
'type' => 'shopping',
'status' => $status,
'data' => [
'table_code' => $message['table_code'],
]
];
self::gateway_query('sendToUid', [$s_id, json_encode($snd_data)]);
}catch (Exception $e) {
Log::write('删除购物车时[error]->>>>>' . $e->getMessage(), 'error');
}
break;
// 批量操作(打包与不打包)
case 'batch':
try {
if (!isset($message['is_pack'])) {
self::gateway_query('sendToClient', [$client_id, json_encode(['msg' => 'is_pack必填'])]);
return;
}
$data = Db::query("
SELECT * FROM `tb_cashier_cart` WHERE
`table_code`= '{$message['table_code']}'");
if(!$data) {
self::gateway_query('sendToClient', [$client_id, json_encode(['msg' => '桌码不存在'])]);
return;
}
$res = self::batch($message);
if($res) {
$status = 1;
}else {
$status = 0;
}
$rand = 'shopping_batch' . Random::build();
$snd_data = [
'msg' => '购物车批量操作',
'operate_type' => 'batch',
'msg_id' => $rand,
'status' => $status,
'type' => 'shopping',
'data' => []
];
self::gateway_query('sendToClient', [$client_id, json_encode($snd_data)]);
}catch (Exception $e) {
Log::write('打包购物车时[error]->>>>>' . $e->getMessage(), 'error');
}
break;
// 锁单
case 'pay_lock':
self::paylock($client_id, $message);
break;
// 解锁
case 'pay_unlock':
self::payunlock($client_id, $message);
break;
// 查询是否锁单
case 'search_pay_lock':
self::searchpaylock($client_id, $message);
break;
}
}
}

View File

@ -0,0 +1,336 @@
<?php
namespace plugin\webman\gateway;
use ba\Random;
use extend\workermans\model\Base;
use GatewayWorker\Lib\Gateway;
use support\Redis;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
use Workerman\Timer;
use Workerman\Worker;
use extend\workermans\model\Cashier;
use extend\workermans\model\Manage;
use extend\workermans\model\Onboc;
use extend\workermans\model\Pad;
use extend\workermans\model\RedisInit;
use extend\workermans\model\Shopping;
class Events
{
public static $redis = null;
public static $db = null;
public static function onWorkerStart($worker)
{
// $url = 'http://127.0.0.1:8686/?method=sendToUid&account=101&params={"data_type":"order","order_id":"2541"}';
// $url = 'https://sockets.sxczgkj.com/s/account/overview';
// 启动redis
RedisInit::inits();
// 开启内部通讯接口。便于内部通讯
$http_worker = new Worker('http://127.0.0.1:8686');
$http_worker->reusePort = true;
$redis = Base::$redis;
$http_worker->onMessage = function (TcpConnection $connection, Request $request) use($redis) {
$method = $request->get('method');
$account = $request->get('account');
$params = $request->get('params');
if (method_exists(Gateway::class, $method)) {
call_user_func_array([Gateway::class, $method], [$account, $params]);
$params_arr = json_decode($params, true);
// 如果是订单打印并且通过uid推送, 保存redis
if($params_arr['operate_type'] == 'order_print' && $method == 'sendToUid') {
$redis->get($params_arr['send_id'], function ($result)use($params_arr, $params){
if($result) {
$msg_id_arr = json_decode($result, true);
$msg_id_arr_c = count($msg_id_arr);
$msg_id_arr[$msg_id_arr_c] = $params_arr;
$result_n = json_encode($msg_id_arr);
Base::setredis_new($result_n, $params_arr['send_id']);
}else {
$params_arr_n[] = $params_arr;
print_r('数组-------->' . json_encode($params_arr_n)) . "\r\n";
Base::setredis_new(json_encode($params_arr_n), $params_arr['send_id']);
}
});
}
return $connection->send('ok');
}
return $connection->send('fail');
};
$http_worker->listen();
if($worker->id == 1) {
print_r('定时器');
// 启动定时器 定时器处理消息回执/在线列表
$_SESSION['auth_timer_id'] = Timer::add(10, function (){
// print_r('时间--->' . date('Y-m-d H:i:s') . "\r\n");
// print_r( "\r\n");
Base::geteventredis_new();
});
}
}
public static function onConnect($client_id)
{
print_r('连接--我是' . $client_id . "\r\n");
Base::add_log_file('当前在线连接总数:' . Gateway::getAllClientCount());
Base::add_total_number($client_id, null, 'total');
}
public static function onWebSocketConnect($client_id, $data)
{
}
public static function onMessage($client_id, $message)
{
$m = $message;
$message = json_decode($message, true);
if(empty($message['type'])) {
Gateway::sendToClient($client_id, json_encode(['msg' => '收到了']));
return;
}
if($message['type'] == 'ping_interval') {
// 记录心跳
if(!empty($message['set'])) {
switch ($message['set']) {
case 'onboc':
Base::add_log_file($m, 'onboc', true);
break;
case 'manage':
Base::add_log_file($m, 'manage', true);
break;
case 'shopping':
Base::add_log_file($m, 'shopping', true);
break;
case 'cashier':
Base::add_log_file($m, 'cashier', true);
break;
case 'pad':
Base::add_log_file($m, 'pad', true);
break;
default:
Base::add_log_file($m, 'other', true);
}
}
Gateway::sendToClient($client_id, json_encode(['msg' => 'ok', 'msg_id' => 'ping_interval']));
return;
}
$type = $message['type'];
if(!empty($message['is_temporary']) && (empty($message['product_name']))) {
Gateway::sendToClient($client_id, json_encode(['msg' => '临时菜请添加菜名']));
return;
}
// 只在初始化的时候绑定
if(!empty($message['operate_type']) && $message['operate_type'] == 'init') {
// 添加在线客户端数量
Base::add_total_number($client_id, $type);
if(!empty($message['shop_id'])) {
if(!empty($message['table_code'])) {
// 绑定shopid和table_code 便于推送多端购物车同步 和 锁单
$group = Base::get_shopping_save_uid($message['shop_id'], $message['table_code']);
if(!empty($_SESSION[$client_id])) {
// 绑定之前必须先删除此client_id下的其他分组
Gateway::leaveGroup($client_id, $_SESSION[$client_id]);
}
Gateway::joinGroup($client_id, $group);
$_SESSION[$client_id] = $group;
}
// 绑定shopid推送商品更新信息
Gateway::joinGroup($client_id, 'product_update' . $message['shop_id']);
}
}
if(!empty($message['operate_type']) && in_array($message['operate_type'], ['add', 'cleanup', 'batch', 'pay_lock', 'search_pay_lock', 'pay_unlock']) && empty($message['table_code'])) {
Gateway::sendToClient($client_id, json_encode(['msg' => 'table_code必传']));
return;
}
// 清空历史订单
if(!empty($message['operate_type']) && $message['operate_type'] == 'clearOrder') {
$status = 1;
$s_id = base::get_shopping_send_id($message);
$rand = 'clearOrder' . Random::build();
$snd_data = [
'msg' => '历史订单清除',
'operate_type' => 'clearOrder',
'msg_id' => $rand,
'type' => 'clearOrder',
'status' => $status,
'data' => [
'table_code' => $message['table_code'],
]
];
base::$shop_id = $message['shop_id'];
base::$client_id = $client_id;
base::gateway_query('sendToUid', [$s_id, json_encode($snd_data)]);
return;
}
// 如果是新增或者编辑,查询库存够不够
if ((!empty($message['operate_type']) && ($message['operate_type'] == 'add' || $message['operate_type'] == 'edit')) && (!empty($message['product_id']) && !empty($message['shop_id']) && !empty($message['number']))) {
$gate_way = GateWay::class;
$number = $message['number'];
try {
$redis = self::$redis;
$redis->connect(Redis::$redis_host, 6379);
$redis->auth(Redis::$password);
$redis->select(3);
$red_number = $redis->get('shop:' . $message['shop_id'] . ':product-stock:' . $message['product_id']);
}catch (\RedisException $e) {
print_r( "Redis 错误: " . $e->getMessage() . "\r\n");
}
$redis->close();
print_r('库存数量-->' . $red_number . "\r\n" . date('Y-m-d H:i:s'));
if(is_numeric($red_number)) {
// 起售数量和库存之间的处理
if(!empty($message['suitNum']) && $message['suitNum'] > 1) {
if($red_number < $message['suitNum']) {
$snd_data = [
'msg' => '此商品库存不足起售数量',
'operate_type' => $message['operate_type'],
'msg_id' => 'no_suit_num' . Random::build(),
'type' => 'no_suit_num',
'data_type' => 'cart',
'id' => $message['id'],
'product_id' => $message['product_id'],
'status' => 0,
'data' => []
];
print_r('此商品库存不足起售数量' . "\r\n" . date('Y-m-d H:i:s'));
$gate_way::sendToClient($client_id, json_encode($snd_data));
return;
}
}
$data = [];
// 如果是编辑,拿到已有数量
if($message['operate_type'] == 'edit' && !empty($message['id'])) {
$data = Base::$db->query("
SELECT * FROM `tb_cashier_cart` WHERE
`id`={$message['id']}");
if($data) {
// 如果编辑数量 小于已有数量并且大于库存数量 直接改成库存数量
if($number < $data[0]['number'] && $number > $red_number) {
$number = $red_number;
$message['number'] = $red_number;
}
}
}
$d_data = false;
$product = Base::$db->query("
SELECT * FROM `tb_product` WHERE
`id`={$message['product_id']}");
// 如果是套餐商品, 拿到商品总数量
if(!empty($message['goods_type']) && $message['goods_type'] == 'package') {
if($product) {
if($product[0]['group_type'] == 1) {
$d_data = true;
}
}
}
if($product) {
if($product[0]['type'] == 'sku') {
if($data) {
if($message['number'] > $data[0]['number']) {
$d_data = true;
}
}
if(!empty($message['operate_type']) && $message['operate_type'] == 'add') {
$d_data = true;
}
}
}
if($d_data) {
$data_number = Base::$db->query("
SELECT SUM(number) number FROM `tb_cashier_cart` WHERE
`shop_id`={$message['shop_id']} AND
`product_id`={$message['product_id']} AND
`table_code`='{$message['table_code']}'
");
if($data_number) {
print_r('已有数量' . $data_number[0]['number'] . "\r\n" . date('Y-m-d H:i:s'));
$number += $data_number[0]['number'];
if($data && $number > $data[0]['number']) {
$number -= $data[0]['number'];
}
}
}
print_r('实际数量' . $number . "\r\n" . date('Y-m-d H:i:s'));
if($red_number < $number) {
$snd_data = [
'msg' => '此商品库存不足',
'operate_type' => $message['operate_type'],
'msg_id' => 'out_of_stock' . Random::build(),
'type' => 'out_of_stock',
'id' => !empty($message['id'])?$message['id']:'',
'data_type' => 'cart',
'status' => 0,
'data' => []
];
$gate_way::sendToClient($client_id, json_encode($snd_data));
return;
}
}
}
if(!empty($type)) {
switch ($type) {
// 收银机
case 'cashier':
Base::add_log_file($m, 'cashier');
// 商户账号(ID)
if(!empty($message['account']) && !empty($message['shop_id']) && $message['operate_type']){
Cashier::handles($client_id, $message);
}
break;
// pad
case 'pad':
Base::add_log_file($m, 'pad');
// 商户账号(ID)
if(!empty($message['account']) && !empty($message['shop_id']) && $message['operate_type']){
Pad::handles($client_id, $message);
}
break;
// 购物车
case 'shopping':
Base::add_log_file($m, 'shopping');
// 桌码ID 和 商户ID 必须同时存在
if(!empty($message['shop_id']) && $message['operate_type']) {
Shopping::handles($client_id, $message);
}
break;
// 管理端小程序代客下单
case 'onboc':
Base::add_log_file($m, 'onboc');
// 商户账号(ID)
if(!empty($message['account']) && !empty($message['shop_id']) && $message['operate_type']){
Onboc::handles($client_id, $message);
}
break;
// PC管理端代客下单
case 'manage':
Base::add_log_file($m, 'manage');
// 商户账号(ID)
if(!empty($message['account']) && !empty($message['shop_id']) && $message['operate_type']){
Manage::handles($client_id, $message);
}
break;
// 消息回执
case 'receipt':
if(!empty($message['msg_id']) && $message['msg_id'] != 'ping_interval') {
Base::delredis_new($client_id, $message['msg_id']);
}
break;
}
}
}
public static function onClose($client_id)
{
// print_r('session----' . json_encode($_SESSION, JSON_UNESCAPED_UNICODE) , "\r\n");
// Timer::del($_SESSION['auth_timer_id']);
Base::add_log_file('关闭-当前在线连接总数:' . Gateway::getAllClientCount());
Base::add_total_number($client_id);
$_SESSION[$client_id] = '';
}
}

73
webman Normal file
View File

@ -0,0 +1,73 @@
#!/usr/bin/env php
<?php
use Webman\Config;
use Webman\Console\Command;
use Webman\Console\Util;
use support\Container;
if (!Phar::running()) {
chdir(__DIR__);
}
require_once __DIR__ . '/vendor/autoload.php';
if (!$appConfigFile = config_path('app.php')) {
throw new RuntimeException('Config file not found: app.php');
}
$appConfig = require $appConfigFile;
if ($timezone = $appConfig['default_timezone'] ?? '') {
date_default_timezone_set($timezone);
}
if ($errorReporting = $appConfig['error_reporting'] ?? '') {
error_reporting($errorReporting);
}
if (!in_array($argv[1] ?? '', ['start', 'restart', 'stop', 'status', 'reload', 'connections'])) {
require_once __DIR__ . '/support/bootstrap.php';
} else {
if (class_exists('Support\App')) {
Support\App::loadAllConfig(['route']);
} else {
Config::reload(config_path(), ['route', 'container']);
}
}
$cli = new Command();
$cli->setName('webman cli');
$cli->installInternalCommands();
if (is_dir($command_path = Util::guessPath(app_path(), '/command', true))) {
$cli->installCommands($command_path);
}
foreach (config('plugin', []) as $firm => $projects) {
if (isset($projects['app'])) {
foreach (['', '/app'] as $app) {
if ($command_str = Util::guessPath(base_path() . "/plugin/$firm{$app}", 'command')) {
$command_path = base_path() . "/plugin/$firm{$app}/$command_str";
$cli->installCommands($command_path, "plugin\\$firm" . str_replace('/', '\\', $app) . "\\$command_str");
}
}
}
foreach ($projects as $name => $project) {
if (!is_array($project)) {
continue;
}
foreach ($project['command'] ?? [] as $class_name) {
$reflection = new \ReflectionClass($class_name);
if ($reflection->isAbstract()) {
continue;
}
$properties = $reflection->getStaticProperties();
$name = $properties['defaultName'];
if (!$name) {
throw new RuntimeException("Command {$class_name} has no defaultName");
}
$description = $properties['defaultDescription'] ?? '';
$command = Container::get($class_name);
$command->setName($name)->setDescription($description);
$cli->add($command);
}
}
}
$cli->run();