chore: 添加静态资源文件和版本配置文件

添加大量图片、字体、音频等静态资源文件,包括用户界面图片、模板文件和安装界面素材
添加系统版本配置文件(.version)和常量定义文件(.constant)
更新供应商依赖文件,包括Symfony VarDumper组件和相关许可证文件
添加验证码配置文件(captcha.php)和.gitignore规则
This commit is contained in:
2026-03-06 20:14:23 +08:00
commit c9a98f342c
4485 changed files with 490986 additions and 0 deletions

35
crmeb/basic/BaseAi.php Normal file
View File

@@ -0,0 +1,35 @@
<?php
namespace crmeb\basic;
use crmeb\services\AccessTokenServeService;
abstract class BaseAi extends BaseStorage
{
/**
* access_token
* @var null
*/
protected $accessToken = NULL;
/**
* BaseProduct constructor.
* @param string $name
* @param AccessTokenServeService $accessTokenServeService
* @param string $configFile
*/
public function __construct(string $name, AccessTokenServeService $accessTokenServeService, string $configFile)
{
parent::__construct($name, [], $configFile);
$this->accessToken = $accessTokenServeService;
}
/**
* 初始化
* @param array $config
* @return mixed|void
*/
protected function initialize(array $config = [])
{
}
}

BIN
crmeb/basic/BaseAuth.php Executable file

Binary file not shown.

BIN
crmeb/basic/BaseController.php Executable file

Binary file not shown.

View File

@@ -0,0 +1,104 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\basic;
/**
* Class BaseDelivery
* @package crmeb\basic
*/
abstract class BaseDelivery extends BaseStorage
{
/**
* 回调地址
* @var null
*/
protected $callback_url = null;
/**
* 初始化
* @param array $config
* @return mixed|void
*/
protected function initialize(array $config)
{
$this->callback_url = rtrim(sys_config('site_url'), '/') . '/api/city_delivery/notify';
}
/**
* @param $data
* @return mixed
*/
abstract function addMerchant($data); //注册商户
/**
* @param $data
* @return mixed
*/
abstract function addShop($data); //创建门店
/**
* @param $data
* @return mixed
*/
abstract function updateShop($data); //更新门店
/**
* @param $data
* @return mixed
*/
abstract function addOrder($data); //发布订单
/**
* @param $data
* @return mixed
*/
abstract function getOrderPrice($data); //计算订单价格
/**
* @param $data
* @return mixed
*/
abstract function getOrderDetail($data); //获取订单详情
/**
* @param $data
* @return mixed
*/
abstract function cancelOrder($data); //取消订单
/**
* @param $data
* @return mixed
*/
abstract function getRecharge($data); //获取充值地址
/**
* @param $data
* @return mixed
*/
abstract function getBalance($data); //获取余额
/**
* @param $data
* @return mixed
*/
abstract function addTip($data); //支付小费
/**
* @param $data
* @return mixed
*/
abstract function getCity($data); //获取城市信息
}

50
crmeb/basic/BaseErp.php Normal file
View File

@@ -0,0 +1,50 @@
<?php
namespace crmeb\basic;
use crmeb\services\erp\AccessToken;
abstract class BaseErp extends BaseStorage
{
/**
* token句柄
* @var AccessToken
*/
protected $accessToken;
/**
* 驱动类型
* @var string
*/
protected $name;
/**
* 配置文件名
* @var string
*/
protected $configFile;
/**
* BaseErp constructor.
* @param string $name
* @param AccessToken $accessToken
* @param string $configFile
*/
public function __construct(string $name, AccessToken $accessToken, string $configFile)
{
parent::__construct($name, [], $configFile);
$this->accessToken = $accessToken;
}
/**
* 初始化
* @param array $config
* @return mixed|void
*/
protected function initialize(array $config = [])
{
// parent::initialize($config);
}
}

View File

@@ -0,0 +1,76 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\basic;
use crmeb\services\AccessTokenServeService;
use crmeb\services\HttpService;
use think\exception\ValidateException;
use think\facade\Config;
use crmeb\services\CacheService;
/**
* Class BaseExpress
* @package crmeb\basic
*/
abstract class BaseExpress extends BaseStorage
{
/**
* access_token
* @var null
*/
protected $accessToken = NULL;
public function __construct(string $name, AccessTokenServeService $accessTokenServeService, string $configFile)
{
parent::__construct($name, [], $configFile);
$this->accessToken = $accessTokenServeService;
}
/**
* 初始化
* @param array $config
* @return mixed|void
*/
protected function initialize(array $config = [])
{
// parent::initialize($config);
}
/**
* 开通服务
* @return mixed
*/
abstract public function open();
/**物流追踪
* @return mixed
*/
abstract public function query(string $num, string $com = '');
/**电子面单
* @return mixed
*/
abstract public function dump($data);
/**快递公司
* @return mixed
*/
//abstract public function express($type, $page, $limit);
/**面单模板
* @return mixed
*/
abstract public function temp(string $com);
}

77
crmeb/basic/BaseJobs.php Normal file
View File

@@ -0,0 +1,77 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\basic;
use crmeb\interfaces\JobInterface;
use think\queue\Job;
/**
* 消息队列基类
* Class BaseJobs
* @package crmeb\basic
*/
class BaseJobs implements JobInterface
{
/**
* 运行消息队列
* @param Job $job
* @param $data
*/
public function fire(Job $job, $data): void
{
try {
$action = $data['do'] ?? 'doJob';//任务名
$infoData = $data['data'] ?? [];//执行数据
$errorCount = $data['errorCount'] ?? 0;//最大错误次数
$this->runJob($action, $job, $infoData, $errorCount);
} catch (\Throwable $e) {
$job->delete();
}
}
/**
* 执行队列
* @param string $action
* @param Job $job
* @param array $infoData
* @param int $errorCount
*/
protected function runJob(string $action, Job $job, array $infoData, int $errorCount = 3)
{
if (!class_exists(get_class($this))) {
$job->delete();
} else {
$action = method_exists($this, $action) ? $action : 'handle';
if (!method_exists($this, $action)) {
$job->delete();
} else {
if ($this->{$action}(...$infoData)) {
//删除任务
$job->delete();
} else {
if ($job->attempts() >= $errorCount && $errorCount) {
//删除任务
$job->delete();
} else {
//从新放入队列
$job->release();
}
}
}
}
}
public function failed($data)
{
}
}

219
crmeb/basic/BaseManager.php Normal file
View File

@@ -0,0 +1,219 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\basic;
use think\facade\Config;
use think\helper\Str;
use think\Container;
/**
* 驱动基类
* Class BaseManager
* @package crmeb\basic
*/
abstract class BaseManager
{
/**
* 驱动的命名空间
* @var null
*/
protected string $namespace;
/**
* 配置
* @var null
*/
protected $configFile = null;
/**
* 配置
* @var array
*/
protected $config = [];
/**
* 驱动
* @var array
*/
protected $drivers = [];
/**
* 驱动类型
* @var null
*/
protected $name = null;
/**
* BaseManager constructor.
* @param string|array|int $name驱动名称
* @param array $config 配置
*/
public function __construct($name = null, array $config = [])
{
$type = null;
if (is_array($name)) {
$config = $name;
$name = null;
}
if (is_int($name)) {
$type = $name;
$name = null;
}
if ($name)
$this->name = $name;
if ($type && is_null($this->name)) {
$this->setHandleType((int)$type - 1);
}
$this->config = $config;
}
/**
* 提取配置文件名
* @return $this
*/
protected function getConfigFile()
{
if (is_null($this->configFile)) {
$this->configFile = strtolower((new \ReflectionClass($this))->getShortName());
}
return $this;
}
/**
* 设置文件句柄
* @param int $type
*/
protected function setHandleType(int $type)
{
$this->getConfigFile();
$stores = array_keys(Config::get($this->configFile . '.stores', []));
$name = $stores[$type] ?? null;
if (!$name) {
throw new \RuntimeException($this->configFile . ' type is not used');
}
$this->name = $name;
}
/**
* 设置默认句柄
* @return mixed
*/
abstract protected function getDefaultDriver();
/**
* 动态调用
* @param $method
* @param $arguments
*/
public function __call($method, $arguments)
{
return $this->driver()->{$method}(...$arguments);
}
/**
* 获取驱动实例
* @param null|string $name
* @return mixed
*/
protected function driver(string $name = null)
{
$name = $name ?: $this->name;
$name = $name ?: $this->getDefaultDriver();
if (is_null($name)) {
throw new \InvalidArgumentException(sprintf(
'Unable to resolve NULL driver for [%s].', static::class
));
}
return $this->drivers[$name] = $this->getDriver($name);
}
/**
* 获取驱动实例
* @param string $name
* @return mixed
*/
protected function getDriver(string $name)
{
return $this->drivers[$name] ?? $this->createDriver($name);
}
/**
* 获取驱动类型
* @param string $name
* @return mixed
*/
protected function resolveType(string $name)
{
return $name;
}
/**
* 创建驱动
*
* @param string $name
* @return mixed
*
*/
protected function createDriver(string $name)
{
$type = $this->resolveType($name);
$method = 'create' . Str::studly($type) . 'Driver';
if (method_exists($this, $method)) {
return $this->$method($name);
}
$class = $this->resolveClass($type);
$this->name = $type;
return $this->invokeClass($class);
}
/**
* 获取驱动类
* @param string $type
* @return string
*/
protected function resolveClass(string $type): string
{
if ($this->namespace || false !== strpos($type, '\\')) {
$class = false !== strpos($type, '\\') ? $type : $this->namespace . Str::studly($type);
if (class_exists($class)) {
return $class;
}
}
throw new \InvalidArgumentException("Driver [$type] not supported.");
}
/**
* 实例化类
* @param $class
* @return mixed
*/
protected function invokeClass($class)
{
if (!class_exists($class)) {
throw new \RuntimeException('class not exists: ' . $class);
}
$this->getConfigFile();
$handle = Container::getInstance()->invokeClass($class, [$this->name, $this->config, $this->configFile]);
$this->config = [];
return $handle;
}
}

152
crmeb/basic/BaseMessage.php Normal file
View File

@@ -0,0 +1,152 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\basic;
use think\facade\Config;
abstract class BaseMessage extends BaseStorage
{
/**
* 模板id
* @var array
*/
protected $templateIds = [];
/**
* openId
* @var string
*/
protected $openId;
/**
* 跳转链接
* @var string
*/
protected $toUrl;
/**
* 颜色
* @var string
*/
protected $color;
/**
* 初始化
* @param array $config
* @return mixed|void
*/
protected function initialize(array $config)
{
$this->templateIds = Config::get($this->configFile . '.stores.' . $this->name . '.template_id', []);
}
/**
* 是否记录日志
* @return mixed
*/
public function isLog()
{
$isLog = Config::get($this->configFile . 'isLog', false);
return Config::get($this->configFile . '.stores.' . $this->name . '.isLog', $isLog);
}
/**
* 获取模板id
* @return array
*/
public function getTemplateId()
{
return $this->templateIds;
}
/**
* openid
* @param string $openId
* @return $this
*/
public function to(string $openId)
{
$this->openId = $openId;
return $this;
}
/**
* 跳转路径
* @param string $url
* @return $this
*/
public function url(string $url)
{
$this->toUrl = $url;
return $this;
}
/**
* 设置背景颜色
* @param string $color
* @return $this
*/
public function color(?string $color)
{
$this->color = $color;
return $this;
}
/**
* 提取模板code
* @param string $templateId
* @return null
*/
protected function getTemplateCode(string $templateId)
{
return $this->templateIds[$templateId] ?? null;
}
/**
* 恢复默认值
*/
protected function clear()
{
$this->openId = null;
$this->toUrl = null;
$this->color = null;
}
/**
* 发送消息
* @param string $templateId
* @param array $data
* @return mixed
*/
abstract public function send(string $templateId, array $data = []);
/**
* 添加模板
* @param string $shortId
* @return mixed
*/
abstract public function add(string $shortId);
/**
* 删除模板
* @param string $templateId
* @return mixed
*/
abstract public function delete(string $templateId);
/**
* 获取所有模板
* @return mixed
*/
abstract public function list();
}

54
crmeb/basic/BaseModel.php Normal file
View File

@@ -0,0 +1,54 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\basic;
use crmeb\traits\ModelTrait;
use think\db\Query;
use think\Model;
use crmeb\topthink\HasManyThrough;
/**
* Class BaseModel
* @package crmeb\basic
* @mixin ModelTrait
* @mixin Query
*/
class BaseModel extends Model
{
/**
* 重写一对多关联
* @param string $model
* @param string $through
* @param string $foreignKey
* @param string $throughKey
* @param string $localKey
* @param string $throughPk
* @return HasManyThrough
* @author 等风来
* @email 136327134@qq.com
* @date 2023/10/11
*/
public function hasManyThrough(string $model, string $through, string $foreignKey = '', string $throughKey = '', string $localKey = '', string $throughPk = ''): HasManyThrough
{
// 记录当前关联信息
$model = $this->parseModel($model);
$through = $this->parseModel($through);
$localKey = $localKey ?: $this->getPk();
$foreignKey = $foreignKey ?: $this->getForeignKey($this->name);
$throughKey = $throughKey ?: $this->getForeignKey((new $through())->getName());
$throughPk = $throughPk ?: (new $through())->getPk();
return new HasManyThrough($this, $model, $through, $foreignKey, $throughKey, $localKey, $throughPk);
}
}

50
crmeb/basic/BasePay.php Normal file
View File

@@ -0,0 +1,50 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\basic;
/**
* Class BasePay
* @package crmeb\basic
*/
abstract class BasePay extends BaseStorage
{
/**
* 支付参数配置
* @var array
*/
protected $configPay = [];
/**
* 发起支付
* @param array|null $configPay
* @return mixed
*/
abstract public function pay(?array $configPay = []);
/**
* 退款
* @param array|null $configPay
* @return mixed
*/
abstract public function refund(?array $configPay = []);
/**
* 设置支付参数
* @param array $configPay
* @return $this
*/
public function setConfigPay(array $configPay)
{
$this->configPay = $configPay;
return $this;
}
}

View File

@@ -0,0 +1,61 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\basic;
use crmeb\services\printer\AccessToken;
/**
* Class BasePrinter
* @package crmeb\basic
*/
abstract class BasePrinter extends BaseStorage
{
/**
* token句柄
* @var AccessToken
*/
protected $accessToken;
/**
* 打印内容
* @var string
*/
protected $printerContent;
/**
* BasePrinter constructor.
* @param string $name
* @param AccessToken $accessToken
* @param string $configFile
*/
public function __construct(string $name, AccessToken $accessToken, string $configFile)
{
parent::__construct($name, [], $configFile);
$this->accessToken = $accessToken;
}
/**
* 开始打印
* @param array|null $systemConfig
* @return mixed
*/
abstract public function startPrinter();
/**
* 设置打印内容
* @param array $config
* @return mixed
*/
abstract public function setPrinterContent(array $config);
}

View File

@@ -0,0 +1,61 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\basic;
use crmeb\services\AccessTokenServeService;
/**
* Class BaseProduct
* @package crmeb\basic
*/
abstract class BaseProduct extends BaseStorage
{
/**
* access_token
* @var null
*/
protected $accessToken = NULL;
/**
* BaseProduct constructor.
* @param string $name
* @param AccessTokenServeService $accessTokenServeService
* @param string $configFile
*/
public function __construct(string $name, AccessTokenServeService $accessTokenServeService, string $configFile)
{
parent::__construct($name, [], $configFile);
$this->accessToken = $accessTokenServeService;
}
/**
* 初始化
* @param array $config
* @return mixed|void
*/
protected function initialize(array $config = [])
{
// parent::initialize($config);
}
/**
* 开通服务
* @return mixed
*/
abstract public function open();
/**复制商品
* @return mixed
*/
abstract public function goods(string $url);
}

107
crmeb/basic/BaseSmss.php Normal file
View File

@@ -0,0 +1,107 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\basic;
use crmeb\services\AccessTokenServeService;
/**
* Class BaseSmss
* @package crmeb\basic
*/
abstract class BaseSmss extends BaseStorage
{
/**
* access_token
* @var null
*/
protected $accessToken = NULL;
/**
* BaseSmss constructor.
* @param string $name
* @param AccessTokenServeService $accessTokenServeService
* @param string $configFile
*/
public function __construct(string $name, AccessTokenServeService $accessTokenServeService, string $configFile, array $config = [])
{
$this->accessToken = $accessTokenServeService;
$this->name = $name;
$this->configFile = $configFile;
$this->initialize($config);
}
/**
* 初始化
* @param array $config
* @return mixed|void
*/
protected function initialize(array $config = [])
{
}
/**
* 开通服务
* @return mixed
*/
abstract public function open();
/**修改签名
* @return mixed
*/
abstract public function modify(string $sign = null, string $phone, string $code);
/**用户信息
* @return mixed
*/
abstract public function info();
/**发送短信
* @return mixed
*/
abstract public function send(string $phone, string $templateId, array $data);
/**
* 短信模板
* @param int $page
* @param int $limit
* @param int $type
* @return mixed
*/
abstract public function temps(int $page, int $limit, int $type);
/**
* 申请模板
* @param string $title
* @param string $content
* @param int $type
* @return mixed
*/
abstract public function apply(string $title, string $content, int $type);
/**
* 模板记录
* @param int $tempType
* @param int $page
* @param int $limit
* @return mixed
*/
abstract public function applys(int $tempType, int $page, int $limit);
/**发送记录
* @return mixed
*/
abstract public function record($record_id);
}

View File

@@ -0,0 +1,56 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\basic;
/**
* 容器基类
* Class BaseStorage
* @package crmeb\basic
*/
abstract class BaseStorage
{
use \crmeb\traits\ErrorTrait;
/**
* 驱动名称
* @var string
*/
protected $name;
/**
* 驱动配置文件名
* @var string
*/
protected $configFile;
/**
* BaseStorage constructor.
* @param string $name 驱动名
* @param string $configFile 驱动配置名
* @param array $config 其他配置
*/
public function __construct(string $name, array $config = [], string $configFile = null)
{
$this->name = $name;
$this->configFile = $configFile;
$this->initialize($config);
}
/**
* 初始化
* @param array $config
* @return mixed
*/
abstract protected function initialize(array $config);
}

459
crmeb/basic/BaseUpload.php Normal file
View File

@@ -0,0 +1,459 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\basic;
use crmeb\exceptions\UploadException;
use think\facade\Config;
/**
* Class BaseUpload
* @package crmeb\basic
*/
abstract class BaseUpload extends BaseStorage
{
/**
* 缩略图
* @var string[]
*/
protected array $thumb = ['big', 'mid', 'small'];
/**
* 缩略图配置
* @var array
*/
protected array $thumbConfig = [
'thumb_big_height' => 700,
'thumb_big_width' => 700,
'thumb_mid_height' => 400,
'thumb_mid_width' => 400,
'thumb_small_height' => 100,
'thumb_small_width' => 100,
];
/**
* 水印配置
* @var array
*/
protected array $waterConfig = [
'image_watermark_status' => 0,
'watermark_type' => 1,
'watermark_image' => '',
'watermark_opacity' => 0,
'watermark_position' => 1,
'watermark_rotate' => 0,
'watermark_text' => '',
'watermark_text_angle' => "",
'watermark_text_color' => '#000000',
'watermark_text_size' => '5',
'watermark_text_font' => '',
'watermark_x' => 0,
'watermark_y' => 0
];
/**
* 图片信息
* @var array
*/
protected $fileInfo;
/**
* 下载图片信息
*/
protected $downFileInfo;
/**
* 要生成缩略图、水印的图片地址
* @var string
*/
protected string $filePath;
/**
* 验证配置
* @var string
*/
protected string $validate;
/**
* 保存路径
* @var string
*/
protected string $path = '';
/**
* 是否自动裁剪
* @var bool
*/
protected bool $authThumb = false;
protected function initialize(array $config)
{
$this->fileInfo = $this->downFileInfo = new \StdClass();
$this->thumbConfig = array_merge($this->thumbConfig, $config['thumb'] ?? []);
$this->waterConfig = array_merge($this->waterConfig, $config['water'] ?? []);
}
/**
* 设置处理缩略图、水印图片路径
* @param string $filePath
* @return $this
*/
public function setFilepath(string $filePath)
{
$this->filePath = substr($filePath, 0, 1) === '.' ? substr($filePath, 1) : $filePath;
return $this;
}
/**
* 是否自动裁剪
* @param bool $auth
* @return $this
*/
public function setAuthThumb(bool $auth)
{
$this->authThumb = $auth;
return $this;
}
/**
* 上传文件路径
* @param string $path
* @return $this
*/
public function to(string $path)
{
$this->path = $path;
return $this;
}
/**
* 获取文件信息
* @return array
*/
public function getFileInfo()
{
return $this->fileInfo;
}
/**
* 检测是否是图片
* @param $filePath
* @return bool
*/
protected function checkImage($filePath)
{
//获取图像信息
$info = @getimagesize($filePath);
//检测图像合法性
if (false === $info || IMAGETYPE_GIF === $info[2] || empty($info['bits'])) {
return false;
}
return true;
}
/**
* 验证合法上传域名
* @param string $url
* @return string
*/
protected function checkUploadUrl(string $url)
{
if ($url && strstr($url, 'http') === false) {
$url = 'http://' . $url;
}
return $url;
}
/**
* 获取系统配置
* @return mixed
*/
protected function getConfig()
{
$config = Config::get($this->configFile . '.stores.' . $this->name, []);
if (empty($config)) {
$config['filesize'] = Config::get($this->configFile . '.filesize', []);
$config['fileExt'] = Config::get($this->configFile . '.fileExt', []);
$config['fileMime'] = Config::get($this->configFile . '.fileMime', []);
}
return $config;
}
/**
* 设置验证规则
* @param array|null $validate
* @return $this
*/
public function validate(?array $validate = null)
{
if (is_null($validate)) {
$validate = $this->getConfig();
}
$this->extractValidate($validate);
return $this;
}
/**
* 验证目录是否正确
* @param string $key
* @return false|string
*/
protected function getUploadPath(string $key)
{
$path = ($this->path ? $this->path . '/' : '') . $key;
if ($path && $path[0] === '/') {
$path = substr($path, 1);
}
return $path;
}
/**
* 提取上传验证
*/
protected function extractValidate(array $validateArray)
{
$validate = [];
foreach ($validateArray as $key => $value) {
$validate[] = $key . ':' . (is_array($value) ? implode(',', $value) : $value);
}
$this->validate = implode('|', $validate);
unset($validate);
}
/**
* 提取文件名
* @param string $path
* @param string $ext
* @return string
*/
protected function saveFileName(string $path = null, string $ext = 'jpg')
{
mt_srand();
return ($path ? substr(md5($path), 0, 5) : '') . date('YmdHis') . rand(0, 9999) . '.' . $ext;
}
/**
* 提取文件后缀以及之前部分
* @param string $path
* @return false|string[]
*/
protected function getFileName(string $path)
{
$_empty = ['', ''];
if (!$path) return $_empty;
if (strpos($path, '?')) {
$_tarr = explode('?', $path);
$path = trim($_tarr[0]);
}
$arr = explode('.', $path);
if (!is_array($arr) || count($arr) <= 1) return $_empty;
$ext_name = trim($arr[count($arr) - 1]);
$ext_name = !$ext_name ? 'jpg' : $ext_name;
return [explode('.' . $ext_name, $path)[0], $ext_name];
}
/**
* 获取图片地址
* @param string $filePath
* @param bool $is_parse_url
* @return string
*/
protected function getFilePath(string $filePath = '', bool $is_parse_url = false)
{
$path = $filePath ? $filePath : $this->filePath;
if ($is_parse_url) {
$data = parse_url($path);
//远程地址处理
if (isset($data['host']) && isset($data['path'])) {
if (file_exists(app()->getRootPath() . 'public' . $data['path'])) {
$path = $data['path'];
}
}
}
return $path;
}
/**
* 文件是否在本地
* @param string $filePath
* @return bool
*/
protected function isLocal(string $filePath)
{
$isLocal = false;
$path = $filePath;
$data = parse_url($path);
//远程地址处理
if (isset($data['host']) && isset($data['path'])) {
if (file_exists(app()->getRootPath() . 'public' . $data['path'])) {
$isLocal = true;
}
}
return $isLocal;
}
/**
* 获取文件类型和大小
* @param string $url
* @param bool $isData
* @return array
*/
protected function getFileHeaders(string $url, $isData = true)
{
stream_context_set_default(['ssl' => ['verify_peer' => false, 'verify_peer_name' => false]]);
$header['size'] = 0;
$header['type'] = 'image/jpeg';
if (!$isData) {
return $header;
}
try {
$headerArray = get_headers(str_replace('\\', '/', $url), true);
if (!isset($headerArray['Content-Length'])) {
$header['size'] = 0;
} else {
if (is_array($headerArray['Content-Length']) && count($headerArray['Content-Length']) == 2) {
$header['size'] = $headerArray['Content-Length'][1];
} else {
$header['size'] = $headerArray['Content-Length'] ?? 0;
}
}
if (!isset($headerArray['Content-Type'])) {
$header['type'] = 'image/jpeg';
} else {
if (is_array($headerArray['Content-Type']) && count($headerArray['Content-Type']) == 2) {
$header['type'] = $headerArray['Content-Type'][1];
} else {
$header['type'] = $headerArray['Content-Type'] ?? 'image/jpeg';
}
}
} catch (\Exception $e) {
}
return $header;
}
/**
* 获取上传信息
* @return array
*/
public function getUploadInfo()
{
if (isset($this->fileInfo->filePath)) {
if (strstr($this->fileInfo->filePath, 'http') === false) {
$url = request()->domain() . $this->fileInfo->filePath;
} else {
$url = $this->fileInfo->filePath;
}
$headers = $this->getFileHeaders($url);
return [
'name' => $this->fileInfo->fileName,
'real_name' => $this->fileInfo->realName ?? '',
'size' => $headers['size'] ?? 0,
'type' => $headers['type'] ?? 'image/jpeg',
'dir' => $this->fileInfo->filePath,
'thumb_path' => $this->fileInfo->filePath,
'thumb_path_big' => $this->fileInfo->filePathBig ?? '',
'thumb_path_mid' => $this->fileInfo->filePathMid ?? '',
'thumb_path_small' => $this->fileInfo->filePathSmall ?? '',
'thumb_path_water' => $this->fileInfo->filePathWater ?? '',
'time' => time(),
];
} else {
return [];
}
}
/**
* 获取下载信息
* @return array
*/
public function getDownloadInfo()
{
if (isset($this->downFileInfo->downloadFilePath)) {
if (strstr($this->downFileInfo->downloadFilePath, 'http') === false) {
$url = request()->domain() . $this->downFileInfo->downloadFilePath;
} else {
$url = $this->downFileInfo->downloadFilePath;
}
$headers = $this->getFileHeaders($url);
return [
'name' => $this->downFileInfo->downloadFileName,
'real_name' => $this->downFileInfo->downloadRealName ?? '',
'size' => $headers['size'] ?? 0,
'type' => $headers['type'] ?? 'image/jpeg',
'dir' => $this->downFileInfo->downloadFilePath ?? '',
'thumb_path' => $this->downFileInfo->downloadFilePath ?? '',
'time' => time(),
];
} else {
return [];
}
}
/**
* 验证文件后缀是否为非法文件
* @param string $key
* @return void
* @author 等风来
* @email 136327134@qq.com
* @date 2023/10/9
*/
public function verifyExtension(string $key)
{
$parseUrl = parse_url($key);
$path = $parseUrl['path'] ?? '';
$extension = pathinfo($path)['extension'] ?? '';
$fileExt = app()->config->get('upload.fileExt');
if (!in_array($extension, $fileExt)) {
throw new UploadException('文件类型错误,支持:' . implode('、', $fileExt));
}
}
/**
* 文件上传
* @return mixed
*/
abstract public function move(string $file = 'file');
/**
* 文件流上传
* @return mixed
*/
abstract public function stream(string $fileContent, string $key = null);
/**
* 删除文件
* @return mixed
*/
abstract public function delete(string $filePath);
/**
* 实例化上传
* @return mixed
*/
abstract protected function app();
/**
* 获取上传密钥
* @return mixed
*/
abstract public function getTempKeys();
/**
* 获取缩略图
* @return mixed
*/
abstract public function thumb(string $filePath = '');
/**
* 添加水印
* @return mixed
*/
abstract public function water(string $filePath = '');
}

46
crmeb/command/Dao.php Normal file
View File

@@ -0,0 +1,46 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\command;
use think\console\command\Make;
/**
* Class Business
* @package crmeb\command
*/
class Dao extends Make
{
protected $type = "Dao";
protected function configure()
{
parent::configure();
$this->setName('make:dao')
->setDescription('Create a new service class');
}
protected function getStub(): string
{
return __DIR__ . DIRECTORY_SEPARATOR. 'stubs' . DIRECTORY_SEPARATOR . 'dao.stub';
}
protected function getNamespace(string $app): string
{
return parent::getNamespace($app) . '\\dao';
}
protected function getPathName(string $name): string
{
$name = str_replace('app\\', '', $name);
return $this->app->getBasePath() . ltrim(str_replace('\\', '/', $name), '/') . 'Dao.php';
}
}

430
crmeb/command/Install.php Normal file
View File

@@ -0,0 +1,430 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\command;
use app\services\system\admin\SystemAdminServices;
use app\services\system\config\SystemConfigServices;
use crmeb\services\MysqlBackupService;
use PhpOffice\PhpSpreadsheet\Cell\Cell;
use think\console\Command;
use think\console\Input;
use think\console\input\Argument;
use think\console\input\Option;
use think\console\Output;
use think\console\Table;
class Install extends Command
{
protected $host;
protected function configure()
{
$this->setName('install')
->addArgument('status', Argument::OPTIONAL, 'start/remove')
->addOption('h', null, Option::VALUE_REQUIRED, '网站域名')
->addOption('db', null, Option::VALUE_NONE, '是否卸载数据库')
->setDescription('命令行一键安装/卸载');
}
protected function execute(Input $input, Output $output)
{
$status = $input->getArgument('status') ?: 'start';
$database = env('database.database');
if (in_array($status, ['start', 'remove'])) {
if (!env('database.hostname') ||
!$database ||
!env('database.username') ||
!env('database.password') ||
!env('database.hostport')
) {
$output->error('请先配置数据库,确保数据库能正常连接!');
return;
}
}
if ($input->hasOption('h')) {
$this->host = $input->getOption('h');
}
if (!$status || !in_array($status, ['start', 'remove'])) {
$question = $output->choice($input, ' 请选择执行指令数字 ', ['start' => '1', 'remove' => '-1', 'exit' => 0]);
if ($question === 'exit') {
$output->info('您已退出命令');
return;
} else {
$status = $question;
}
}
if ($status === 'remove') {
$this->remove($input, $output);
} elseif ($status === 'start') {
$this->start($input, $output);
}
return;
}
/**
* 开始安装
* @param Input $input
* @param Output $output
* @throws \think\db\exception\BindParamException
*/
protected function start(Input $input, Output $output)
{
$installLockDir = root_path('public') . 'install/install.lock';
if (file_exists($installLockDir)) {
$crmeb = get_crmeb_version();
$question = $output->confirm($input, '您已经安装' . $crmeb . '版本是否重新安装,重新安装会清除掉之前的数据请谨慎操作?', false);
if ($question) {
$res = $this->authBackups();
if (!$res) {
$output->info('已退出安装程序');
}
$database = env('database.database');
$this->dropTable($database);
unlink($installLockDir);
} else {
$output->info('已退出安装程序');
return;
}
}
$installSql = file_get_contents(root_path('public' . DIRECTORY_SEPARATOR . 'install') . 'crmeb.sql');
if (!$installSql) {
$output->error('读取安装sql失败,请检查安装sql文件权限,再次尝试安装!');
return;
}
$this->query($installSql);
$this->cleanTable();
$this->output->writeln('+---------------------------- [创建管理员] ---------------------------------+');
$this->output->newLine();
[$account, $password] = $this->createAdmin();
file_put_contents($installLockDir, time());
$output->info('安装完成!!请妥善保管您的账号密码!');
$output->info('账号:' . $account);
$output->info('密码:' . $password);
return;
}
/**
* 创建账号
*/
protected function createAdmin()
{
$account = $this->adminAccount();
$password = $this->adminPassword();
/** @var SystemAdminServices $service */
$service = app()->make(SystemAdminServices::class);
$tablepre = env('database.prefix');
$this->app->db->query('truncate table ' . $tablepre . 'system_admin');
try {
$service->create(['conf_pwd' => $password, 'roles' => [1], 'pwd' => $password, 'account' => $account, 'level' => 0, 'status' => 1]);
} catch (\Throwable $e) {
$this->output->writeln($e->getMessage());
$this->output->newLine();
[$account, $password] = $this->createAdmin();
}
if ($this->host) {
/** @var SystemConfigServices $configService */
$configService = app()->make(SystemConfigServices::class);
$configService->update('site_url', ['value' => json_encode($this->host)], 'menu_name');
}
return [$account, $password];
}
/**
* 卸载程序
* @param Input $input
* @param Output $output
* @throws \think\db\exception\BindParamException
*/
protected function remove(Input $input, Output $output)
{
$installLockDir = root_path('public') . 'install/install.lock';
if (!file_exists($installLockDir)) {
$this->output->info('你尚未安装本程序');
return;
}
$database = env('database.database');
$output->info(' 正在进行卸载中...');
$this->authBackups();
if ($input->hasOption('db')) {
$question = $output->confirm($input, '您确定要清除掉[' . $database . ']数据吗?', false);
if ($question) {
$this->dropTable($database);
}
}
unlink($installLockDir);
$this->output->info('卸载完成');
return;
}
/**
* 清除所有表数据
* @param string $database
* @return mixed
* @throws \think\db\exception\BindParamException
*/
protected function dropTable(string $database)
{
$this->output->writeln('+---------------------------- [清理表数据] ---------------------------------+');
$this->output->newLine();
$this->output->write("\r 正在清理表数据");
/** @var MysqlBackupService $service */
$service = app()->make(MysqlBackupService::class, [[
//数据库备份卷大小
'compress' => 1,
//数据库备份文件是否启用压缩 0不压缩 1 压缩
'level' => 5,
]]);
$dataList = $service->dataList();
$tableName = array_column($dataList, 'name');
$count = count($tableName);
if ($count) {
$res = $this->app->db->transaction(function () use ($database, $tableName) {
foreach ($tableName as $name) {
$this->app->db->query('DROP TABLE ' . $name);
}
});
}
$this->output->write("\r 已清理完毕");
$this->output->newLine(2);
return $res;
}
/**
* 执行安装sql
* @param string $installSql
*/
protected function query(string $installSql)
{
$tablepre = env('database.prefix');
$sqlArray = $this->sqlSplit($installSql, $tablepre);
$table = new Table();
$this->output->writeln('+----------------------------- [SQL安装] -----------------------------------+');
$this->output->newLine();
$header = ['表名', '执行结果', '错误原因', '时间'];
$table->setHeader($header);
foreach ($sqlArray as $sql) {
$sql = trim($sql);
if (strstr($sql, 'CREATE TABLE')) {
preg_match('/CREATE TABLE (IF NOT EXISTS)? `eb_([^ ]*)`/is', $sql, $matches);
$tableName = $tablepre . ($matches[2] ?? '');
} else {
$tableName = '';
}
try {
$this->app->db->transaction(function () use ($tablepre, $sql, $tableName) {
$sql = str_replace('`eb_', '`' . $tablepre, $sql);//替换表前缀
$this->app->db->query($sql);
});
$tableName && $table->addRow([$tableName, 'ok', '无错误', date('Y-m-d H:i:s')]);
} catch (\Throwable $e) {
$tableName && $table->addRow([$tableName, 'x', $e->getMessage(), date('Y-m-d H:i:s')]);
}
}
$this->output->writeln($table->render());
$this->output->newLine(2);
}
/**
* 账号
* @return bool|mixed|string
*/
protected function adminAccount()
{
$account = $this->output->ask($this->input, '请输入后台登陆账号,最少4个字符', null, function ($value) {
if (strlen($value) < 4) {
return false;
}
return $value;
});
if (!$account) {
$this->output->error('账号至少4个字符');
$this->output->newLine();
$account = $this->adminAccount();
}
return $account;
}
/**
* 密码
* @return bool|mixed|string|null
*/
protected function adminPassword()
{
$password = $this->output->ask($this->input, '请输入登陆密码,密码为数字加字母/字母加符号/数字加字符的组合不能少于6位');
if (!preg_match('/^(?![a-zA-z]+$)(?!\d+$)(?![!@#$%^<>&*]+$)[a-zA-Z\d!@#$%^&<>*]{6,16}$/', $password)) {
$this->output->error('请输入符合要求的密码');
$this->output->newLine();
$password = $this->adminPassword();
}
return $password;
}
/**
* 清楚多余数据
*/
protected function cleanTable()
{
$tablepre = env('database.prefix');
$database = env('database.database');
$blTable = ['eb_system_admin', 'eb_system_role', 'eb_system_config', 'eb_system_config_tab',
'eb_system_menus', 'eb_system_file', 'eb_express', 'eb_system_group', 'eb_system_group_data',
'eb_template_message', 'eb_shipping_templates', "eb_shipping_templates_region",
"eb_shipping_templates_free", 'eb_system_city', 'eb_diy', 'eb_member_ship', 'eb_member_right',
'eb_agreement', 'eb_store_service_speechcraft', 'eb_system_user_level', 'eb_cache'];
if ($tablepre !== 'eb_') {
$blTable = array_map(function ($name) use ($tablepre) {
return str_replace('eb_', $tablepre, $name);
}, $blTable);
}
$tableList = $this->app->db->query("select table_name from information_schema.tables where table_schema='$database'");
$tableList = array_column($tableList, 'table_name');
foreach ($tableList as $table) {
if (!in_array($table, $blTable)) {
$this->app->db->query('truncate table ' . $table);
}
}
}
/**
* 切割sql
* @param $sql
* @return array
*/
protected function sqlSplit(string $sql, string $tablepre)
{
if ($tablepre != "tp_")
$sql = str_replace("tp_", $tablepre, $sql);
$sql = preg_replace("/TYPE=(InnoDB|MyISAM|MEMORY)( DEFAULT CHARSET=[^; ]+)?/", "ENGINE=\\1 DEFAULT CHARSET=utf8", $sql);
$sql = str_replace("\r", "\n", $sql);
$ret = [];
$num = 0;
$queriesarray = explode(";\n", trim($sql));
unset($sql);
foreach ($queriesarray as $query) {
$ret[$num] = '';
$queries = explode("\n", trim($query));
$queries = array_filter($queries);
foreach ($queries as $query) {
$str1 = substr($query, 0, 1);
if ($str1 != '#' && $str1 != '-')
$ret[$num] .= $query;
}
$num++;
}
return $ret;
}
/**
* 自动备份表
* @return bool|mixed|string|null
* @throws \think\db\exception\BindParamException
*/
protected function authBackups(bool $g = false)
{
/** @var MysqlBackupService $service */
$service = app()->make(MysqlBackupService::class, [[
//数据库备份卷大小
'compress' => 1,
//数据库备份文件是否启用压缩 0不压缩 1 压缩
'level' => 5,
]]);
$dataList = $service->dataList();
$tableName = array_column($dataList, 'name');
$count = count($tableName);
if ($count) {
$this->output->writeln('+----------------------------- [自动备份] ----------------------------------+');
$this->output->newLine();
$this->output->newLine();
$this->output->writeln(' 正在自动备份[start]');
$data = [];
foreach ($tableName as $i => $t) {
// $equalStr = str_repeat("=", $i);
// $space = str_repeat(" ", $count - $i);
// $this->output->write("\r [$equalStr>$space]($i/$count%)");
$this->output->writeln(' 已备份:' . $t . ' 完成:(' . ($i + 1) . '/' . $count . ')');
$res = $service->backup($t, 0);
if ($res == false && $res != 0) {
$data [] = $t;
}
}
$this->output->writeln("\r\n 备份结束[end]");
if ($data && $g) {
return $this->output->confirm($this->input, '自动备份表失败,失败数据库表:' . implode('|', $data) . ';是否继续执行?');
}
$this->output->newLine();
}
return true;
}
/**
* 创建进度条
* @param $percent
* @return string
*/
protected function buildLine($percent)
{
$repeatTimes = 100;
if ($percent > 0) {
$hasColor = str_repeat('■', $percent);
} else {
$hasColor = '';
}
if ($repeatTimes - $percent > 0) {
$noColor = str_repeat(' ', $repeatTimes - $percent);
} else {
$noColor = '';
}
$buffer = sprintf("[{$hasColor}{$noColor}]");
if ($percent !== 100) {
$percentString = sprintf("[ %-6s]", $percent . '%');
} else {
$percentString = sprintf("[ %-5s]", 'OK');
}
return $percentString . $buffer . "\r";
}
}

46
crmeb/command/Service.php Normal file
View File

@@ -0,0 +1,46 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\command;
use think\console\command\Make;
/**
* Class Business
* @package crmeb\command
*/
class Service extends Make
{
protected $type = "Service";
protected function configure()
{
parent::configure();
$this->setName('make:service')
->setDescription('Create a new service class');
}
protected function getStub(): string
{
return __DIR__ . DIRECTORY_SEPARATOR. 'stubs' . DIRECTORY_SEPARATOR . 'service.stub';
}
protected function getNamespace(string $app): string
{
return parent::getNamespace($app) . '\\services';
}
protected function getPathName(string $name): string
{
$name = str_replace('app\\', '', $name);
return $this->app->getBasePath() . ltrim(str_replace('\\', '/', $name), '/') . 'Services.php';
}
}

View File

@@ -0,0 +1,35 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
declare (strict_types = 1);
namespace {%namespace%};
use app\dao\BaseDao;
use app\model\***\{%className%};
/**
*
* Class {%className%}Dao
* @package {%namespace%}
*/
class {%className%}Dao extends BaseDao
{
/**
* 设置模型
* @return string
*/
protected function setModel(): string
{
return {%className%}::class;
}
}

View File

@@ -0,0 +1,35 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
declare (strict_types = 1);
namespace {%namespace%};
use app\services\BaseServices;
use app\dao\***\{%className%}Dao;
/**
*
* Class {%className%}Services
* @package {%namespace%}
*/
class {%className%}Services extends BaseServices
{
/**
* {%className%}Services constructor.
* @param {%className%}Dao $dao
*/
public function __construct({%className%}Dao $dao)
{
$this->dao = $dao;
}
}

View File

@@ -0,0 +1,35 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\exceptions;
use Throwable;
/**
* Class AuthException
* @package crmeb\exceptions
*/
class AdminException extends \RuntimeException
{
public function __construct($message, $code = 0, Throwable $previous = null)
{
if(is_array($message)){
$errInfo = $message;
$message = $errInfo[1] ?? '未知错误';
if ($code === 0) {
$code = $errInfo[0] ?? 400;
}
}
parent::__construct($message, $code, $previous);
}
}

View File

@@ -0,0 +1,33 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\exceptions;
/**
* API应用错误信息
* Class ApiException
* @package crmeb\exceptions
*/
class ApiException extends \RuntimeException
{
public function __construct($message, $code = 0, \Throwable $previous = null)
{
if (is_array($message)) {
$errInfo = $message;
$message = $errInfo[1] ?? '未知错误';
if ($code === 0) {
$code = $errInfo[0] ?? 400;
}
}
parent::__construct($message, $code, $previous);
}
}

View File

@@ -0,0 +1,35 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\exceptions;
use Throwable;
/**
* Class AuthException
* @package crmeb\exceptions
*/
class AuthException extends \RuntimeException
{
public function __construct($message = "", $code = 0, Throwable $previous = null)
{
if (is_array($message)) {
$errInfo = $message;
$message = $errInfo[1] ?? '未知错误';
if ($code === 0) {
$code = $errInfo[0] ?? 400;
}
}
parent::__construct($message, $code, $previous);
}
}

View File

@@ -0,0 +1,20 @@
<?php
/**
* +----------------------------------------------------------------------
* | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
* +----------------------------------------------------------------------
* | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
* +----------------------------------------------------------------------
* | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
* +----------------------------------------------------------------------
* | Author: CRMEB Team <admin@crmeb.com>
* +----------------------------------------------------------------------
*/
namespace crmeb\exceptions;
class BadMethodCallException extends \RuntimeException
{
}

View File

@@ -0,0 +1,16 @@
<?php
namespace crmeb\exceptions;
use Throwable;
class ErpException extends \RuntimeException
{
public function __construct($message = "", $code = 0, Throwable $previous = null)
{
parent::__construct($message, $code, $previous);
}
}

View File

@@ -0,0 +1,32 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\exceptions;
/**
* Class PayException
* @package crmeb\exceptions
*/
class PayException extends \RuntimeException
{
public function __construct($message = "", $code = 0, Throwable $previous = null)
{
if (is_array($message)) {
$errInfo = $message;
$message = $errInfo[1] ?? '未知错误';
if ($code === 0) {
$code = $errInfo[0] ?? 400;
}
}
parent::__construct($message, $code, $previous);
}
}

View File

@@ -0,0 +1,35 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\exceptions;
use Throwable;
/**
* Class AuthException
* @package crmeb\exceptions
*/
class SmsException extends \RuntimeException
{
public function __construct($message = "", $code = 0, Throwable $previous = null)
{
if (is_array($message)) {
$errInfo = $message;
$message = $errInfo[1] ?? '未知错误';
if ($code === 0) {
$code = $errInfo[0] ?? 400;
}
}
parent::__construct($message, $code, $previous);
}
}

View File

@@ -0,0 +1,35 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\exceptions;
use Throwable;
/**
* Class TemplateException
* @package crmeb\exceptions
*/
class TemplateException extends \RuntimeException
{
public function __construct($message = "", $code = 0, Throwable $previous = null)
{
if (is_array($message)) {
$errInfo = $message;
$message = $errInfo[1] ?? '未知错误';
if ($code === 0) {
$code = $errInfo[0] ?? 400;
}
}
parent::__construct($message, $code, $previous);
}
}

View File

@@ -0,0 +1,35 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\exceptions;
use Throwable;
/**
* Class AuthException
* @package crmeb\exceptions
*/
class UploadException extends \RuntimeException
{
public function __construct($message = "", $code = 0, Throwable $previous = null)
{
if (is_array($message)) {
$errInfo = $message;
$message = $errInfo[1] ?? '未知错误';
if ($code === 0) {
$code = $errInfo[0] ?? 400;
}
}
parent::__construct($message, $code, $previous);
}
}

View File

@@ -0,0 +1,35 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\exceptions;
use Throwable;
/**
* 微信消息回复错误
* Class WechatReplyException
* @package crmeb\exceptions
*/
class WechatReplyException extends \RuntimeException
{
public function __construct($message = "", $code = 0, Throwable $previous = null)
{
if (is_array($message)) {
$errInfo = $message;
$message = $errInfo[1] ?? '未知错误';
if ($code === 0) {
$code = $errInfo[0] ?? 400;
}
}
parent::__construct($message, $code, $previous);
}
}

View File

@@ -0,0 +1,121 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\form;
/**
* 基础组件集成
* Class BaseComponent
* @package crmeb\form
*/
abstract class BaseComponent
{
/**
* @var bool
*/
protected $init = false;
/**
* @var array
*/
protected $rule = [];
/**
* 数据库验证
* @var array
*/
protected $validate = [];
/**
* @var CommonRule
*/
protected $validataRule;
/**
* 是否实例化
*/
protected function init()
{
if (!$this->init) {
$this->validataRule = new CommonRule;
$this->init = true;
}
}
/**
* 多个验证规则
* @param array $validate
* @return $this
*/
public function validates(array $validate)
{
$this->validate = $validate;
return $this;
}
/**
* 单个验证规则
* @param CommonRule $validate
* @return $this
*/
public function validate(CommonRule $validate)
{
$this->validate[] = $validate;
return $this;
}
/**
* 是否必填
* @return $this
*/
public function required()
{
$this->init();
$this->validataRule->required();
return $this;
}
/**
* 设置提示消息
* @param string $message
* @return $this
*/
public function message(string $message)
{
$this->init();
$this->validataRule->message($message);
return $this;
}
/**
* 数据写入
*/
protected function before()
{
if (!$this->validate && $this->validataRule instanceof CommonRule) {
if (!$this->validataRule->getMessage() && $this->rule['title']) {
$this->validataRule->message('请输入' . $this->rule['title']);
}
$this->validate[] = $this->validataRule->toArray();
}
$validate = [];
foreach ($this->validate as $item) {
if ($item instanceof CommonRule) {
$validate[] = $item->toArray();
} else {
$validate[] = $item;
}
}
$this->rule['validate'] = $validate;
}
}

262
crmeb/form/Build.php Normal file
View File

@@ -0,0 +1,262 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\form;
use crmeb\form\components\Address;
use crmeb\form\components\Alert;
use crmeb\form\components\Card;
use crmeb\form\components\CheckBox;use crmeb\form\components\DiyTable;
use crmeb\form\components\Input;
use crmeb\form\components\InputNumber;
use crmeb\form\components\Map;
use crmeb\form\components\Radio;
use crmeb\form\components\Select;
use crmeb\form\components\Switchs;
use crmeb\form\components\Tabs;
use crmeb\form\components\Time;
use crmeb\form\components\UploadFrame;
use crmeb\form\components\UploadImage;
/**
* Class Build
* @package crmeb\form
* @method Input input(string $field, string $title, $value = null)
* @method Tabs tabs(array $options = [])
* @method Card card(string $title)
* @method InputNumber inputNum(string $field, string $title, $value = null)
* @method Select select(string $field, string $title, $value = null)
* @method UploadFrame uploadFrame(string $field, string $title, $value = null)
* @method UploadImage uploadImage(string $field, string $title, $value = null)
* @method Radio radio(string $field, string $title, $value = null)
* @method CheckBox checkbox(string $field, string $title, $value = null)
* @method Switchs switch (string $field, string $title, $value = null)
* @method Alert alert (string $title, string $type = '', bool $closable = false, bool $showIcon = false)
* @method DiyTable diyTable(string $field, string $title, array $value = [], array $options = [])
* @method Map map(string $field, string $title, $value = null)
* @method Address address(string $field, string $title, $value = null)
* @method Time time(string $field, string $title, $value = null)
*/
class Build
{
/**
* 挂载组件
* @var string[]
*/
protected static array $components = [
'input' => Input::class,
'tabs' => Tabs::class,
'card' => Card::class,
'inputNum' => InputNumber::class,
'select' => Select::class,
'uploadFrame' => UploadFrame::class,
'uploadImage' => UploadImage::class,
'radio' => Radio::class,
'switch' => Switchs::class,
'alert' => Alert::class,
'diyTable' => DiyTable::class,
'address' => Address::class,
'map' => Map::class,
'time' => Time::class,
];
/**
* @var array
*/
protected array $rule = [];
/**
* 请求地址
* @var
*/
protected ?string $url;
/**
* @var string
*/
protected string $method = 'POST';
/**
* @var array
*/
protected array $data = [];
/**
* Build constructor.
* @param string|null $url
* @param array $rule
* @param string|null $method
* @param array $data
*/
public function __construct(string $url = null, array $rule = [], string $method = null, array $data = [])
{
$this->url = $url;
$this->rule = $rule;
$this->method = $method ?: 'POST';
$this->data = $data;
}
/**
* @param array $rule
* @return $this
*/
public function rule(array $rule = [])
{
$this->rule = $rule;
return $this;
}
/**
* @param string $url
* @return $this
*/
public function url(string $url)
{
$this->url = $url;
return $this;
}
/**
* @param string $method
* @return $this
*/
public function method(string $method)
{
$this->method = $method;
return $this;
}
/**
* @param array $data
* @return Build
*/
public function data(array $data)
{
$this->data = $data;
return $this;
}
/**
* 批量设置数据
* @param $rule
* @return mixed
*/
public function setValue($rule)
{
if (!$this->data) {
return $rule;
}
foreach ($rule as &$value) {
if (isset($value['value']) && $value['value'] !== '' && isset($value['field'])) {
$value['value'] = $this->data[$value['field']];
}
if (isset($value['options']) && $value['options']) {
foreach ($value['options'] as $i => $option) {
if (isset($option['componentsModel']) && $option['componentsModel']) {
$value['options'][$i] = $this->setValue($option['componentsModel']);
}
}
}
if (isset($value['control']) && $value['control']) {
foreach ($value['control'] as $ii => $control) {
if (isset($control['componentsModel']) && $control['componentsModel']) {
$value['control'][$ii] = $this->setValue($control['componentsModel']);
}
}
}
if (isset($value['componentsModel']) && $value['componentsModel']) {
$value['componentsModel'] = $this->setValue($value['componentsModel']);
}
}
return $rule;
}
/**
* 提取验证值
* @param $rule
* @return array
*/
protected function getValidate($rule)
{
$validate = [];
foreach ($rule as $value) {
if (isset($value['field']) && isset($value['validate']) && $value['validate']) {
$validate[$value['field']] = $value['validate'];
}
if (isset($value['options']) && $value['options']) {
foreach ($value['options'] as $option) {
if (isset($option['componentsModel']) && $option['componentsModel']) {
$validate = array_merge($validate, $this->getValidate($option['componentsModel']));
}
}
}
if (isset($value['control']) && $value['control']) {
foreach ($value['control'] as $control) {
if (isset($control['componentsModel']) && $control['componentsModel']) {
$validate = array_merge($validate, $this->getValidate($control['componentsModel']));
}
}
}
if (isset($value['componentsModel']) && $value['componentsModel']) {
$validate = array_merge($validate, $this->getValidate($value['componentsModel']));
}
}
return $validate;
}
/**
* @return array
*/
public function toArray()
{
$rule = [];
foreach ($this->rule as $item) {
if ($item instanceof BuildInterface) {
$rule[] = $item->toArray();
}
}
$data = [
'rules' => $this->setValue($rule),
'validate' => $this->getValidate($rule),
'url' => $this->url,
'method' => $this->method
];
$data['validate'] = $data['validate'] ?: (object)[];
$this->url = null;
$this->rule = [];
$this->method = 'POST';
return $data;
}
/**
* @return false|string
*/
public function toString()
{
return json_encode($this->toArray());
}
/**
* @param $name
* @param $arguments
* @return mixed
*/
public static function __callStatic($name, $arguments)
{
$compKeys = array_keys(self::$components);
if (in_array($name, $compKeys)) {
return new self::$components[$name](...$arguments);
}
throw new BuildException('Method does not exist');
}
}

View File

@@ -0,0 +1,27 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\form;
use Throwable;
/**
* Class BuildException
* @package crmeb\form
*/
class BuildException extends \RuntimeException
{
public function __construct($message = "", $code = 0, Throwable $previous = null)
{
parent::__construct($message, $code, $previous);
}
}

View File

@@ -0,0 +1,24 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\form;
/**
* Interface BuildInterface
* @package crmeb\form
*/
interface BuildInterface
{
public function toArray(): array;
}

180
crmeb/form/CommonRule.php Normal file
View File

@@ -0,0 +1,180 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\form;
/**
* Class CommonRule
* @package crmeb\form
*/
class CommonRule implements BuildInterface
{
/**
* 验证类型
*/
const VALIDATE_TYPE = ['string', 'number', 'boolean', 'method', 'regexp', 'integer', 'float', 'array', 'object', 'enum', 'date', 'url', 'hex', 'email'];
/**
* @var string
*/
protected $type = '';
/**
* @var bool
*/
protected $required = false;
/**
* @var string
*/
protected $pattern = '';
/**
* 枚举值
* @var array
*/
protected $enum = [];
/**
* 提示语
* @var string
*/
protected $message = '';
/**
* 深度验证对象
* @var array
*/
protected $fields = [];
/**
* 验证触发方式
* @var string
*/
protected $trigger = 'blur';
/**
* @param string $type
* @return $this
*/
public function type(string $type)
{
$this->type = in_array($type, self::VALIDATE_TYPE) ? $type : null;
if (!$this->type) {
throw new FormValidate('验证类型错误');
}
return $this;
}
/**
* 是否必填
* @return $this
*/
public function required()
{
$this->required = true;
return $this;
}
/**
* 设置错误提示
* @param string $message
* @return $this
*/
public function message(string $message)
{
$this->message = $message;
return $this;
}
/**
* 提示语
* @return string
*/
public function getMessage()
{
return $this->message;
}
/**
* 枚举数据
* @param array $enum
* @return $this
*/
public function enum(array $enum)
{
$this->enum = $enum;
return $this;
}
/**
* 正则表达式
* @param string $pattern
* @return $this
*/
public function pattern(string $pattern)
{
$this->pattern = $pattern;
return $this;
}
/**
* 验证规则
* @param string|array|BuildInterface $field
* @param array $rule
* @return $this
*/
public function field($field, array $rule = [])
{
if (!in_array($this->type, ['array', 'object'])) {
throw new BuildException('无效规则,类型只能在array或者object情况下才可设置');
}
if ($this->type === 'array') {
$rules = [];
if ($field instanceof BuildInterface) {
$rules = $field->toArray();
}
$this->fields[] = $rules;
} else {
$rules = [];
foreach ($rule as $item) {
if ($item instanceof BuildInterface) {
$rules[] = $item->toArray();
}
}
$this->fields[$field] = $rules;
}
return $this;
}
/**
* 数据转换
* @return array
*/
public function toArray(): array
{
$data = [
'required' => $this->required,
'message' => $this->message,
'trigger' => $this->trigger,
'pattern' => $this->pattern,
'enum' => $this->enum,
'type' => $this->type
];
$res = [];
foreach ($data as $key => $value) {
if (is_bool($value) || $value) {
$res[$key] = $value;
}
}
return $res;
}
}

View File

@@ -0,0 +1,25 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\form;
/**
* Class FormValidate
* @package crmeb\form
*/
class FormValidate extends \RuntimeException
{
public function __construct($message = "", $code = 0, Throwable $previous = null)
{
parent::__construct($message, $code, $previous);
}
}

View File

@@ -0,0 +1,70 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\form\components;
use crmeb\form\BaseComponent;
use crmeb\form\BuildInterface;
/**
* 选择地址
* Class Addres
* @package crmeb\form\components
*/
class Address extends BaseComponent implements BuildInterface
{
const NAME = 'address';
/**
* @var string[]
*/
protected $rule = [
'title' => '',
'field' => '',
'value' => '',
'info' => '',
];
/**
* Map constructor.
* @param string $field
* @param string $title
* @param array $value
*/
public function __construct(string $field, string $title, array $value = null)
{
$this->rule['field'] = $field;
$this->rule['title'] = $title . ':';
$this->rule['value'] = empty($value) ? '' : $value;
}
/**
* @param string $info
* @return $this
*/
public function info(string $info)
{
$this->rule['info'] = $info;
return $this;
}
/**
* @return array|string[]
*/
public function toArray(): array
{
$this->rule['name'] = self::NAME;
$this->before();
return $this->rule;
}
}

View File

@@ -0,0 +1,102 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\form\components;
use crmeb\form\BuildInterface;
/**
* 警告框
* Class Alert
* @package crmeb\form\components
*/
class Alert implements BuildInterface
{
//组件名
const NAME = 'alert';
//提示类型
const INFO = 'info';
//成功类型
const SUCCESS = 'success';
//警告类型
const WARNING = 'warning';
//错误类型
const ERROR = 'error';
//组件类型
const TYPE = [self::INFO, self::SUCCESS, self::WARNING, self::ERROR];
/**
* 规则
* @var array
*/
protected $rule = [
'title' => '',
'type' => '',
'closable' => false,
'showIcon' => false
];
/**
* Alert constructor.
* @param string $title
* @param string $type
* @param bool $closable
* @param bool $showIcon
*/
public function __construct(string $title, string $type = '', bool $closable = false, bool $showIcon = false)
{
$this->rule['type'] = in_array($type, self::TYPE) ? $type : '';
$this->rule['title'] = $title . ':';
$this->rule['closable'] = $closable;
$this->rule['showIcon'] = $showIcon;
}
/**
* 设置类型
* @param string $type
* @return $this
*/
public function type(string $type)
{
$this->rule['type'] = in_array($type, self::TYPE) ? $type : '';
return $this;
}
/**
* 是否可关闭
* @param bool $closable
* @return $this
*/
public function closable(bool $closable = false)
{
$this->rule['closable'] = $closable;
return $this;
}
/**
* 是否展示图标
* @param bool $showIcon
* @return $this
*/
public function showIcon(bool $showIcon = false)
{
$this->rule['showIcon'] = $showIcon;
return $this;
}
public function toArray(): array
{
$this->rule['name'] = self::NAME;
return $this->rule;
}
}

View File

@@ -0,0 +1,74 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\form\components;
use crmeb\form\BuildInterface;
/**
* 卡片组件
* Class Card
* @package crmeb\form\components
*/
class Card implements BuildInterface
{
/**
* 组件名
*/
const NAME = 'card';
/**
* 规则
* @var array
*/
protected $rule = [
'componentsModel' => [],
'title' => '',
];
/**
* Card constructor.
* @param string $title
*/
public function __construct(string $title)
{
$this->rule['title'] = $title;
}
/**
* 添加组件群
* @param array $components
* @return $this
*/
public function components(array $components = [])
{
$this->rule['componentsModel'] = $components;
return $this;
}
/**
* @return array
*/
public function toArray(): array
{
$this->rule['name'] = self::NAME;
$componentsModel = [];
foreach ($this->rule['componentsModel'] as $item) {
if ($item instanceof BuildInterface) {
$componentsModel[] = $item->toArray();
}
}
$this->rule['componentsModel'] = $componentsModel;
return $this->rule;
}
}

View File

@@ -0,0 +1,90 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\form\components;
use crmeb\form\BaseComponent;
use crmeb\form\BuildInterface;
/**
* 多选组件
* Class CheckBox
* @package crmeb\form\components
*/
class CheckBox extends BaseComponent implements BuildInterface
{
/**
* 组件名
*/
const NAME = 'checkbox';
/**
* 组件规则
* @var array
*/
protected $rule = [
'title' => '',
'field' => '',
'value' => [],
'info' => '',
'options' => [],
];
/**
* Radio constructor.
* @param string $title
* @param string $field
* @param null $value
*/
public function __construct(string $field, string $title, array $value = null)
{
$this->rule['title'] = $title . ':';
$this->rule['field'] = $field;
$this->rule['value'] = !is_null($value) ? $value : null;
}
/**
* options数据 ['label'=>'确定','value'=>1]
* @param array $options
* @return $this
*/
public function options(array $options = [])
{
$this->rule['options'] = $options;
return $this;
}
/**
* 设置提示语
* @param string $info
* @return $this
*/
public function info(string $info)
{
$this->rule['info'] = $info;
return $this;
}
/**
* 数据转换
* @return array
*/
public function toArray(): array
{
$this->rule['name'] = self::NAME;
$this->before();
return $this->rule;
}
}

View File

@@ -0,0 +1,91 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\form\components;
use crmeb\form\BaseComponent;
use crmeb\form\BuildInterface;
/**
* 自定义表格
* Class DiyTable
* @package crmeb\form\components
*/
class DiyTable extends BaseComponent implements BuildInterface
{
/**
* 组件名称
*/
const NAME = 'diyTable';
//内部表格自定义类型
const TYPE = ['input', 'select', 'inputNumber', 'switch'];
/**
* 规则
* @var string[]
*/
protected $rule = [
'title' => '',
'value' => [],
'type' => '',
'field' => '',
'options' => [],
'info' => '',
];
/**
* DiyTable constructor.
* @param string $field
* @param string $title
* @param array $value
* @param array $options
*/
public function __construct(string $field, string $title, array $value = [], array $options = [])
{
$this->rule['title'] = $title . ':';
$this->rule['field'] = $field;
$this->rule['options'] = $options;
$this->rule['value'] = $value;
}
/**
* @param string $info
* @return $this
*/
public function info(string $info)
{
$this->rule['info'] = $info;
return $this;
}
/**
* 设置列
* @param string $name
* @param string $key
* @param string $type
* @param array $props
* @return $this
*/
public function column(string $name, string $key, string $type = 'input', array $props = [])
{
$this->rule['options'][] = ['name' => $name, 'key' => $key, 'type' => $type, 'props' => $props];
return $this;
}
public function toArray(): array
{
$this->rule['name'] = self::NAME;
$this->before();
return $this->rule;
}
}

View File

@@ -0,0 +1,132 @@
<?php
namespace crmeb\form\components;
use crmeb\form\BaseComponent;
use crmeb\form\BuildInterface;
/**
* 输入框组件
* Class Input
* @package crmeb\form\components
* @method Input info(string $info) 设置info
* @method Input placeholder(string $placeholder) 设置placeholder
* @method Input suffix(string $suffix) 输入框头部图标
* @method Input prefix(string $prefix) 输入框尾部图标
* @method Input value($value) 设置value
* @method Input rows(int $rows) 设置rows
* @method Input type(string $type) 设置type
* @method Input maxlength(int $maxlength) 设置maxlength
*/
class Input extends BaseComponent implements BuildInterface
{
/**
* 组件名称
*/
const NAME = 'input';
/**
* 规则
* @var string[]
*/
protected $rule = [
'title' => '',
'value' => '',
'type' => '',
'field' => '',
'info' => '',
'disabled' => false,
'placeholder' => '',
'suffix' => '',
'prefix' => '',
'rows' => 2,
'copy' => false,
'copyText' => '',
'randToken' => 0,
'maxlength' => null,
];
/**
* Input constructor.
* @param string $field
* @param string $title
* @param null $value
*/
public function __construct(string $field, string $title, $value = null)
{
$this->rule['title'] = $title . ':';
$this->rule['field'] = $field;
$this->rule['value'] = empty($value) ? '' : $value;
}
/**
* 是否禁用
* @param bool $disabled
* @return $this
*/
public function disabled(bool $disabled = true)
{
$this->rule['disabled'] = $disabled;
return $this;
}
/**
* 随机token
* @return $this
*/
public function randToken()
{
$this->rule['randToken'] = 1;
return $this;
}
/**
* 随机encodingAESKeyGen
* @return $this
*/
public function randAESK()
{
$this->rule['randToken'] = 2;
return $this;
}
/**
* 复制按钮
* @param string $copyText
* @return $this
*/
public function copy(string $copyText = '复制')
{
$this->rule['copy'] = true;
$this->rule['copyText'] = $copyText;
return $this;
}
/**
* @return string[]
*/
public function toArray(): array
{
$this->rule['name'] = self::NAME;
$this->before();
return $this->rule;
}
/**
* @param $name
* @param $arguments
* @return $this
*/
public function __call($name, $arguments)
{
if (in_array($name, ['title', 'field', 'disabled', 'copyText'])) {
return $this;
}
$keys = array_keys($this->rule);
if (in_array($name, $keys)) {
$this->rule[$name] = $arguments[0] ?? null;
}
return $this;
}
}

View File

@@ -0,0 +1,118 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\form\components;
use crmeb\form\BaseComponent;
use crmeb\form\BuildInterface;
/**
* 数字输入框
* Class InputNumber
* @package crmeb\form\components
*/
class InputNumber extends BaseComponent implements BuildInterface
{
/**
* 组件名
*/
const NAME = 'inputNumber';
/**
* 规则
* @var string[]
*/
protected $rule = [
'title' => '',
'value' => '',
'type' => '',
'field' => '',
'prefix' => '',
'suffix' => '',
'info' => '',
'min' => null,
'max' => 99999999
];
/**
* InputNumber constructor.
* @param string $field
* @param string $title
* @param null $value
*/
public function __construct(string $field, string $title, $value = null)
{
$this->rule['title'] = $title . ':';
$this->rule['field'] = $field;
$this->rule['value'] = floatval($value);
}
/**
* 提示语
* @param string $info
* @return $this
*/
public function info(string $info)
{
$this->rule['info'] = $info;
return $this;
}
/**
* 最小值
* @param int $min
* @return $this
*/
public function min(int $min)
{
$this->rule['min'] = $min;
return $this;
}
/**
* 最大值
* @param int $max
* @return $this
*/
public function max(int $max)
{
$this->rule['max'] = $max;
return $this;
}
/**
* @return array|string[]
*/
public function toArray(): array
{
$this->rule['name'] = self::NAME;
$this->before();
return $this->rule;
}
/**
* @param $name
* @param $arguments
* @return $this
*/
public function __call($name, $arguments)
{
if (in_array($name, ['title', 'field'])) {
return $this;
}
$keys = array_keys($this->rule);
if (in_array($name, $keys)) {
$this->rule[$name] = $arguments[0] ?? null;
}
}
}

View File

@@ -0,0 +1,70 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\form\components;
use crmeb\form\BaseComponent;
use crmeb\form\BuildInterface;
/**
* 地图组件
* Class Map
* @package crmeb\form\components
*/
class Map extends BaseComponent implements BuildInterface
{
const NAME = 'map';
/**
* @var string[]
*/
protected $rule = [
'title' => '',
'field' => '',
'value' => '',
'info' => '',
];
/**
* Map constructor.
* @param string $field
* @param string $title
* @param string $value
*/
public function __construct(string $field, string $title, string $value = null)
{
$this->rule['field'] = $field;
$this->rule['title'] = $title . ':';
$this->rule['value'] = empty($value) ? '' : $value;
}
/**
* @param string $info
* @return $this
*/
public function info(string $info)
{
$this->rule['info'] = $info;
return $this;
}
/**
* @return array|string[]
*/
public function toArray(): array
{
$this->rule['name'] = self::NAME;
$this->before();
return $this->rule;
}
}

View File

@@ -0,0 +1,134 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\form\components;
use crmeb\form\BaseComponent;
use crmeb\form\BuildInterface;
/**
* 单选框组件
* Class Radio
* @package crmeb\form\components
*/
class Radio extends BaseComponent implements BuildInterface
{
/**
* 组件名
*/
const NAME = 'radio';
/**
* 组件规则
* @var array
*/
protected $rule = [
'title' => '',
'field' => '',
'value' => 0,
'info' => '',
'vertical' => false,
'control' => [],
'options' => [],
];
/**
* Radio constructor.
* @param string $title
* @param string $field
* @param null $value
*/
public function __construct(string $field, string $title, $value = null)
{
$this->rule['title'] = $title . ':';
$this->rule['field'] = $field;
$this->rule['value'] = !is_null($value) ? $value : null;
}
/**
* 多个组件联动
* @param array $controls
* @return $this
*/
public function controls(array $controls = [])
{
$this->rule['control'] = $controls;
return $this;
}
/**
* options数据 ['label'=>'确定','value'=>1]
* @param array $options
* @return $this
*/
public function options(array $options = [])
{
$this->rule['options'] = $options;
return $this;
}
/**
* 组件联动
* @param $value
* @param array $components
* @return $this
*/
public function control($value, array $components = [])
{
$this->rule['control'][] = ['value' => $value, 'componentsModel' => $components];
return $this;
}
/**
* 设置提示语
* @param string $info
* @return $this
*/
public function info(string $info)
{
$this->rule['info'] = $info;
return $this;
}
/**
* 是否垂直展示
* @param bool $vertical
* @return $this
*/
public function vertical(bool $vertical)
{
$this->rule['vertical'] = $vertical;
return $this;
}
/**
* 数据转换
* @return array
*/
public function toArray(): array
{
$this->rule['name'] = self::NAME;
$control = [];
foreach ($this->rule['control'] as $item) {
$data = ['value' => $item['value'], 'componentsModel' => []];
foreach ($item['componentsModel'] as $value) {
if ($value instanceof BuildInterface) {
$data['componentsModel'][] = $value->toArray();
}
}
$control[] = $data;
}
$this->rule['control'] = $control;
$this->before();
return $this->rule;
}
}

View File

@@ -0,0 +1,90 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\form\components;
use crmeb\form\BaseComponent;
use crmeb\form\BuildInterface;
/**
* 多选组件
* Class Select
* @package crmeb\form\components
* @method placeholder(string $placeholder)
* @method options(array $options = [])
* @method info(string $info)
*/
class Select extends BaseComponent implements BuildInterface
{
/**
* 组件名
*/
const NAME = 'select';
/**
* 规则
* @var string[]
*/
protected $rule = [
'title' => '',
'value' => '',
'type' => '',
'field' => '',
'info' => '',
'placeholder' => '',
'options' => [],
];
/**
* Radio constructor.
* @param string $title
* @param string $field
* @param null $value
*/
public function __construct(string $field, string $title, $value = null)
{
$this->rule['title'] = $title . ':';
$this->rule['field'] = $field;
$this->rule['value'] = !is_null($value) ? $value : null;
}
/**
* 转换数据
* @return array|string[]
*/
public function toArray(): array
{
$this->rule['name'] = self::NAME;
$this->before();
return $this->rule;
}
/**
* @param $name
* @param $arguments
* @return $this
*/
public function __call($name, $arguments)
{
if (in_array($name, ['title', 'field'])) {
return $this;
}
$keys = array_keys($this->rule);
if (in_array($name, $keys)) {
$this->rule[$name] = $arguments[0] ?? null;
}
return $this;
}
}

View File

@@ -0,0 +1,135 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\form\components;
use crmeb\form\BaseComponent;
use crmeb\form\BuildInterface;
/**
* 开关组件
* Class Switchs
* @package crmeb\form\components
*/
class Switchs extends BaseComponent implements BuildInterface
{
/**
* 组件名
*/
const NAME = 'switch';
/**
* 规则
* @var array
*/
protected $rule = [
'title' => '',
'field' => '',
'value' => '',
'info' => '',
'control' => [],
'options' => [],
];
/**
* Switchs constructor.
* @param string $field
* @param string $title
* @param int $value
*/
public function __construct(string $field, string $title, int $value = null)
{
$this->rule['title'] = $title . ':';
$this->rule['field'] = $field;
$this->rule['value'] = !is_null($value) ? intval($value) : null;
}
/**
* 多组件群添加
* @param array $controls
* @return $this
*/
public function controls(array $controls = [])
{
$this->rule['control'] = $controls;
return $this;
}
/**
* 组件联动添加
* @param $value
* @param array $components
* @return $this
*/
public function control(int $value, array $components = [])
{
$this->rule['control'][] = ['value' => $value, 'componentsModel' => $components];
return $this;
}
/**
* 开启值和名称设置
* @param string $label
* @param int $value
* @return $this
*/
public function trueValue(string $label, int $value)
{
$this->rule['options'][] = ['trueValue' => $value, 'label' => $label];
return $this;
}
/**
* 关闭值和名称设置
* @param string $label
* @param int $value
* @return $this
*/
public function falseValue(string $label, int $value)
{
$this->rule['options'][] = ['falseValue' => $value, 'label' => $label];
return $this;
}
/**
* 设置提示信息
* @param string $info
* @return $this
*/
public function info(string $info)
{
$this->rule['info'] = $info;
return $this;
}
/**
* 数据转换
* @return array
*/
public function toArray(): array
{
$this->rule['name'] = self::NAME;
$control = [];
foreach ($this->rule['control'] as $item) {
$data = ['value' => $item['value'], 'componentsModel' => []];
foreach ($item['componentsModel'] as $value) {
if ($value instanceof BuildInterface) {
$data['componentsModel'][] = $value->toArray();
}
}
$control[] = $data;
}
$this->rule['control'] = $control;
$this->before();
return $this->rule;
}
}

View File

@@ -0,0 +1,76 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\form\components;
use crmeb\form\BuildInterface;
/**
* Tabs 组件
* Class Tabs
* @package crmeb\form\components
*/
class Tabs implements BuildInterface
{
//组件名
const NAME = 'tabs';
/**
* 规则
* @var array[]
*/
protected $rule = [
'options' => []
];
/**
* Tabs constructor.
* @param array $options
*/
public function __construct(array $options = [])
{
$this->rule['options'] = $options;
}
/**
* 添加单个选项卡组件群
* @param string $label
* @param array $components
* @return $this
*/
public function option(string $label, array $components = [])
{
$this->rule['options'][] = ['label' => $label, 'componentsModel' => $components];
return $this;
}
/**
* @return array|array[]
*/
public function toArray(): array
{
$this->rule['name'] = self::NAME;
$options = [];
foreach ($this->rule['options'] as $option) {
$data = ['label' => $option['label'], 'componentsModel' => []];
foreach ($option['componentsModel'] as $item) {
if ($item instanceof BuildInterface) {
$data['componentsModel'][] = $item->toArray();
}
}
$options[] = $data;
}
$this->rule['options'] = $options;
return $this->rule;
}
}

View File

@@ -0,0 +1,85 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\form\components;
use crmeb\form\BaseComponent;
use crmeb\form\BuildInterface;
/**
* 时间组件
* Class Time
* @package crmeb\form\components
* @method Time info(string $info) 设置info
* @method Time value($value) 设置value
* @method Time type(string $type) 设置type
* @method Time placeholder(string $placeholder) 设置placeholder
*/
class Time extends BaseComponent implements BuildInterface
{
const NAME = 'time';
/**
* @var string[]
*/
protected $rule = [
'title' => '',
'value' => '',
'field' => '',
'info' => '',
'placeholder' => '',
'format' => 'HH:mm:ss',
'type' => 'timerange'
];
/**
* Time constructor.
* @param string $field
* @param string $title
* @param array|null $value
*/
public function __construct(string $field, string $title, array $value = null)
{
$this->rule['field'] = $field;
$this->rule['title'] = $title . ':';
$this->rule['value'] = empty($value) ? '' : $value;
}
/**
* @return array|string[]
*/
public function toArray(): array
{
$this->rule['name'] = self::NAME;
$this->before();
return $this->rule;
}
/**
* @param $name
* @param $arguments
* @return $this
*/
public function __call($name, $arguments)
{
if (in_array($name, ['title', 'field', 'disabled', 'copyText'])) {
return $this;
}
$keys = array_keys($this->rule);
if (in_array($name, $keys)) {
$this->rule[$name] = $arguments[0] ?? null;
}
return $this;
}
}

View File

@@ -0,0 +1,140 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\form\components;
use crmeb\form\BaseComponent;
use crmeb\form\BuildInterface;
/**
* 图片选择组件
* Class UploadFrame
* @package crmeb\form\components
*/
class UploadFrame extends BaseComponent implements BuildInterface
{
/**
* 组件名
*/
const NAME = 'uploadFrame';
/**
* 规则
* @var array
*/
protected $rule = [
'upload' => [
'url' => '',
'width' => '960px',
'height' => '505px',
'field' => 'att_dir',
'maxNum' => 1,
],
'field' => '',
'title' => '',
'value' => '',
'info' => '',
];
/**
* UploadFrame constructor.
* @param string $field
* @param string $title
* @param null $value
*/
public function __construct(string $field, string $title, $value = null)
{
$this->rule['title'] = $title . ':';
$this->rule['field'] = $field;
$this->rule['value'] = !is_null($value) ? $value : null;
}
/**
* 设置iframe跳转地址
* @param string $url
* @return $this
*/
public function url(string $url)
{
$this->rule['upload']['url'] = $url;
return $this;
}
/**
* 设置iframe宽
* @param string $width
* @return $this
*/
public function width(string $width = '960px')
{
$this->rule['upload']['width'] = $width;
return $this;
}
/**
* 设置iframe高
* @param string $height
* @return $this
*/
public function height(string $height = '505px')
{
$this->rule['upload']['height'] = $height;
return $this;
}
/**
* 设置提取字段
* @param string $field
* @return $this
*/
public function field(string $field)
{
$this->rule['upload']['field'] = $field;
return $this;
}
/**
* 多图单图选择
* @param int $maxNum
* @return $this
*/
public function maxNum(int $maxNum = 1)
{
$this->rule['upload']['maxNum'] = $maxNum;
return $this;
}
/**
* 设置提示
* @param string $info
* @return $this
*/
public function info(string $info)
{
$this->rule['info'] = $info;
return $this;
}
/**
* @return array
*/
public function toArray(): array
{
if ($this->rule['upload']['maxNum'] > 1 && $this->rule['value'] && !is_array($this->rule['value'])) {
$this->rule['value'] = [];
}
$this->rule['name'] = self::NAME;
$this->before();
return $this->rule;
}
}

View File

@@ -0,0 +1,156 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\form\components;
use crmeb\form\BaseComponent;
use crmeb\form\BuildInterface;
/**
* 文件上传组件
* Class UploadImage
* @package crmeb\form\components
*/
class UploadImage extends BaseComponent implements BuildInterface
{
// 组件名
const NAME = 'uploadImage';
//图片类型
const IMAGE = 'image';
//文件类型
const FILE = 'file';
//上传支持类型
const TYPE = [self::IMAGE, self::FILE];
/**
* 规则
* @var array
*/
protected $rule = [
'upload' => [
'url' => '',
'size' => 2097152,
'format' => [],
'headers' => [],
'maxNum' => 1,
],
'field' => '',
'type' => '',
'title' => '',
'icon' => '',
'info' => '',
'value' => ''
];
/**
* UploadImage constructor.
* @param string $field
* @param string $title
* @param null $value
*/
public function __construct(string $field, string $title, $value = null)
{
$this->rule['title'] = $title . ':';
$this->rule['field'] = $field;
$this->rule['value'] = !is_null($value) ? $value : null;
}
/**
* 上传地址
* @param string $url
* @return $this
*/
public function url(string $url)
{
$this->rule['upload']['url'] = $url;
return $this;
}
/**
* 上传类型
* @param string $type
* @return $this
*/
public function type(string $type)
{
$this->rule['type'] = in_array($type, self::TYPE) ? $type : '';
return $this;
}
/**
* 上传展示icon
* @param string $icon
* @return $this
*/
public function icon(string $icon)
{
$this->rule['icon'] = $icon;
return $this;
}
/**
* 上传文件headers
* @param array $headers
* @return $this
*/
public function headers(array $headers = [])
{
$this->rule['upload']['headers'] = (object)$headers;
return $this;
}
/**
* 上传文件大小
* @param string $size
* @return $this
*/
public function size(string $size)
{
$this->rule['upload']['size'] = $size;
return $this;
}
/**
* 上传文件类型
* @param array $format
* @return $this
*/
public function format(array $format = [])
{
$this->rule['upload']['format'] = $format;
return $this;
}
/**
* 组件提示
* @param string $info
* @return $this
*/
public function info(string $info)
{
$this->rule['info'] = $info;
return $this;
}
/**
* @return array
*/
public function toArray(): array
{
$this->rule['name'] = self::NAME;
$this->before();
return $this->rule;
}
}

View File

@@ -0,0 +1,30 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\form\validate;
/**
* 数组
* Class ArrRules
* @package crmeb\form\validate
*/
class ArrRules extends BaseRules
{
/**
* @return string
*/
public static function getType(): string
{
return 'array';
}
}

View File

@@ -0,0 +1,72 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\form\validate;
use crmeb\form\CommonRule;
/**
* Class BaseRules
* @package crmeb\form\validate
* @method CommonRule required() 是否必填
* @method CommonRule message(string $message) 设置错误提示
* @method CommonRule enum(array $enum) 枚举
* @method CommonRule pattern(string $pattern) 正则表达式
* @method CommonRule field($field, array $rule = []) 验证规则
*/
abstract class BaseRules
{
/**
* 是否初始化
* @var bool
*/
protected static $init = false;
/**
* @var CommonRule
*/
protected static $rule;
/**
* @return mixed
*/
public static function getType(): string
{
return '';
}
/**
* 初始化
*/
public static function init()
{
if (!self::$init) {
self::$rule = new CommonRule();
self::$rule->type(static::getType());
self::$init = true;
}
}
/**
* @param $name
* @param $arguments
* @return mixed
*/
public static function __callStatic($name, $arguments)
{
self::init();
if (method_exists(self::$rule, $name)) {
return self::$rule->{$name}(...$arguments);
}
throw new FormValidate(__CLASS__ . ' Method does not exist' . $name . '()');
}
}

View File

@@ -0,0 +1,29 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\form\validate;
/**
* 布尔
* Class BoolRules
* @package crmeb\form\validate
*/
class BoolRules extends BaseRules
{
/**
* @return string
*/
public static function getType(): string
{
return 'boolean';
}
}

View File

@@ -0,0 +1,29 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\form\validate;
/**
* 日期
* Class DateRules
* @package crmeb\form\validate
*/
class DateRules extends BaseRules
{
/**
* @return string
*/
public static function getType(): string
{
return 'date';
}
}

View File

@@ -0,0 +1,29 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\form\validate;
/**
* 邮箱
* Class EmailRules
* @package crmeb\form\validate
*/
class EmailRules extends BaseRules
{
/**
* @return string
*/
public static function getType(): string
{
return 'email';
}
}

View File

@@ -0,0 +1,29 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\form\validate;
/**
* 枚举
* Class EnumRules
* @package crmeb\form\validate
*/
class EnumRules extends BaseRules
{
/**
* @return string
*/
public static function getType(): string
{
return 'enum';
}
}

View File

@@ -0,0 +1,29 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\form\validate;
/**
* 浮点
* Class FloatRules
* @package crmeb\form\validate
*/
class FloatRules extends BaseRules
{
/**
* @return string
*/
public static function getType(): string
{
return 'float';
}
}

View File

@@ -0,0 +1,28 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\form\validate;
/**
*
* Class FunRules
* @package crmeb\form\validate
*/
class FunRules extends BaseRules
{
/**
* @return string
*/
public static function getType(): string
{
return 'method';
}
}

View File

@@ -0,0 +1,29 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\form\validate;
/**
* 16进制
* Class HexRules
* @package crmeb\form\validate
*/
class HexRules extends BaseRules
{
/**
* @return string
*/
public static function getType(): string
{
return 'hex';
}
}

View File

@@ -0,0 +1,28 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\form\validate;
/**
* Class IntRules
* @package crmeb\form\validate
*/
class IntRules extends BaseRules
{
/**
* @return string
*/
public static function getType(): string
{
return 'integer';
}
}

View File

@@ -0,0 +1,28 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\form\validate;
/**
* Class NumRules
* @package crmeb\form\validate
*/
class NumRules extends BaseRules
{
/**
* @return string
*/
public static function getType(): string
{
return 'number';
}
}

View File

@@ -0,0 +1,27 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\form\validate;
/**
* Class ObjRules
* @package crmeb\form\validate
*/
class ObjRules extends BaseRules
{
/**
* @return string
*/
public static function getType(): string
{
return 'object';
}
}

View File

@@ -0,0 +1,27 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\form\validate;
/**
* Class RegRules
* @package crmeb\form\validate
*/
class RegRules extends BaseRules
{
/**
* @return string
*/
public static function getType(): string
{
return 'regexp';
}
}

View File

@@ -0,0 +1,37 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\form\validate;
use crmeb\form\FormValidate;
/**
* Class StrRules
* @package crmeb\form\validate
*/
class StrRules extends BaseRules
{
/**
* 手机号正则
*/
const PHONE_NUMBER = '/((\d{3,4}-)?[0-9]{7,8}$)|(^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])[0-9]{8}$)/';
/**
* 设置类型
* @return string
*/
public static function getType(): string
{
return 'string';
}
}

View File

@@ -0,0 +1,28 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\form\validate;
/**
* Class UrlRules
* @package crmeb\form\validate
*/
class UrlRules extends BaseRules
{
/**
* @return string
*/
public static function getType(): string
{
return 'url';
}
}

View File

@@ -0,0 +1,42 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2018 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: yunwuxin <448901948@qq.com>
// +----------------------------------------------------------------------
namespace crmeb\interfaces;
use Swoole\Websocket\Frame;
use think\Request;
interface HandlerInterface
{
/**
* "onOpen" listener.
*
* @param int $fd
* @param Request $request
*/
public function onOpen($fd, Request $request);
/**
* "onMessage" listener.
* only triggered when event handler not found
*
* @param Frame $frame
*/
public function onMessage(Frame $frame);
/**
* "onClose" listener.
*
* @param int $fd
* @param int $reactorId
*/
public function onClose($fd, $reactorId);
}

View File

@@ -0,0 +1,20 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\interfaces;
use think\queue\Job;
interface JobInterface
{
public function fire(Job $job, $data): void;
}

View File

@@ -0,0 +1,18 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\interfaces;
interface ListenerInterface
{
public function handle($event): void;
}

View File

@@ -0,0 +1,20 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\interfaces;
use app\Request;
interface MiddlewareInterface
{
public function handle(Request $request, \Closure $next);
}

View File

@@ -0,0 +1,19 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\interfaces;
interface ProviderInterface
{
public function register($config);
}

View File

@@ -0,0 +1,50 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\listeners;
use app\listener\system\AutoConfig;
use crmeb\interfaces\ListenerInterface;
use crmeb\utils\Start;
use think\facade\Event;
use think\swoole\Manager;
use Swoole\Process\Pool;
/**
* swoole 初始化
*/
class InitSwooleLockListen implements ListenerInterface
{
public function handle($event): void
{
//注入事件
Event::listen('get.config', AutoConfig::class);
//启动时输出内容
app()->make(Start::class)->show();
//增加定时任务进程
app()->make(Manager::class)->addBatchWorker(1, [$this, 'createCronServer'], 'cron server');
}
/**
* 创建定时任务服务 - 单独启动一个进程做为定时任务执行进程
* @author 等风来
* @email 136327134@qq.com
* @date 2023/10/7
*/
public function createCronServer(Pool $pool, $workerId)
{
event('crontab', $workerId);
}
}

View File

@@ -0,0 +1,34 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\listeners;
use crmeb\interfaces\ListenerInterface;
use think\facade\Log;
/**
* swoole 定时任务
*/
class SwooleCronListen implements ListenerInterface
{
public function handle($event): void
{
try {
event('crontab');//app/event.php 里面配置事件
} catch (\Throwable $e) {
Log::error('监听定时器报错: ' . $e->getMessage());
}
}
}

View File

@@ -0,0 +1,28 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\listeners;
use crmeb\interfaces\ListenerInterface;
use Swoole\Timer;
/**
* swoole 停止
*/
class SwooleShutdownListen implements ListenerInterface
{
public function handle($event): void
{
Timer::clearAll();
}
}

View File

@@ -0,0 +1,33 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\listeners;
use crmeb\interfaces\ListenerInterface;
/**
* swoole启动监听
* Class SwooleStartListen
* @package crmeb\listeners
*/
class SwooleStartListen implements ListenerInterface
{
/**
* 事件执行
* @param $event
*/
public function handle($event): void
{
}
}

View File

@@ -0,0 +1,167 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\services;
use crmeb\exceptions\ApiException;
use think\facade\Log;
/**
* Class AccessTokenServeService
* @package crmeb\services
*/
class AccessTokenServeService extends HttpService
{
/**
* 配置
* @var string
*/
protected string $account;
/**
* @var string
*/
protected string $secret;
/**
* @var Cache|null
*/
protected $cache;
/**
* @var string
*/
protected string $cacheTokenPrefix = "_crmeb_plat";
/**
* @var string
*/
protected string $apiHost = 'http://sms.crmeb.net/api/';
/**
* 登录接口
*/
const USER_LOGIN = "v2/user/login";
/**
* AccessTokenServeService constructor.
* @param string $account
* @param string $secret
* @param null $cache
*/
public function __construct(string $account, string $secret, $cache = null)
{
if (!$cache) {
/** @var CacheService $cache */
$cache = app()->make(CacheService::class);
}
$this->account = $account;
$this->secret = $secret;
$this->cache = $cache;
}
/**
* 获取配置
* @return array
*/
public function getConfig(): array
{
return [
'access_key' => $this->account,
'secret_key' => $this->secret
];
}
/**
* 获取缓存token
* @return mixed
*/
public function getToken()
{
$accessTokenKey = md5($this->account . '_' . $this->secret . $this->cacheTokenPrefix);
$cacheToken = $this->cache->get($accessTokenKey);
if (!$cacheToken) {
$getToken = $this->getTokenFromServer();
$this->cache->set($accessTokenKey, $getToken['access_token'], 300);
$cacheToken = $getToken['access_token'];
}
return $cacheToken;
}
/**
* 从服务器获取token
* @return mixed
*/
public function getTokenFromServer()
{
$params = [
'access_key' => $this->account,
'secret_key' => $this->secret,
];
if (!$this->account || !$this->secret) {
throw new ApiException('请先登录一号通平台!');
}
$response = $this->postRequest($this->get(self::USER_LOGIN), $params);
$response = json_decode($response, true);
if (!$response) {
throw new ApiException('获取token失败');
}
if ($response['status'] === 200) {
return $response['data'];
} else {
throw new ApiException($response['msg']);
}
}
/**
* 请求
* @param string $url
* @param array $data
* @param string $method
* @param bool $isHeader
* @param array $header
* @return array|mixed
*/
public function httpRequest(string $url, array $data = [], string $method = 'POST', bool $isHeader = true, array $header = [])
{
if ($isHeader) {
$accessToken = $this->getToken();
if (!$accessToken) {
throw new ApiException('配置已更改或token已失效');
}
$header = array_merge($header, ['Authorization:Bearer-' . $accessToken]);
}
Log::info('请求接口:' . $url . ' 请求参数:' . json_encode($data, JSON_UNESCAPED_UNICODE));
$res = $this->request($this->get($url), $method, $data, $header);
if (!$res) {
throw new ApiException('平台错误:发生异常,请稍后重试');
}
$result = json_decode($res, true) ?: false;
if (!isset($result['status']) || $result['status'] != 200) {
throw new ApiException(isset($result['msg']) ? '平台错误:' . $result['msg'] : '平台错误:发生异常,请稍后重试');
}
Log::info('接口返回:' . json_encode($result, JSON_UNESCAPED_UNICODE));
return $result['data'] ?? [];
}
/**
* @param string $apiUrl
* @return string
*/
public function get(string $apiUrl = '')
{
return $this->apiHost . $apiUrl;
}
}

View File

@@ -0,0 +1,374 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\services;
use Alipay\EasySDK\Payment\Common\Models\AlipayTradeFastpayRefundQueryResponse;
use Alipay\EasySDK\Payment\Common\Models\AlipayTradeRefundResponse;
use Alipay\EasySDK\Payment\Wap\Models\AlipayTradeWapPayResponse;
use crmeb\utils\Hook;
use JetBrains\PhpStorm\ArrayShape;
use think\facade\Log;
use think\facade\Route as Url;
use Alipay\EasySDK\Kernel\Config;
use Alipay\EasySDK\Kernel\Factory;
use crmeb\exceptions\PayException;
use app\services\pay\PayNotifyServices;
use Alipay\EasySDK\Kernel\Util\ResponseChecker;
use AlibabaCloud\Tea\Tea;
/**
* Class AliPayService
* @package crmeb\services
*/
class AliPayService
{
/**
* 配置
* @var array
*/
protected array $config = [
'appId' => '',
'merchantPrivateKey' => '',//应用私钥
'alipayPublicKey' => '',//支付宝公钥
'notifyUrl' => '',//可设置异步通知接收服务地址
'encryptKey' => '',//可设置AES密钥,调用AES加解密相关接口时需要(可选)
];
/**
* @var ResponseChecker
*/
protected ResponseChecker $response;
/**
* 付款码
* @var string
*/
protected string $authCode;
/**
* @var static
*/
protected static $instance;
/**
* AliPayService constructor.
* @param array $config
*/
protected function __construct(array $config = [])
{
if (!$config) {
$alipay = SystemConfigService::more(['ali_pay_appid', 'alipay_merchant_private_key', 'alipay_public_key', 'site_url']);
$config = [
'appId' => $alipay['ali_pay_appid'] ?? '',
'merchantPrivateKey' => $alipay['alipay_merchant_private_key'] ?? '',
'alipayPublicKey' => $alipay['alipay_public_key'] ?? '',
'notifyUrl' => ($alipay['site_url'] ?? '') . Url::buildUrl('/api/pay/notify/alipay'),
];
}
$this->config = array_merge($this->config, $config);
Factory::setOptions($this->getOptions());
$this->response = new ResponseChecker();
}
/**
* 实例化
* @param array $config
* @return static
*/
public static function instance(array $config = []): self
{
if (is_null(self::$instance)) {
self::$instance = new static($config);
}
return self::$instance;
}
/**
* 是否是支付宝付款码
* @param string $authCode
* @return bool
*/
public static function isAliPayAuthCode(string $authCode): bool
{
return preg_match('/^[0-9]{16,24}$/', $authCode) && in_array(substr($authCode, 0, 2), ['25', '26', '27', '28', '29', '30']);
}
/**
* 初始化
*/
protected function initialize()
{
Factory::setOptions($this->getOptions());
}
/**
* 设置配置
* @return Config
*/
protected function getOptions(): Config
{
$options = new Config();
$options->protocol = 'https';
$options->gatewayHost = 'openapi.alipay.com';
$options->signType = 'RSA2';
$options->appId = $this->config['appId'];
// 为避免私钥随源码泄露,推荐从文件中读取私钥字符串而不是写入源码中
$options->merchantPrivateKey = $this->config['merchantPrivateKey'];
//注:如果采用非证书模式,则无需赋值上面的三个证书路径,改为赋值如下的支付宝公钥字符串即可
$options->alipayPublicKey = $this->config['alipayPublicKey'];
//可设置异步通知接收服务地址(可选)
$options->notifyUrl = $this->config['notifyUrl'];
//可设置AES密钥,调用AES加解密相关接口时需要(可选)
if ($this->config['encryptKey']) {
$options->encryptKey = $this->config['encryptKey'];
}
Tea::config(['verify' => false]);
return $options;
}
/**
* 付款码付款
* @param string $authCode
* @param string $title
* @param string $orderId
* @param string $totalAmount
* @param string $passbackParams
* @return array
*/
#[ArrayShape([
'paid' => "int",
'message' => "mixed|string",
'payInfo' => "array"
])]
public function microPay(string $authCode, string $title, string $orderId, string $totalAmount, string $passbackParams): array
{
$title = trim($title);
try {
$result = Factory::payment()->faceToFace()->optional('passback_params', $passbackParams)->pay($title, $orderId, $totalAmount, $authCode);
if ($this->response->success($result)) {
$response = $result->toMap();
return [
'paid' => $response['code'] === '10000' ? 1 : 0,
'message' => $response['sub_msg'] ?? '支付成功',
'payInfo' => $response
];
} else {
throw new PayException('失败原因:' . $result->msg . ',' . $result->subMsg);
}
} catch (\Exception $e) {
throw new PayException($e->getMessage());
}
}
/**
* 创建订单
* @param string $title 商品名称
* @param string $orderId 订单号
* @param string $totalAmount 支付金额
* @param string $passbackParams 备注
* @param string $quitUrl 同步跳转地址
* @param string $siteUrl
* @param bool $isCode
*/
public function create(string $title, string $orderId, string $totalAmount, string $passbackParams, string $quitUrl = '', string $siteUrl = '', bool $isCode = false)
{
$title = trim($title);
try {
if ($isCode) {
//二维码支付
$result = Factory::payment()->faceToFace()->optional('passback_params', $passbackParams)->precreate($title, $orderId, $totalAmount);
} else if (request()->isApp()) {
//app支付
$result = Factory::payment()->app()->optional('passback_params', $passbackParams)->pay($title, $orderId, $totalAmount);
} else {
//h5支付
$result = Factory::payment()->wap()->optional('passback_params', $passbackParams)->pay($title, $orderId, $totalAmount, $quitUrl, $siteUrl);
}
if ($this->response->success($result)) {
return $result->body ?? $result;
} else {
throw new PayException('失败原因:' . $result->msg . ',' . $result->subMsg);
}
} catch (\Exception $e) {
throw new PayException($e->getMessage());
}
}
/**
* 订单退款
* @param string $outTradeNo 订单号
* @param string $totalAmount 退款金额
* @param string $refund_id 退款单号
* @return AlipayTradeRefundResponse
*/
public function refund(string $outTradeNo, string $totalAmount, string $refund_id): AlipayTradeRefundResponse
{
try {
$result = Factory::payment()->common()->refund($outTradeNo, $totalAmount, $refund_id);
if ($this->response->success($result)) {
return $result;
} else {
throw new PayException('失败原因:' . $result->msg . ',' . $result->subMsg);
}
} catch (\Exception $e) {
throw new PayException($e->getMessage());
}
}
/**
* 查询交易退款单号信息
* @param string $outTradeNo
* @param string $outRequestNo
* @return AlipayTradeFastpayRefundQueryResponse
*/
public function queryRefund(string $outTradeNo, string $outRequestNo): AlipayTradeFastpayRefundQueryResponse
{
try {
$result = Factory::payment()->common()->queryRefund($outTradeNo, $outRequestNo);
if ($this->response->success($result)) {
return $result;
} else {
throw new PayException('失败原因:' . $result->msg . ',' . $result->subMsg);
}
} catch (\Exception $e) {
throw new PayException($e->getMessage());
}
}
/**
* 支付异步回调
* @return string
*/
public static function handleNotify()
{
return self::instance()->notify(function ($notify) {
if (isset($notify->out_trade_no)) {
if (isset($notify->attach) && $notify->attach) {
if (($count = strpos($notify->out_trade_no, '_')) !== false) {
$notify->trade_no = $notify->out_trade_no;
$notify->out_trade_no = substr($notify->out_trade_no, $count + 1);
}
return (new Hook(PayNotifyServices::class, 'aliyun'))->listen($notify->attach, $notify->out_trade_no, $notify->trade_no);
}
return false;
}
});
}
/**
* 异步回调
* @param callable $notifyFn
* @return string
*/
public function notify(callable $notifyFn)
{
// app()->request->filter(['trim']);
// $paramInfo = app()->request->postMore([
// ['gmt_create', ''],
// ['charset', ''],
// ['seller_email', ''],
// ['subject', ''],
// ['sign', ''],
//// ['buyer_id', ''],
// ['invoice_amount', ''],
// ['notify_id', ''],
// ['fund_bill_list', ''],
// ['notify_type', ''],
// ['trade_status', ''],
// ['receipt_amount', ''],
// ['buyer_pay_amount', ''],
// ['app_id', ''],
// ['seller_id', ''],
// ['sign_type', ''],
// ['gmt_payment', ''],
// ['notify_time', ''],
// ['passback_params', ''],
// ['version', ''],
// ['out_trade_no', ''],
// ['total_amount', ''],
// ['trade_no', ''],
// ['auth_app_id', ''],
// ['buyer_logon_id', ''],
// ['point_amount', ''],
// ], false, false);
$paramInfo = app()->request->param();
unset($paramInfo['type']);
//卡劵红包类
// $voucher_detail_list = app()->request->param('voucher_detail_list');
// if ($voucher_detail_list) {
// $paramInfo['voucher_detail_list'] = $voucher_detail_list;
// }
//商户订单号
$postOrder['out_trade_no'] = $paramInfo['out_trade_no'] ?? '';
//支付宝交易号
$postOrder['trade_no'] = $paramInfo['trade_no'] ?? '';
//交易状态
$postOrder['trade_status'] = $paramInfo['trade_status'] ?? '';
//备注
$postOrder['attach'] = isset($paramInfo['passback_params']) ? urldecode($paramInfo['passback_params']) : '';
if (in_array($postOrder['trade_status'], ['TRADE_SUCCESS', 'TRADE_FINISHED']) && $this->verifyNotify($paramInfo)) {
try {
if ($notifyFn((object)$postOrder)) {
return 'success';
}
} catch (\Exception $e) {
Log::error('支付宝异步会回调成功,执行函数错误。错误单号:' . $postOrder['out_trade_no']);
}
}
return 'fail';
}
/**
* 验签
* @param array $param
* @return bool
*/
protected function verifyNotify(array $param): bool
{
try {
return Factory::payment()->common()->verifyNotify($param);
} catch (\Exception $e) {
Log::error('支付宝回调成功,验签发生错误,错误原因:' . $e->getMessage());
}
return false;
}
/**
* 商家支付接口
* @param array $bizParams
* @return \Alipay\EasySDK\Util\Generic\Models\AlipayOpenApiGenericResponse|false
* User: liusl
* DateTime: 2024/10/21 12:01
*/
public function merchantPay(array $bizParams)
{
try {
// 调用工厂类的通用方法执行支付宝转账操作
$result = Factory::util()->generic()->execute('alipay.fund.trans.toaccount.transfer', [], $bizParams);
// 判断支付是否成功
if ($this->response->success($result)) {
return $result;
} else {
return false;
}
} catch (\Exception $e) {
// 记录日志并返回false
Log::error('支付宝转账失败,失败原因:' . $e->getMessage());
return false;
}
}
}

View File

@@ -0,0 +1,436 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\services;
use think\facade\Cache as CacheStatic;
/**
* crmeb 缓存类
* Class CacheService
* @package crmeb\services
* @mixin \Redis
*/
class CacheService
{
const CACHE_EXPIRE_NAME = 'cache_expire';
//副屏相关
const CASHIER_AUX_SCREEN_TAG = 'auxScreen';
/**
* 标签名
* @var string
*/
protected static $globalCacheName = '_cached_1515146130';
/**
* 缓存队列key
* @var string[]
*/
protected static $redisQueueKey = [
0 => 'product',
1 => 'seckill',
2 => 'bargain',
3 => 'combination',
4 => 'integral',
5 => 'discounts',
6 => 'lottery'
];
/**
* 过期时间
* @var int
*/
protected static $expire;
/**
* 获取缓存过期时间
* @param int|null $expire
* @return int
*/
protected static function getExpire(int $expire = null): int
{
if (self::$expire) {
return (int)self::$expire;
}
$expire = !is_null($expire) ? $expire : CacheStatic::store('redis')->get(self::CACHE_EXPIRE_NAME, 360);
if (!is_int($expire))
$expire = (int)$expire;
return self::$expire = $expire;
}
/**
* 判断缓存是否存在
* @param string $name
* @return bool
* @throws \Psr\SimpleCache\InvalidArgumentException
*/
public static function has(string $name): bool
{
try {
return CacheStatic::has($name);
} catch (\Throwable $e) {
return false;
}
}
/**
* 写入缓存
* @param string $name 缓存名称
* @param mixed $value 缓存值
* @param int $expire 缓存时间,为0读取系统缓存时间
* @return bool
*/
public static function set(string $name, $value, int $expire = null): bool
{
try {
return self::handler()->set($name, $value, $expire ?? self::getExpire($expire));
} catch (\Throwable $e) {
return false;
}
}
/**
* 如果不存在则写入缓存
* @param string $name
* @param bool $default
* @return mixed
*/
public static function get(string $name, $default = false, int $expire = null)
{
try {
return self::handler()->remember($name, $default, $expire ?? self::getExpire($expire));
} catch (\Throwable $e) {
try {
if (is_callable($default)) {
return $default();
} else {
return $default;
}
} catch (\Throwable $e) {
return null;
}
}
}
/**
* 如果不存在则写入缓存
* @param string $name
* @param bool $default
* @return mixed
*/
public static function remember(string $name, $default = false, int $expire = null)
{
try {
return self::handler()->remember($name, $default, $expire ?? self::getExpire($expire));
} catch (\Throwable $e) {
try {
if (is_callable($default)) {
return $default();
} else {
return $default;
}
} catch (\Throwable $e) {
return null;
}
}
}
/**
* 删除缓存
* @param string $name
* @return bool
* @throws \Psr\SimpleCache\InvalidArgumentException
*/
public static function delete(string $name)
{
return CacheStatic::delete($name);
}
/**
* 缓存句柄
*
* @return \think\cache\TagSet|CacheStatic
*/
public static function handler(?string $cacheName = null)
{
return CacheStatic::tag($cacheName ?: self::$globalCacheName);
}
/**
* 清空缓存池
* @return bool
*/
public static function clear()
{
return self::handler()->clear();
}
/**
* Redis缓存句柄
*
* @return \think\cache\TagSet|CacheStatic
*/
public static function redisHandler($type = null)
{
if ($type) {
return CacheStatic::store('redis')->tag($type);
} else {
return CacheStatic::store('redis');
}
}
/**
* 放入令牌桶
* @param string $key
* @param array $value
* @param string $type
* @return bool
*/
public static function setTokenBucket(string $key, $value, $expire = null, string $type = 'admin')
{
try {
$redisCahce = self::redisHandler($type);
return $redisCahce->set($key, $value, $expire);
} catch (\Throwable $e) {
return false;
}
}
/**
* 清除所有令牌桶
* @param string $type
* @return bool
*/
public static function clearTokenAll(string $type = 'admin')
{
try {
return self::redisHandler($type)->clear();
} catch (\Throwable $e) {
return false;
}
}
/**
* 清除令牌桶
* @param string $type
* @return bool
*/
public static function clearToken(string $key)
{
try {
return self::redisHandler()->delete($key);
} catch (\Throwable $e) {
return false;
}
}
/**
* 查看令牌是否存在
* @param string $key
* @return bool
*/
public static function hasToken(string $key)
{
try {
return self::redisHandler()->has($key);
} catch (\Throwable $e) {
return false;
}
}
/**
* 获取token令牌桶
* @param string $key
* @return mixed|null
* @throws \Psr\SimpleCache\InvalidArgumentException
*/
public static function getTokenBucket(string $key)
{
try {
return self::redisHandler()->get($key, null);
} catch (\Throwable $e) {
return null;
}
}
/**
* 获取指定分数区间的成员
* @param $key
* @param int $start
* @param int $end
* @param array $options
* @return mixed
*/
public static function zRangeByScore($key, $start = '-inf', $end = '+inf', array $options = [])
{
return self::redisHandler()->zRangeByScore($key, $start, $end, $options);
}
/**
* 设置redis入库队列
* @param string $unique
* @param int $number
* @param int $type
* @param bool $isPush true :重置 false:累加
* @return bool
*/
public static function setStock(string $unique, int $number, int $type = 1, bool $isPush = true)
{
if (!$unique || !$number) return false;
$name = (self::$redisQueueKey[$type] ?? '') . '_' . $type . '_' . $unique;
/** @var self $cache */
$cache = self::redisHandler();
$res = true;
if ($isPush) {
$cache->del($name);
}
$data = [];
for ($i = 1; $i <= $number; $i++) {
$data[] = $i;
}
$res = $res && $cache->lPush($name, ...$data);
return $res;
}
/**
* 弹出redis队列中的库存条数
* @param string $unique
* @param int $number
* @param int $type
* @return bool
*/
public static function popStock(string $unique, int $number, int $type = 1)
{
if (!$unique || !$number) return false;
$name = (self::$redisQueueKey[$type] ?? '') . '_' . $type . '_' . $unique;
/** @var self $cache */
$cache = self::redisHandler();
$res = true;
if ($number > $cache->lLen($name)) {
return false;
}
for ($i = 1; $i <= $number; $i++) {
$res = $res && $cache->lPop($name);
}
return $res;
}
/**
* 是否有库存|返回库存
* @param string $unique
* @param int $number
* @param int $type
* @return bool
*/
public static function checkStock(string $unique, int $number = 0, int $type = 1)
{
$name = (self::$redisQueueKey[$type] ?? '') . '_' . $type . '_' . $unique;
if ($number) {
return self::redisHandler()->lLen($name) >= $number;
} else {
return self::redisHandler()->lLen($name);
}
}
/**
* 检查锁
* @param int $uid
* @param int $timeout
* @return bool
* @author 等风来
* @email 136327134@qq.com
* @date 2022/11/22
*/
public static function setMutex(string $key, int $timeout = 10)
{
$curTime = time();
$readMutexKey = "redis:mutex:{$key}";
$mutexRes = self::redisHandler()->handler()->setnx($readMutexKey, $curTime + $timeout);
if ($mutexRes) {
return true;
}
//就算意外退出,下次进来也会检查key,防止死锁
$time = self::redisHandler()->handler()->get($readMutexKey);
if ($curTime > $time) {
self::redisHandler()->handler()->del($readMutexKey);
return self::redisHandler()->handler()->setnx($readMutexKey, $curTime + $timeout);
}
return false;
}
/**
* 删除锁
* @param $uid
* @author 等风来
* @email 136327134@qq.com
* @date 2022/11/22
*/
public static function delMutex(string $key)
{
$readMutexKey = "redis:mutex:{$key}";
self::redisHandler()->handler()->del($readMutexKey);
}
/**
* 数据库锁
* @param $key
* @param $fn
* @param int $ex
* @return bool|mixed
*/
public static function lock($key, $fn = [], int $ex = 10)
{
$service = app()->make(LockService::class);
if ($fn instanceof \Closure) {
return $service->exec($key, $fn, $ex);
} else {
return $service->lock($key, 1, $ex);
}
}
/**
* 销毁锁
* @param $key
* @return bool
*/
public static function unLock($key)
{
return app()->make(LockService::class)->unlock($key);
}
/**
* 魔术方法
* @param $name
* @param $arguments
* @return mixed
*/
public static function __callStatic($name, $arguments)
{
return self::redisHandler()->{$name}(...$arguments);
}
/**
* 魔术方法
* @param $name
* @param $arguments
* @return mixed
*/
public function __call($name, $arguments)
{
return self::redisHandler()->{$name}(...$arguments);
}
}

View File

@@ -0,0 +1,596 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\services;
/**
* 复制主流商城商品
* Class CopyProductService
* @package crmeb\services
*/
class CopyProductService
{
//接口地址
protected static $api = [
'taobao' => 'https://api03.6bqb.com/taobao/detail', //https://api03.6bqb.com/app/taobao/detail
'tmall' => 'https://api03.6bqb.com/tmall/detail',
'jd' => 'https://api03.6bqb.com/jd/detail',
'pdd' => 'https://api03.6bqb.com/pdd/detail',
'suning' => 'https://api03.6bqb.com/suning/detail',
'1688' => 'https://api03.6bqb.com/alibaba/detail'
];
protected static $apiKey = '';//996EF05B079F8706345938A0CD7339BB
//商品默认字段
protected static $productInfo = [
'cate_id' => '',
'store_name' => '',
'store_info' => '',
'unit_name' => '件',
'price' => 0,
'keyword' => '',
'ficti' => 0,
'ot_price' => 0,
'give_integral' => 0,
'postage' => 0,
'cost' => 0,
'image' => '',
'slider_image' => '',
'video_link' => '',
'add_time' => 0,
'stock' => 0,
'description' => '',
'description_images' => [],
'soure_link' => '',
'temp_id' => '',
'items' => [],
'attrs' => [],
'info' => [],
];
/**
* 整合
* @param $url
* @param $method
* @param $data
* @return string
*/
public static function makeUrl(string $url, string $method, array $data)
{
$param = '';
if (strtolower($method) == 'get' && $data) {
foreach ($data as $key => $value) {
$param .= '&' . $key . '=' . $value;
}
}
return $url . '?apikey=' . self::$apiKey . $param;
}
/**
* @param bool $status
* @param string $msg
* @param array $data
*/
public static function setReturn(bool $status = true, string $msg = 'SUCCESS', array $data = [])
{
return ['status' => $status, 'msg' => $msg, 'data' => $data];
}
/**
*
* @param array $data
*/
public static function getInfo(string $type = 'taobao', array $data = [], string $apikey = '')
{
if (!$apikey) {
return self::setReturn(false, '请先去设置复制商品apiKey');
}
$url = self::$api[$type] ?? '';
$type = $type == '1688' ? 'alibaba' : $type;
$action = $type . 'Info';
$deal_action = $type . 'Deal';
$method = 'get';
self::$apiKey = $apikey;
if (!$data || !$url || !is_callable(self::class, $action) || !is_callable(self::class, $deal_action)) {
return self::setReturn(false, '暂不支持该平台商品复制');
}
switch ($type) {
case 'taobao':
case 'tmall':
case 'jd':
case 'pdd':
case 'alibaba':
$method = 'get';
if (!isset($data['itemid']) || !$data['itemid'])
return self::setReturn(false, '缺少商品ID');
break;
case 'suning':
$method = 'get';
if (!isset($data['itemid']) || !$data['itemid'])
return self::setReturn(false, '缺少商品ID');
if (!isset($data['shopid']) || !$data['shopid'])
return self::setReturn(false, '缺少商户ID');
break;
}
$url = self::makeUrl($url, $method, $data);
if ($cache_info = CacheService::get(md5($url))) {
return self::setReturn(true, 'SUCCESS', $cache_info);
}
$info = self::$action($url, $data);
if (!$info) return self::setReturn(false, '获取商品失败');
$info = json_decode($info, true);
if (!$info || (!in_array($info['retcode'], ['0000']))) {
return self::setReturn(false, $info['message'] ?? '获取商品失败', $info);
}
$result = $info['data'];
//可能存在下一页 但是api中没有分页参数 暂留
// if (isset($info['hasNext']) && $info['hasNext']) {
// $data['page'] = $info['page'] + 1;
// }
$result = self::$deal_action($result);
//过滤采集到的规格 删除其中的空值
if ($result['items']) {
foreach ($result['items'] as $k => $item) {
if (isset($item['value'])) {
if ($item['value'] == '') unset($result['items'][$k]);
if (!$item['detail'] || !isset($item['detail'][0]) || $item['detail'][0] == '') unset($result['items'][$k]);
} else {
unset($result['items'][$k]);
}
}
}
if (!$result['items']) {
$result['items'] = [
[
'value' => '默认',
'detail' => [
'默认'
]
]
];
}
$result['info'] = self::formatAttr(array_values($result['items']));
if (!$result['image'] && $result['slider_image'])
$result['image'] = $result['slider_image'][0] ?? '';
if ($result['description']) {
$result['description'] = str_replace('data-lazyload', 'src', $result['description']);
}
CacheService::set(md5($url), $result, 3600 * 24);
return self::setReturn(true, 'SUCCESS', $result);
}
/**
* 获取淘宝商品
* @param $url
* @param $data
* @param string $method
* @return bool|string
*/
public static function taobaoInfo(string $url, array $data, string $method = 'get')
{
$info = HttpService::request($url, $method, $data);
$result = false;
if ($info) {
$result = $info;
}
return $result;
}
/**
* 处理获取淘宝的商品
* @param $data
* @return mixed
*/
public static function taobaoDeal(array $data)
{
$info = $data['item'] ?? [];
$result = self::$productInfo;
if ($info) {
$result['store_name'] = $info['title'] ?? '';
$result['store_info'] = $info['subTitle'] ?? '';
$result['slider_image'] = $info['images'] ?? '';
$result['description'] = $info['desc'] ?? '';
$result['description_images'] = $info['descImgs'] ?? [];
$items = [];
if (isset($info['props']) && $info['props']) {
foreach ($info['props'] as $key => $prop) {
$item['value'] = $prop['name'];
$item['detail'] = [];
foreach ($prop['values'] as $name) {
$item['detail'][] = $name['name'];
}
$items[] = $item;
}
}
$result['items'] = $items;
}
return $result;
}
/**
* 获取天猫商品
* @param $url
* @param $data
* @param string $method
* @return bool|string
*/
public static function tmallInfo(string $url, array $data, string $method = 'get')
{
$info = HttpService::request($url, $method, $data);
$result = false;
if ($info) {
$result = $info;
}
return $result;
}
/**
* 处理天猫商品
* @param $data
* @return mixed
*/
public static function tmallDeal(array $data)
{
$info = $data['item'] ?? [];
$result = self::$productInfo;
if ($info) {
$result['store_name'] = $info['title'] ?? '';
$result['store_info'] = $info['subTitle'] ?? '';
$result['slider_image'] = self::lingByHttp($info['images'] ?? '');
$result['description_images'] = self::lingByHttp($info['descImgs'] ?? []);
$description = '';
foreach ($result['description_images'] as $item) {
$description .= '<img src="' . $item . '">';
}
unset($item);
$result['description'] = $description;
$items = [];
if (isset($info['props']) && $info['props']) {
foreach ($info['props'] as $key => $prop) {
$item['value'] = $prop['name'];
$item['detail'] = [];
foreach ($prop['values'] as $name) {
$item['detail'][] = $name['name'];
}
$items[] = $item;
}
}
$result['items'] = $items;
}
return $result;
}
/**
* 获取京东商品
* @param $url
* @param $data
* @param string $method
* @return bool|string
*/
public static function jdInfo(string $url, array $data, string $method = 'get')
{
$info = HttpService::request($url, $method, $data);
$result = false;
if ($info) {
$result = $info;
}
return $result;
}
/**
* 处理京东商品
* @param $data
* @return mixed
*/
public static function jdDeal(array $data)
{
$info = $data['item'] ?? [];
$result = self::$productInfo;
if ($info) {
$result['store_name'] = $info['name'] ?? '';
$result['store_info'] = $result['store_name'];
$result['price'] = $info['price'] ?? 0;
$result['ot_price'] = $info['originalPrice'] ?? 0;
$result['slider_image'] = $info['images'] ?? [];
$result['description'] = $info['desc'] ?? '';
$result['description_images'] = $info['descImgs'] ?? [];
$result['description_images'] = array_map(function ($item) {
if (strstr($item, 'http') === false) {
$item = 'http:' . $item;
}
return $item;
}, $result['description_images']);
if (strstr($result['description'], '<style>') !== false && strstr($result['description'], '<img') === false) {
$content = '';
foreach ($result['description_images'] as $item) {
$content .= '<p><img src="' . $item . '"></p>';
}
$result['description'] = $content;
}
$items = [];
if (isset($info['skuProps']) && $info['skuProps']) {
foreach ($info['skuProps'] as $key => $prop) {
$item = [];
$item['value'] = $info['saleProp'][$key] ?? '';
$item['detail'] = $prop;
$items[] = $item;
}
}
$result['items'] = $items;
}
return $result;
}
/**
* @param $data
* @return array|string
*/
public static function lingByHttp($data)
{
if (is_array($data)) {
foreach ($data as &$item) {
if (strstr($item, 'http://') === false && strstr($item, 'https://') === false) {
$item = 'http:' . $item;
}
}
return $data;
} else {
if (strstr($data, 'http://') === false && strstr($data, 'https://') === false) {
$data = 'http:' . $data;
}
return $data;
}
}
/**
* 获取拼多多商品
* @param $url
* @param $data
* @param string $method
* @return bool|string
*/
public static function pddInfo(string $url, array $data, string $method = 'get')
{
$info = HttpService::request($url, $method, $data);
$result = false;
if ($info) {
$result = $info;
}
return $result;
}
/**
* 处理拼多多商品
* @param $data
* @return mixed
*/
public static function pddDeal(array $data)
{
$info = $data['item'] ?? [];
$result = self::$productInfo;
if ($info) {
$result['store_name'] = $info['goodsName'] ?? '';
$result['store_info'] = $info['goodsDesc'] ?? '';
$result['image'] = $info['thumbUrl'] ?? '';
$result['slider_image'] = $info['banner'] ?? [];
$image = [];
foreach ($result['slider_image'] as &$item) {
if (is_array($item) && isset($item['url'])) {
$image[] = $item['url'];
}
}
if ($image) {
$result['slider_image'] = $image;
}
$result['video_link'] = $info['video']['videoUrl'] ?? '';
$result['price'] = $info['maxNormalPrice'] ?? 0;
$result['ot_price'] = $info['marketPrice'] ?? 0;
$descImgs = [];
if (isset($info['detail']) && $info['detail']) {
foreach ($info['detail'] as $img) {
if (isset($img['url']) && $img['url']) $descImgs[] = $img['url'];
}
}
$result['description_images'] = $descImgs;
$desc = '<p>';
foreach ($descImgs as $item) {
$desc .= '<img src="' . $item . '"/>';
}
$desc .= '</p>';
$result['description'] = $desc;
$items = [];
if (isset($info['skus']) && $info['skus']) {
$i = 0;
foreach ($info['skus'] as $sku) {
foreach ($sku['specs'] as $key => $spec) {
if ($i == 0) $items[$key]['value'] = $spec['spec_key'];
$items[$key]['detail'][] = $spec['spec_value'];
}
$i++;
}
}
foreach ($items as $k => $item) {
$items[$k]['detail'] = array_unique($item['detail']);
}
$result['items'] = $items;
}
return $result;
}
/**
* 获取苏宁商品
* @param $url
* @param $data
* @param string $method
* @return bool|string
*/
public static function suningInfo(string $url, array $data, string $method = 'get')
{
$info = HttpService::request($url, $method, $data);
$result = false;
if ($info) {
$result = $info;
}
return $result;
}
/**
*
* @param string $url
* @param array $data
* @param string $method
* @return bool|string
*/
public static function alibabaInfo(string $url, array $data, string $method = 'get')
{
$info = HttpService::request($url, $method, $data);
$result = false;
if ($info) {
$result = $info;
}
return $result;
}
/**
* @param array $data
* @return array
*/
public static function alibabaDeal(array $data)
{
$result = self::$productInfo;
if ($data) {
$result['store_name'] = $data['title'] ?? '';
$result['store_info'] = $result['store_name'];
$result['slider_image'] = $data['images'] ?? [];
$result['price'] = $data['price'] ?? 0;
$result['description'] = $data['desc'] ?? '';
$items = [];
if (isset($data['skuProps']) && $data['skuProps']) {
$i = 0;
foreach ($data['skuProps'] as $passSUb) {
$items[$i]['value'] = $passSUb['prop'];
$items[$i]['detail'] = array_column($passSUb['value'], 'name');
$i++;
}
}
foreach ($items as $k => $item) {
$items[$k]['detail'] = array_unique($item['detail']);
}
$result['items'] = $items;
}
return $result;
}
/**
* 处理苏宁商品
* @param $data
* @return mixed
*/
public static function suningDeal(array $data)
{
$result = self::$productInfo;
if ($data) {
$result['store_name'] = $data['title'] ?? '';
$result['store_info'] = $result['store_name'];
$result['slider_image'] = $data['images'] ?? [];
$result['price'] = $data['price'] ?? 0;
$result['description'] = $data['desc'] ?? '';
$items = [];
if (isset($data['passSubList']) && $data['passSubList']) {
$i = 0;
foreach ($data['passSubList'] as $passSUb) {
$j = 0;
foreach ($passSUb as $key => $sub) {
if ($i == 0) $items[$j]['value'] = $key;
foreach ($sub as $value) {
if (isset($value['characterValueDisplayName']) && $value['characterValueDisplayName'])
$items[$j]['detail'][] = $value['characterValueDisplayName'];
}
$j++;
}
$i++;
}
}
foreach ($items as $k => $item) {
$items[$k]['detail'] = array_unique($item['detail']);
}
$result['items'] = $items;
}
return $result;
}
/**
* 格式化规格
* @param $attr
* @return array
*/
public static function formatAttr(array $attr)
{
$value = attr_format($attr)[1];
$valueNew = [];
$count = 0;
foreach ($value as $key => $item) {
$detail = $item['detail'];
// sort($item['detail'], SORT_STRING);
$suk = implode(',', $item['detail']);
$sukValue[$suk]['pic'] = '';
$sukValue[$suk]['price'] = 0;
$sukValue[$suk]['cost'] = 0;
$sukValue[$suk]['ot_price'] = 0;
$sukValue[$suk]['stock'] = 0;
$sukValue[$suk]['bar_code'] = '';
$sukValue[$suk]['weight'] = 0;
$sukValue[$suk]['volume'] = 0;
$sukValue[$suk]['brokerage'] = 0;
$sukValue[$suk]['brokerage_two'] = 0;
foreach (array_keys($detail) as $k => $title) {
if ($title == '') continue;
$header[$k]['title'] = $title;
$header[$k]['align'] = 'center';
$header[$k]['minWidth'] = 120;
}
foreach (array_values($detail) as $k => $v) {
if ($v == '') continue;
$valueNew[$count]['value' . ($k + 1)] = $v;
$header[$k]['key'] = 'value' . ($k + 1);
}
$valueNew[$count]['detail'] = $detail;
$valueNew[$count]['pic'] = $sukValue[$suk]['pic'] ?? '';
$valueNew[$count]['price'] = $sukValue[$suk]['price'] ? floatval($sukValue[$suk]['price']) : 0;
$valueNew[$count]['cost'] = $sukValue[$suk]['cost'] ? floatval($sukValue[$suk]['cost']) : 0;
$valueNew[$count]['ot_price'] = isset($sukValue[$suk]['ot_price']) ? floatval($sukValue[$suk]['ot_price']) : 0;
$valueNew[$count]['vip_price'] = isset($sukValue[$suk]['vip_price']) ? floatval($sukValue[$suk]['vip_price']) : 0;
$valueNew[$count]['stock'] = $sukValue[$suk]['stock'] ? intval($sukValue[$suk]['stock']) : 0;
$valueNew[$count]['bar_code'] = $sukValue[$suk]['bar_code'] ?? '';
$valueNew[$count]['weight'] = $sukValue[$suk]['weight'] ? floatval($sukValue[$suk]['weight']) : 0;
$valueNew[$count]['volume'] = $sukValue[$suk]['volume'] ? floatval($sukValue[$suk]['volume']) : 0;
$valueNew[$count]['brokerage'] = $sukValue[$suk]['brokerage'] ? floatval($sukValue[$suk]['brokerage']) : 0;
$valueNew[$count]['brokerage_two'] = $sukValue[$suk]['brokerage_two'] ? floatval($sukValue[$suk]['brokerage_two']) : 0;
$count++;
}
$header[] = ['title' => '图片', 'slot' => 'pic', 'align' => 'center', 'minWidth' => 80];
$header[] = ['title' => '售价', 'slot' => 'price', 'align' => 'center', 'minWidth' => 95];
$header[] = ['title' => '成本价', 'slot' => 'cost', 'align' => 'center', 'minWidth' => 95];
$header[] = ['title' => '划线价', 'slot' => 'ot_price', 'align' => 'center', 'minWidth' => 95];
$header[] = ['title' => '会员价', 'slot' => 'vip_price', 'align' => 'center', 'minWidth' => 140];
$header[] = ['title' => '库存', 'slot' => 'stock', 'align' => 'center', 'minWidth' => 95];
$header[] = ['title' => '商品编号', 'slot' => 'bar_code', 'align' => 'center', 'minWidth' => 120];
$header[] = ['title' => '重量(KG)', 'slot' => 'weight', 'align' => 'center', 'minWidth' => 95];
$header[] = ['title' => '体积(m³)', 'slot' => 'volume', 'align' => 'center', 'minWidth' => 95];
$header[] = ['title' => '操作', 'slot' => 'action', 'align' => 'center', 'minWidth' => 70];
$info = ['attr' => $attr, 'value' => $valueNew, 'header' => $header];
return $info;
}
}

View File

@@ -0,0 +1,62 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\services;
use crmeb\interfaces\DeliveryInterface;
use crmeb\services\delivery\Delivery;
use crmeb\services\delivery\storage\Dada;
use crmeb\services\delivery\store\Uupt;
/**
* Class BaseExpress
* @package crmeb\basic
*/
class DeliverySevices
{
protected static $delivery = [];
const DELIVERY_TYPE_DADA = 1;
const DELIVERY_TYPE_UU = 2;
/**
* @param int $type
* @param bool $is_cache
* @return Delivery|mixed
*/
public static function init(int $type = self::DELIVERY_TYPE_DADA, bool $is_cache = false)
{
$type = (int)$type;
if ($is_cache && isset(self::$delivery['delivery_' . $type]) && self::$delivery['delivery_' . $type]) {
return self::$delivery['delivery_' . $type];
}
$config = [];
switch ($type) {
case 1:
$config = [
'app_key' => sys_config('dada_app_key'),
'app_secret' => sys_config('dada_app_sercret'),
'source_id' => sys_config('dada_source_id'),
];
break;
case 2:
$config = [
'app_key' => sys_config('uupt_appkey'),
'app_id' => sys_config('uupt_app_id'),
'open_id' => sys_config('uupt_open_id'),
];
break;
}
return self::$delivery['delivery_' . $type] = new Delivery($type, $config);
}
}

View File

@@ -0,0 +1,217 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\services;
use crmeb\exceptions\AdminException;
use think\exception\ValidateException;
use think\Image;
class DownloadImageService
{
//是否生成缩略图
protected $thumb = false;
//缩略图宽度
protected $thumbWidth = 300;
//缩略图高度
protected $thumHeight = 300;
//存储位置
protected $path = 'attach';
protected $rules = ['thumb', 'thumbWidth', 'thumHeight', 'path'];
/**
* 获取即将要下载的图片扩展名
* @param string $url
* @param string $ex
* @return array|string[]
*/
public function getImageExtname($url = '', $ex = 'jpg')
{
$_empty = ['file_name' => '', 'ext_name' => $ex];
if (!$url) return $_empty;
if (strpos($url, '?')) {
$_tarr = explode('?', $url);
$url = trim($_tarr[0]);
}
$arr = explode('.', $url);
if (!is_array($arr) || count($arr) <= 1) return $_empty;
$ext_name = trim($arr[count($arr) - 1]);
$ext_name = !$ext_name ? $ex : $ext_name;
return ['file_name' => md5($url) . '.' . $ext_name, 'ext_name' => $ext_name];
}
/**
* 下载图片
* @param string $url
* @param string $name
* @param int $upload_type
* @return mixed
*/
public function downloadImage(string $url, $name = '')
{
if (!$name) {
// 获取要下载的文件名称
$downloadImageInfo = $this->getImageExtname($url);
$ext = $downloadImageInfo['ext_name'];
$name = $downloadImageInfo['file_name'];
if (!$name) throw new ValidateException('上传图片不存在');
} else {
$ext = $this->getImageExtname($name)['ext_name'];
}
if (!in_array($ext, ['png', 'jpg', 'jpeg', 'gif'])) {
throw new ValidateException('格式错误,文件后缀不允许');
}
if (strstr($url, 'http://') === false && strstr($url, 'https://') === false) {
$url = 'http:' . $url;
}
$url = str_replace('https://', 'http://', $url);
if ($this->path == 'attach') {
$date_dir = date('Y') . DIRECTORY_SEPARATOR . date('m') . DIRECTORY_SEPARATOR . date('d');
$to_path = $this->path . '/' . $date_dir;
} else {
$to_path = $this->path;
}
$upload = UploadService::init(1);
if (!file_exists($upload->uploadDir($to_path) . '/' . $name)) {
ob_start();
readfile($url);
$content = ob_get_contents();
ob_end_clean();
$size = strlen(trim($content));
if (!$content || $size <= 2) throw new ValidateException('图片流获取失败');
if ($upload->to($to_path)->down($content, $name) === false) {
throw new ValidateException('图片下载失败');
}
$imageInfo = $upload->getDownloadInfo();
$path = $imageInfo['dir'];
if ($this->thumb) {
Image::open(root_path() . 'public' . $path)->thumb($this->thumbWidth, $this->thumHeight)->save(root_path() . 'public' . $path);
$this->thumb = false;
}
} else {
$path = '/uploads/' . $to_path . '/' . $name;
$imageInfo['name'] = $name;
}
$date['path'] = $path;
$date['name'] = $imageInfo['name'];
$date['size'] = $imageInfo['size'] ?? '';
$date['mime'] = $imageInfo['type'] ?? '';
$date['image_type'] = 1;
$date['is_exists'] = false;
return $date;
}
/**
* 网络图片下载
* @param $url
* @param $name
* @param $type
* @param $timeout
* @param $w
* @param $h
* @return array|string
*/
public function downloadOnlineImage($url = '', $name = '', $type = 0, $timeout = 30, $w = 0, $h = 0)
{
if (!strlen(trim($url))) return '';
if (!strlen(trim($name))) {
//TODO 获取要下载的文件名称
$downloadImageInfo = $this->getImageExtname($url);
$ext = $downloadImageInfo['ext_name'];
$name = $downloadImageInfo['file_name'];
if (!strlen(trim($name))) throw new ValidateException('上传图片不存在');
} else {
$ext = $this->getImageExtname($name)['ext_name'];
}
if (!in_array($ext, ['png', 'jpg', 'jpeg', 'gif', 'webp', 'bpm', 'tif', 'pcx', 'tga', 'exif', 'fpx', 'svg', 'apng'])) {
$headerArray = get_headers(str_replace('\\', '/', $url), true);
if (is_array($headerArray['Content-Type']) && count($headerArray['Content-Type']) == 2) {
$contentType = $headerArray['Content-Type'][1];
} else {
$contentType = $headerArray['Content-Type'];
}
if(!$contentType) throw new ValidateException('格式错误,文件后缀不允许');
$img = explode('/',$contentType);
if($img[0]!= 'image') throw new ValidateException('格式错误,文件后缀不允许');
}
if (strstr($url, 'http://') === false && strstr($url, 'https://') === false) {
$url = 'http:' . $url;
}
$url = str_replace('https://', 'http://', $url);
if ($this->path == 'attach') {
$date_dir = date('Y') . DIRECTORY_SEPARATOR . date('m') . DIRECTORY_SEPARATOR . date('d');
$to_path = $this->path . '/' . $date_dir;
} else {
$to_path = $this->path;
}
//TODO 获取远程文件所采用的方法
if ($type) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, false);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); //TODO 跳过证书检查
if (stripos($url, "https://") !== FALSE) curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); //TODO 从证书中检查SSL加密算法是否存在
curl_setopt($ch, CURLOPT_HTTPHEADER, array('user-agent:' . $_SERVER['HTTP_USER_AGENT']));
if (ini_get('open_basedir') == '' && ini_get('safe_mode') == 'Off') curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);//TODO 是否采集301、302之后的页面
$content = curl_exec($ch);
curl_close($ch);
} else {
try {
ob_start();
if (substr($url, 0, 2) == '//') {
$url = "https:" . $url;
}
readfile($url);
$content = ob_get_contents();
ob_end_clean();
} catch (\Exception $e) {
throw new ValidateException($e->getMessage());
}
}
$size = strlen(trim($content));
if (!$content || $size <= 2) throw new ValidateException('图片流获取失败');
$upload_type = sys_config('upload_type', 1);
$upload = UploadService::init($upload_type);
if ($upload->to($to_path)->validate()->setAuthThumb(false)->stream($content, $name) === false) {
throw new ValidateException($upload->getError());
}
$imageInfo = $upload->getUploadInfo();
$date['path'] = $imageInfo['dir'];
$date['name'] = $imageInfo['name'];
$date['size'] = $imageInfo['size'];
$date['mime'] = $imageInfo['type'];
$date['image_type'] = $upload_type;
$date['is_exists'] = false;
return $date;
}
/**
* @param $name
* @param $arguments
* @return $this
*/
public function __call($name, $arguments)
{
if (in_array($name, $this->rules)) {
if ($name === 'path') {
$this->{$name} = $arguments[0] ?? 'attach';
} else {
$this->{$name} = $arguments[0] ?? null;
}
return $this;
} else {
throw new \RuntimeException('Method does not exist' . __CLASS__ . '->' . $name . '()');
}
}
}

View File

@@ -0,0 +1,29 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\services;
class ExpressService
{
protected static $api = [
'query' => 'https://wuliu.market.alicloudapi.com/kdi'
];
public static function query($no, $type = '')
{
$appCode = sys_config('system_express_app_code');
if (!$appCode) return false;
$res = HttpService::getRequest(self::$api['query'], compact('no', 'type'), ['Authorization:APPCODE ' . $appCode]);
$result = json_decode($res, true) ?: false;
return $result;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,49 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\services;
use FormBuilder\Factory\Iview as Form;
use FormBuilder\UI\Iview\Components\InputNumber;
/**
* Form Builder
* Class FormBuilder
* @package crmeb\services
*/
class FormBuilder extends Form
{
public static function setOptions($call)
{
if (is_array($call)) {
return $call;
} else {
return $call();
}
}
public static function number($field,$title,$value = null){
$number = new InputNumber($field, $title, $value);
if (!$number->getProp('max')) {
if ($field == 'sort') {
$number->max(99999);
if (!$number->getProp('min')) {
$number->min(0);
}
} else {
$number->max(9999999999);
}
}
return $number;
}
}

View File

@@ -0,0 +1,133 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\services;
use app\services\system\config\SystemGroupDataServices;use think\facade\Config;
/**
* 获取组合数据配置
* Class GroupDataService
* @package crmeb\services
*/
class GroupDataService
{
/**
* 缓存前缀字符
*/
const CACHE_SYSTEM = 'system_group_data';
/**
* 过期时间
*/
const EXPIRE_TIME = 30 * 24 * 3600;
/**
* 获取配置缓存前缀
* @return string
*/
public static function getTag()
{
return Config::get('cache.stores.redis.tag_prefix') . 'cache_' . self::CACHE_SYSTEM;
}
/**
* 获取单个值
* @param string $config_name 配置名称
* @param int $limit 截取多少条
* @param bool $isCaChe 是否读取缓存
* @return array
*/
public static function getData(string $config_name, int $limit = 0, bool $isCaChe = false): array
{
$callable = function () use ($config_name, $limit) {
event('get.config');
try {
/** @var SystemGroupDataServices $service */
$service = app()->make(SystemGroupDataServices::class);
return $service->getConfigNameValue($config_name, $limit);
} catch (\Exception) {
return [];
}
};
try {
$cacheName = $limit ? "data_{$config_name}_{$limit}" : "data_{$config_name}";
if ($isCaChe)
return $callable();
return CacheService::redisHandler(self::getTag())->remember($cacheName, $callable, self::EXPIRE_TIME);
} catch (\Throwable) {
try {
return $callable();
} catch (\Throwable) {
return [];
}
}
}
/**
* 根据id 获取单个值
* @param int $id
* @param bool $isCaChe 是否读取缓存
* @return array
*/
public static function getDataNumber(int $id, bool $isCaChe = false): array
{
$callable = function () use ($id) {
try {
/** @var SystemGroupDataServices $service */
$service = app()->make(SystemGroupDataServices::class);
$data = $service->getDateValue($id);
if (is_object($data))
$data = $data->toArray();
return $data;
} catch (\Exception) {
return [];
}
};
try {
$cacheName = "data_number_{$id}";
if ($isCaChe)
return $callable();
return CacheService::redisHandler(self::getTag())->remember($cacheName, $callable, self::EXPIRE_TIME);
} catch (\Throwable) {
try {
return $callable();
} catch (\Throwable) {
return [];
}
}
}
/**
* 清空配置缓存
* @return bool|void
*/
public static function clear()
{
try {
return CacheService::redisHandler(self::getTag())->clear();
} catch (\Throwable $e) {
\think\facade\Log::error('清空配置缓存失败:原因:' . $e->getMessage());
return false;
}
}
}

View File

@@ -0,0 +1,156 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\services;
/**
* Class HttpService
* @package crmeb\services
*/
class HttpService
{
/**
* 错误信息
* @var string|null
*/
private static string|null $curlError;
/**
* header头信息
* @var string|null
*/
private static string|null $headerStr;
/**
* 请求状态
* @var int
*/
private static $status;
/**
* @return string
*/
public static function getCurlError()
{
return self::$curlError;
}
/**
* @return mixed
*/
public static function getStatus()
{
return self::$status;
}
/**
* 模拟GET发起请求
* @param $url
* @param array $data
* @param bool $header
* @param int $timeout
* @return bool|string
*/
public static function getRequest($url, $data = array(), $header = false, $timeout = 10)
{
if (!empty($data)) {
$url .= (stripos($url, '?') === false ? '?' : '&');
$url .= (is_array($data) ? http_build_query($data) : $data);
}
return self::request($url, 'get', array(), $header, $timeout);
}
/**
* curl 请求
* @param $url
* @param string $method
* @param array $data
* @param bool $header
* @param int $timeout
* @return bool|string
*/
public static function request($url, $method = 'get', $data = array(), $header = false, $timeout = 15)
{
self::$status = null;
self::$curlError = null;
self::$headerStr = null;
$curl = curl_init($url);
$method = strtoupper($method);
//请求方式
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
//post请求
if ($method == 'POST') {
curl_setopt($curl, CURLOPT_POSTFIELDS, is_array($data) ? http_build_query($data) : $data);
} elseif ($method == 'GET' && count($data)) {
$url .= '?' . http_build_query($data);
curl_setopt($curl, CURLOPT_URL, $url);
}
//超时时间
curl_setopt($curl, CURLOPT_TIMEOUT, 300);
//设置header头
if ($header !== false) curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
curl_setopt($curl, CURLOPT_FAILONERROR, false);
//返回抓取数据
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
//输出header头信息
curl_setopt($curl, CURLOPT_HEADER, true);
//TRUE 时追踪句柄的请求字符串,从 PHP 5.1.3 开始可用。这个很关键,就是允许你查看请求header
curl_setopt($curl, CURLINFO_HEADER_OUT, true);
//https请求
if (1 == strpos("$" . $url, "https://")) {
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
}
self::$curlError = curl_error($curl);
[$content, $status] = [curl_exec($curl), curl_getinfo($curl), curl_close($curl)];
self::$status = $status;
self::$headerStr = trim(substr($content, 0, $status['header_size']));
$content = trim(substr($content, $status['header_size']));
return (intval($status["http_code"]) === 200) ? $content : false;
}
/**
* 模拟POST发起请求
* @param $url
* @param array $data
* @param bool $header
* @param int $timeout
* @return bool|string
*/
public static function postRequest($url, $data = [], $header = false, $timeout = 10)
{
return self::request($url, 'post', $data, $header, $timeout);
}
/**
* 获取header头字符串类型
* @return mixed
*/
public static function getHeaderStr()
{
return self::$headerStr;
}
/**
* 获取header头数组类型
* @return array
*/
public static function getHeader()
{
$headArr = explode("\r\n", self::$headerStr);
return $headArr;
}
}

View File

@@ -0,0 +1,55 @@
<?php
namespace crmeb\services;
use think\exception\ValidateException;
use think\facade\Cache;
class LockService
{
/**
* @param $key
* @param $fn
* @param int $ex
* @return mixed
* @author 吴汐
* @email 442384644@qq.com
* @date 2023/03/01
*/
public function exec($key, $fn, int $ex = 6)
{
try {
if ($this->lock($key, $key, $ex))
return $fn();
else throw new ValidateException('请求太过频繁,请稍后再试');
} finally {
$this->unlock($key, $key);
}
}
public function tryLock($key, $value = '1', $ex = 6)
{
return Cache::store('redis')->handler()->set('lock_' . $key, $value, ["NX", "EX" => $ex]);
}
public function lock($key, $value = '1', $ex = 6)
{
if ($this->tryLock($key, $value, $ex)) {
return true;
} else {
return false;
}
}
public function unlock($key, $value = '1')
{
$script = <<< EOF
if (redis.call("get", "lock_" .. KEYS[1]) == ARGV[1]) then
return redis.call("del", "lock_" .. KEYS[1])
else
return 0
end
EOF;
return Cache::store('redis')->handler()->eval($script, [$key, $value], 1) > 0;
}
}

View File

@@ -0,0 +1,526 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\services;
use think\facade\Db;
class MysqlBackupService
{
/**
* 文件指针
* @var resource
*/
private $fp;
/**
* 备份文件信息 part - 卷号,name - 文件名
* @var array
*/
private $file;
/**
* 当前打开文件大小
* @var integer
*/
private $size = 0;
/**
* 数据库配置
* @var integer
*/
private $dbconfig = array();
/**
* 备份配置
* @var integer
*/
private $config = array(
'path' => './Data/',
//数据库备份路径
'part' => 20971520,
//数据库备份卷大小
'compress' => 0,
//数据库备份文件是否启用压缩 0不压缩 1 压缩
'level' => 9,
);
/**
* 数据库备份构造方法
*
* @param array $file 备份或还原的文件信息
* @param array $config 备份配置信息
*/
public function __construct($config = [])
{
$this->config['path'] = app()->getRootPath() . 'backup/';
$this->config = array_merge($this->config, $config);
//初始化文件名
$this->setFile();
//初始化数据库连接参数
$this->setDbConn();
//检查文件是否可写
if (!$this->checkPath($this->config['path'])) {
throw new \Exception("The current directory is not writable");
}
}
/**
* 设置脚本运行超时时间
* 0表示不限制,支持连贯操作
*/
public function setTimeout($time = null)
{
if (!is_null($time)) {
set_time_limit($time) || ini_set("max_execution_time", $time);
}
return $this;
}
/**
* 设置数据库连接必备参数
*
* @param array $dbconfig 数据库连接配置信息
* @return $this
*/
public function setDbConn($dbconfig = [])
{
if (empty($dbconfig)) {
$this->dbconfig = config('database.connections.' . config('database.default'));
//$this->dbconfig = Config::get('database');
} else {
$this->dbconfig = $dbconfig;
}
return $this;
}
/**
* 设置备份文件名
*
* @param null $file
* @return $this
*/
public function setFile($file = null)
{
if (is_null($file)) {
$this->file = ['name' => date('Ymd-His'), 'part' => 1];
} else {
if (!array_key_exists("name", $file) && !array_key_exists("part", $file)) {
$this->file = $file['1'];
} else {
$this->file = $file;
}
}
return $this;
}
//数据类连接
public static function connect()
{
return Db::connect();
}
/**
* 数据库表列表
*
* @param null $table
* @param int $type
* @return array
* @throws \think\db\exception\BindParamException
* @throws \think\exception\PDOException
*/
public function dataList(?string $table = null, int $type = 1)
{
$key = 'mysql_backup_' . $table . '_' . $type;
$data = CacheService::get($key);
if (!$data) {
$db = self::connect();
if (is_null($table)) {
$list = $db->query("SHOW TABLE STATUS");
} else {
if ($type) {
$list = $db->query("SHOW FULL COLUMNS FROM {$table}");
} else {
$list = $db->query("show columns from {$table}");
}
}
$data = array_map('array_change_key_case', $list);
CacheService::set($key, $data, 7200);
}
return $data;
}
/**
* 数据库备份文件列表
*
* @return array
*/
public function fileList()
{
$list = [];
if (!is_dir($this->config['path'])) {
mkdir($this->config['path'], 0755, true);
return $list;
}
$path = realpath($this->config['path']);
$flag = \FilesystemIterator::KEY_AS_FILENAME;
$glob = new \FilesystemIterator($path, $flag);
foreach ($glob as $name => $file) {
if (preg_match('/^\\d{8,8}-\\d{6,6}-\\d+\\.sql(?:\\.gz)?$/', $name)) {
$info['filename'] = $name;
$name = sscanf($name, '%4s%2s%2s-%2s%2s%2s-%d');
$date = $name[0] . '-' . $name[1] . '-' . $name[2];
$time = $name[3] . ':' . $name[4] . ':' . $name[5];
$part = $name[6];
if (isset($list[$date . $time])) {
$info = $list[$date . $time];
$info['part'] = max($info['part'], $part);
$info['size'] = $info['size'] + $file->getSize();
} else {
$info['part'] = $part;
$info['size'] = $file->getSize();
}
$extension = strtoupper(pathinfo($file->getFilename(), PATHINFO_EXTENSION));
$info['compress'] = $extension === 'SQL' ? '-' : $extension;
$info['time'] = strtotime($date . $time);
$list[$date . $time] = $info;
}
}
return $list;
}
/**
* @param string $type
* @param int $time
* @return array|false|string
* @throws \Exception
*/
public function getFile($type = '', $time = 0)
{
//
if (!is_numeric($time)) {
throw new \Exception("{$time} Illegal data type");
}
switch ($type) {
case 'time':
$name = date('Ymd-His', $time) . '-*.sql*';
$path = realpath($this->config['path']) . DIRECTORY_SEPARATOR . $name;
return glob($path);
break;
case 'timeverif':
$name = date('Ymd-His', $time) . '-*.sql*';
$path = realpath($this->config['path']) . DIRECTORY_SEPARATOR . $name;
$files = glob($path);
$list = array();
foreach ($files as $name) {
$basename = basename($name);
$match = sscanf($basename, '%4s%2s%2s-%2s%2s%2s-%d');
$gz = preg_match('/^\\d{8,8}-\\d{6,6}-\\d+\\.sql.gz$/', $basename);
$list[$match[6]] = array($match[6], $name, $gz);
}
$last = end($list);
if (count($list) === $last[0]) {
return $list;
} else {
throw new \Exception("File {$files['0']} may be damaged, please check again");
}
break;
case 'pathname':
return "{$this->config['path']}{$this->file['name']}-{$this->file['part']}.sql";
break;
case 'filename':
return "{$this->file['name']}-{$this->file['part']}.sql";
break;
case 'filepath':
return $this->config['path'];
break;
default:
$arr = array('pathname' => "{$this->config['path']}{$this->file['name']}-{$this->file['part']}.sql", 'filename' => "{$this->file['name']}-{$this->file['part']}.sql", 'filepath' => $this->config['path'], 'file' => $this->file);
return $arr;
}
}
/**
* 删除备份文件
* @param $time
* @return mixed
* @throws \Exception
*/
public function delFile($time)
{
if ($time) {
$file = $this->getFile('time', $time);
array_map("unlink", $this->getFile('time', $time));
if (count($this->getFile('time', $time))) {
throw new \Exception("File {$time} deleted failed");
} else {
return $time;
}
} else {
throw new \Exception("{$time} Time parameter is incorrect");
}
}
/**
* 下载备份
*
* @param $time
* @param int $part
* @throws \Exception
*/
public function downloadFile($time, int $part = 0, bool $isFile = false)
{
$file = $this->getFile('time', $time);
$fileName = $file[$part];
if (file_exists($fileName)) {
if ($isFile) {
$key = password_hash(time() . $fileName, PASSWORD_DEFAULT);
CacheService::set($key, ['path' => $fileName, 'fileName' => substr(strstr($fileName, 'backup'), 7)], 300);
return $key;
}
ob_end_clean();
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header('Content-Description: File Transfer');
header('Access-Control-Allow-Origin: ' . request()->domain());
header('Content-Type: application/octet-stream');
header('Content-Length: ' . filesize($fileName));
header('Content-Disposition: attachment; filename=' . basename($fileName));
return readfile($fileName);
} else {
throw new \Exception("{$time} File is abnormal");
}
}
public function import($start)
{
//还原数据
$db = self::connect();
if ($this->config['compress']) {
$gz = gzopen($this->file[1], 'r');
$size = 0;
} else {
$size = filesize($this->file[1]);
$gz = fopen($this->file[1], 'r');
}
$sql = '';
if ($start) {
$this->config['compress'] ? gzseek($gz, $start) : fseek($gz, $start);
}
for ($i = 0; $i < 1000; $i++) {
$sql .= $this->config['compress'] ? gzgets($gz) : fgets($gz);
if (preg_match('/.*;$/', trim($sql))) {
if (false !== $db->execute($sql)) {
$start += strlen($sql);
} else {
return false;
}
$sql = '';
} elseif ($this->config['compress'] ? gzeof($gz) : feof($gz)) {
return 0;
}
}
return array($start, $size);
}
/**
* 写入初始数据
*
* @return boolean true - 写入成功,false - 写入失败
*/
public function Backup_Init()
{
$sql = "-- -----------------------------\n";
$sql .= "-- Think MySQL Data Transfer \n";
$sql .= "-- \n";
$sql .= "-- Host : " . $this->dbconfig['hostname'] . "\n";
$sql .= "-- Port : " . $this->dbconfig['hostport'] . "\n";
$sql .= "-- Database : " . $this->dbconfig['database'] . "\n";
$sql .= "-- \n";
$sql .= "-- Part : #{$this->file['part']}\n";
$sql .= "-- Date : " . date("Y-m-d H:i:s") . "\n";
$sql .= "-- -----------------------------\n\n";
$sql .= "SET FOREIGN_KEY_CHECKS = 0;\n\n";
return $this->write($sql);
}
/**
* 备份表结构
*
* @param string $table
* @param int $start
* @return bool|int
* @throws \think\db\exception\BindParamException
* @throws \think\exception\PDOException
*/
public function backup(string $table, int $start, $sql = '')
{
$db = self::connect();
// 备份表结构
if (0 == $start) {
$result = $db->query("SHOW CREATE TABLE `{$table}`");
$sql .= "\n";
$sql .= "-- -----------------------------\n";
$sql .= "-- Table structure for `{$table}`\n";
$sql .= "-- -----------------------------\n";
$sql .= "DROP TABLE IF EXISTS `{$table}`;\n";
$sql .= trim($result[0]['Create Table']) . ";\n\n";
}
//数据总数
$result = $db->query("SELECT COUNT(*) AS count FROM `{$table}`");
$count = $result['0']['count'];
//备份表数据
if ($count) {
//写入数据注释
if (0 == $start) {
$sql .= "-- -----------------------------\n";
$sql .= "-- Records of `{$table}`\n";
$sql .= "-- -----------------------------\n";
}
//备份数据记录
$result = $db->query("SELECT * FROM `{$table}` LIMIT :MIN, 1000", ['MIN' => intval($start)]);
foreach ($result as $row) {
$row = array_map('addslashes', $row);
$sql .= "INSERT INTO `{$table}` VALUES ('" . str_replace(array("\r", "\n"), array('\\r', '\\n'), implode("', '", $row)) . "');\n";
}
if (false === $this->write($sql)) {
return false;
}
//还有更多数据
if ($count > $start + 1000) {
//return array($start + 1000, $count);
return $this->backup($table, $start + 1000);
}
}
//备份下一表
return 0;
}
/**
* 优化表
*
* @param array|string $tables
* @throws \think\db\exception\BindParamException
* @throws \think\exception\PDOException
*/
public function optimize($tables)
{
if ($tables) {
$db = self::connect();
if (is_array($tables)) {
$tables = implode('`,`', $tables);
$list = $db->query("OPTIMIZE TABLE `{$tables}`");
} else {
$list = $db->query("OPTIMIZE TABLE {$tables}");
}
if (!$list) {
throw new \Exception("data sheet'{$tables}'Repair mistakes please try again!");
}
return $list;
} else {
throw new \Exception("Please specify the table to be repaired!");
}
}
/**
* 修复表
*
* @param string|null $tables
* @return array
* @throws \think\db\exception\BindParamException
* @throws \think\exception\PDOException
*/
public function repair(?string $tables = null)
{
if ($tables) {
$db = self::connect();
if (is_array($tables)) {
$tables = implode('`,`', $tables);
$list = $db->query("REPAIR TABLE `{$tables}`");
} else {
$list = $db->query("REPAIR TABLE {$tables}");
}
if ($list) {
return $list;
} else {
throw new \Exception("data sheet'{$tables}'Repair mistakes please try again!");
}
} else {
throw new \Exception("Please specify the table to be repaired!");
}
}
/**
* 写入SQL语句
*
* @param string $sql 要写入的SQL语句
* @return boolean true - 写入成功,false - 写入失败!
*/
private function write(string $sql)
{
$size = strlen($sql);
//由于压缩原因,无法计算出压缩后的长度,这里假设压缩率为50%,
//一般情况压缩率都会高于50%;
$size = $this->config['compress'] ? $size / 2 : $size;
$this->open($size);
return $this->config['compress'] ? @gzwrite($this->fp, $sql) : @fwrite($this->fp, $sql);
}
/**
* 打开一个卷,用于写入数据
*
* @param integer $size 写入数据的大小
*/
private function open(int $size)
{
if ($this->fp) {
$this->size += $size;
if ($this->size > $this->config['part']) {
$this->config['compress'] ? @gzclose($this->fp) : @fclose($this->fp);
$this->fp = null;
$this->file['part']++;
session('backup_file', $this->file);
$this->Backup_Init();
}
} else {
$backuppath = $this->config['path'];
$filename = "{$backuppath}{$this->file['name']}-{$this->file['part']}.sql";
if ($this->config['compress']) {
$filename = "{$filename}.gz";
$this->fp = @gzopen($filename, "a{$this->config['level']}");
} else {
$this->fp = @fopen($filename, 'a');
}
$this->size = filesize($filename) + $size;
}
}
/**
* 检查目录是否可写
*
* @param string $path
* @return bool
*/
protected function checkPath(string $path)
{
if (is_dir($path)) {
return true;
}
if (mkdir($path, 0755, true)) {
return true;
} else {
return false;
}
}
/**
* 析构方法,用于关闭文件资源
*/
public function __destruct()
{
$this->config['compress'] ? @gzclose($this->fp) : @fclose($this->fp);
}
}

View File

@@ -0,0 +1,120 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\services;
use app\services\system\attachment\SystemAttachmentServices;
use crmeb\services\wechat\MiniProgram;
use GuzzleHttp\Psr7\Utils;
/**
* Class QrcodeService
* @package crmeb\services
*/
class QrcodeService
{
/**
* 获取二维码完整路径,不存在则自动生成
* @param string $name 路径名
* @param string $link 需要生成二维码的跳转路径
* @param int $type https 1 = http , 0 = https
* @param bool $force 是否返回false
* @return bool|mixed|string
*/
public static function getWechatQrcodePath(string $name, string $link, bool $force = false)
{
/** @var SystemAttachmentServices $systemAttchment */
$systemAttchment = app()->make(SystemAttachmentServices::class);
try {
$imageInfo = $systemAttchment->getInfo(['name' => $name]);
$siteUrl = sys_config('site_url');
if (!$imageInfo) {
$codeUrl = UtilService::setHttpType($siteUrl . $link, request()->isSsl() ? 0 : 1);//二维码链接
$imageInfo = UtilService::getQRCodePath($codeUrl, $name);
if (is_string($imageInfo) && $force)
return false;
if (is_array($imageInfo)) {
$systemAttchment->attachmentAdd($imageInfo['name'], $imageInfo['size'], $imageInfo['type'], $imageInfo['dir'], $imageInfo['thumb_path'], 1, $imageInfo['image_type'], $imageInfo['time'], 2);
$url = $imageInfo['dir'];
} else {
$url = '';
$imageInfo = ['image_type' => 0];
}
} else $url = $imageInfo['att_dir'];
if ($imageInfo['image_type'] == 1 && $url) $url = $siteUrl . $url;
return $url;
} catch (\Throwable $e) {
if ($force)
return false;
else
return '';
}
}
/**
* 获取小程序分享二维码
* @param int $id
* @param int $uid
* @param int $type 1 = 拼团,2 = 秒杀
* @return bool|string
*/
public static function getRoutineQrcodePath(int $id, int $uid, int $type, array $parame = [])
{
$page = '';
$namePath = '';
$data = 'id=' . $id . '&pid=' . $uid;
switch ($type) {
case 1:
$page = '/pages/activity/goods_details/index?type=3';
$namePath = 'combination_' . $id . '_' . $uid . '.jpg';
break;
case 2:
$page = '/pages/activity/goods_details/index?type=1';
$namePath = 'seckill_' . $id . '_' . $uid . '.jpg';
if (isset($parame['stop_time']) && $parame['stop_time']) {
$data .= '&time=' . $parame['stop_time'];
$namePath = $parame['stop_time'] . $namePath;
}
break;
}
if (!$page || !$namePath) {
return false;
}
/** @var SystemAttachmentServices $systemAttchment */
$systemAttchment = app()->make(SystemAttachmentServices::class);
try {
$imageInfo = $systemAttchment->getInfo($namePath, 'name');
$siteUrl = sys_config('site_url');
if (!$imageInfo) {
$res = MiniProgram::appCodeUnlimit($page, $data, 280);
if (!$res) return false;
$uploadType = (int)sys_config('upload_type', 1);
$upload = UploadService::init($uploadType);
$res = (string)Utils::streamFor($res);
$res = $upload->to('routine/product')->validate()->stream($res, $namePath);
if ($res === false) {
return false;
}
$imageInfo = $upload->getUploadInfo();
$imageInfo['image_type'] = $uploadType;
if ($imageInfo['image_type'] == 1) $remoteImage = UtilService::remoteImage($siteUrl . $imageInfo['dir']);
else $remoteImage = UtilService::remoteImage($imageInfo['dir']);
if (!$remoteImage['status']) return false;
$systemAttchment->attachmentAdd($imageInfo['name'], $imageInfo['size'], $imageInfo['type'], $imageInfo['dir'], $imageInfo['thumb_path'], 1, $imageInfo['image_type'], $imageInfo['time'], 2);
$url = $imageInfo['dir'];
} else $url = $imageInfo['att_dir'];
if ($imageInfo['image_type'] == 1) $url = $siteUrl . $url;
return $url;
} catch (\Throwable $e) {
return false;
}
}
}

View File

@@ -0,0 +1,166 @@
<?php
/**
* +----------------------------------------------------------------------
* | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
* +----------------------------------------------------------------------
* | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
* +----------------------------------------------------------------------
* | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
* +----------------------------------------------------------------------
* | Author: CRMEB Team <admin@crmeb.com>
* +----------------------------------------------------------------------
*/
namespace crmeb\services;
use think\facade\Config;
use Swoole\Coroutine\Channel;
use Swoole\Coroutine\Redis;
/**
* Class RedisService
* @author 等风来
* @email 136327134@qq.com
* @date 2022/10/29
* @package crmeb\services
*/
class RedisService
{
/**
* @var array
*/
protected $config;
/**
* 获取进程池最大时间
* @var int
*/
protected $maxWaitTime = 3;
/**
* 最大连接池数量
* @var int
*/
protected $maxActive;
/**
* @var Channel
*/
protected $pool;
/**
* RedisService constructor.
* @param array $config
* @param array $pool
*/
public function __construct(array $config = [], array $pool = [])
{
$this->config = $config ?: Config::get('cache.stores.redis');
$this->maxActive = $pool['maxActive'] ?? Config::get('swoole.pool.redis.cache.max_active', 50);
$this->maxWaitTime = $pool['maxWaitTime'] ?? Config::get('swoole.pool.redis.cache.max_wait_time', 5);
}
/**
* 初始化连接池
* @author 等风来
* @email 136327134@qq.com
* @date 2022/10/29
*/
public function init()
{
$this->pool = new Channel($this->maxActive);
go(function () {
for ($i = 0; $i < $this->maxActive; $i++) {
$redis = $this->createConnect($this->config);
$this->pool->push($redis);
}
});
return $this;
}
/**
* 创建连接
* @param array $config
* @return mixed
* @author 等风来
* @email 136327134@qq.com
* @date 2022/10/29
*/
public function createConnect(array $config)
{
$connection = new Redis();
$res = $connection->connect($config['host'], $config['port'], \Redis::SERIALIZER_PHP);
if ($config['password']) {
$connection->auth($config['password']);
}
$connection->select($config['select']);
if ($res === false) {
throw new \RuntimeException("Failed to connect redis server");
}
return $connection;
}
/**
* 销毁连接
* @param $connection
* @author 等风来
* @email 136327134@qq.com
* @date 2022/10/29
*/
public function removeConnect($connection)
{
\Swoole\Coroutine\defer(function () use ($connection) { //释放
$connection->close();
});
}
/**
* 获取redis连接句柄
* @return Redis
* @author 等风来
* @email 136327134@qq.com
* @date 2022/10/29
*/
public function getRedis()
{
if ($this->pool->isEmpty()) {
$redis = $this->createConnect($this->config);
$this->removeConnect($redis);
return $redis;
}
$redis = $this->pool->pop($this->maxWaitTime);
if (false === $redis) {
$redis = $this->createConnect($this->config);
$this->removeConnect($redis);
} else {
\Swoole\Coroutine\defer(function () use ($redis) { //释放
$this->pool->push($redis);
});
}
return $redis;
}
/**
* @param $name
* @param $arguments
* @return Redis
* @author 等风来
* @email 136327134@qq.com
* @date 2022/10/29
*/
public function __call($name, $arguments)
{
return call_user_func_array([$this->getRedis(), $name], $arguments);
}
}

View File

@@ -0,0 +1,344 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\services;
use crmeb\utils\Arr;
use PhpOffice\PhpSpreadsheet\IOFactory;
class SpreadsheetExcelService
{
//
private static $instance = null;
//PHPSpreadsheet实例化对象
private static $spreadsheet = null;
//sheet实例化对象
private static $sheet = null;
//表头计数
protected static $count;
//表头占行数
protected static $topNumber = 3;
//表能占据表行的字母对应self::$cellkey
protected static $cells;
//表头数据
protected static $data = [];
//文件名
protected static $title = '订单导出';
//行宽
protected static $width = 20;
//行高
protected static $height = 50;
//保存文件目录
protected static $path = '/phpExcel/';
//设置style
private static $styleArray = [
// 'borders' => [
// 'allBorders' => [
// // PHPExcel_Style_Border里面有很多属性,想要其他的自己去看
// // 'style' => \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THICK,//边框是粗的
// // 'style' => \PHPExcel_Style_Border::BORDER_DOUBLE,//双重的
// // 'style' => \PHPExcel_Style_Border::BORDER_HAIR,//虚线
// // 'style' => \PHPExcel_Style_Border::BORDER_MEDIUM,//实粗线
// // 'style' => \PHPExcel_Style_Border::BORDER_MEDIUMDASHDOT,//虚粗线
// // 'style' => \PHPExcel_Style_Border::BORDER_MEDIUMDASHDOTDOT,//点虚粗线
// 'style' => \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN,//细边框
// // 'color' => ['argb' => 'FFFF0000'],
// ],
// ],
'font' => [
'bold' => true
],
'alignment' => [
'horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER,
'vertical' => \PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_CENTER
]
];
private function __construct()
{
}
private function __clone()
{
}
public static function instance()
{
if (self::$instance === null) {
self::$instance = new self();
self::$spreadsheet = $spreadsheet = new \PhpOffice\PhpSpreadsheet\Spreadsheet();
self::$sheet = $spreadsheet->getActiveSheet();
}
return self::$instance;
}
/**
* 设置字符串字符集
* @param string $str 需要设置字符集的字符串
* @return string
*/
public function utf8String($str)
{
$str = is_object($str) ? $str->__toString() : $str;
$encode = mb_detect_encoding($str, ["ASCII", 'UTF-8', "GB2312", "GBK", 'BIG5', 'CP936']);
if (strtoupper($encode) != 'UTF-8') $str = mb_convert_encoding($str, 'utf-8', $encode);
return $str;
}
/**
* 创建保存excel目录
* return string
*/
public static function savePath()
{
if (!is_dir(self::$path)) {
if (mkdir(self::$path, 0700) == false) {
return false;
}
}
//年月一级目录
$mont_path = self::$path . date('Ym');
if (!is_dir($mont_path)) {
if (mkdir($mont_path, 0700) == false) {
return false;
}
}
//日二级目录
$day_path = $mont_path . '/' . date('d');
if (!is_dir($day_path)) {
if (mkdir($day_path, 0700) == false) {
return false;
}
}
return $day_path;
}
/**
* 设置标题
* @param $title string || array ['title'=>'','name'=>'','info'=>[]]
* @param $Name string
* @param $info string || array;
* @param $funName function($style,$A,$A2) 自定义设置头部样式
* @return $this
*/
public function setExcelTile($title = '', $Name = '', $info = [], $funName = null)
{
//设置参数
if (is_array($title)) {
if (isset($title['title'])) $title = $title['title'];
if (isset($title['name'])) $Name = $title['name'];
if (isset($title['info'])) $info = $title['info'];
}
if (empty($title))
$title = self::$title;
else
self::$title = $title;
if (empty($Name)) $Name = time();
//设置Excel属性
self::$spreadsheet->getProperties()
->setCreator("Neo")
->setLastModifiedBy("Neo")
->setTitle($this->utf8String($title))
->setSubject($Name)
->setDescription("")
->setKeywords($Name)
->setCategory("");
self::$sheet->setTitle($Name);
self::$sheet->setCellValue('A1', $title);
self::$sheet->setCellValue('A2', self::setCellInfo($info));
//文字居中
self::$sheet->getStyle('A1')->getAlignment()->setHorizontal(\PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER);
self::$sheet->getStyle('A2')->getAlignment()->setHorizontal(\PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER);
//合并表头单元格
self::$sheet->mergeCells('A1:' . self::$cells . '1');
self::$sheet->mergeCells('A2:' . self::$cells . '2');
self::$sheet->getRowDimension(1)->setRowHeight(40);
self::$sheet->getRowDimension(2)->setRowHeight(20);
//设置表头字体
self::$sheet->getStyle('A1')->getFont()->setName('黑体');
self::$sheet->getStyle('A1')->getFont()->setSize(20);
self::$sheet->getStyle('A1')->getFont()->setBold(true);
self::$sheet->getStyle('A2')->getFont()->setName('宋体');
self::$sheet->getStyle('A2')->getFont()->setSize(14);
self::$sheet->getStyle('A2')->getFont()->setBold(true);
self::$sheet->getStyle('A3:' . self::$cells . '3')->getFont()->setBold(true);
return $this;
}
/**
* 设置第二行标题内容
* @param $info array (['name'=>'','site'=>'','phone'=>123] || ['我是表名','我是地址','我是手机号码'] ) || string 自定义
* @return string
*/
private static function setCellInfo($info)
{
$content = ['操作者:', '导出日期:' . date('Y-m-d', time()), '地址:', '电话:'];
if (is_array($info) && !empty($info)) {
if (isset($info['name'])) {
$content[0] .= $info['name'];
} else {
$content[0] .= isset($info[0]) ? $info[0] : '';
}
if (isset($info['site'])) {
$content[2] .= $info['site'];
} else {
$content[2] .= isset($info[1]) ? $info[1] : '';
}
if (isset($info['phone'])) {
$content[3] .= $info['phone'];
} else {
$content[3] .= isset($info[2]) ? $info[2] : '';
}
return implode(' ', $content);
} else if (is_string($info)) {
return empty($info) ? implode(' ', $content) : $info;
}
}
/**
* 设置头部信息
* @param $data array
* @return $this
*/
public function setExcelHeader($data)
{
$span = 'A';
foreach ($data as $key => $value) {
self::$sheet->getColumnDimension($span)->setWidth(self::$width);
self::$sheet->setCellValue($span . self::$topNumber, $value);
$span++;
}
self::$sheet->getRowDimension(3)->setRowHeight(self::$height);
self::$cells = $span;
return $this;
}
/**
* 读取表格内的文件数据
* @param string $filePath
* @param array $cellsData
* @param callable $closure
* @param int $startLine
* @return array
* @throws \PhpOffice\PhpSpreadsheet\Exception
* @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
*/
public static function getExcelData(string $filePath, array $cellsData = [], callable $closure = null, int $startLine = 2)
{
if (!file_exists($filePath)) {
throw new \RuntimeException('文件不存在');
}
$extension = ucwords(pathinfo($filePath, PATHINFO_EXTENSION));
$io = IOFactory::createreader($extension);
$spreadsheet = $io->load($filePath);
$worksheet = $spreadsheet->getActiveSheet();
$highestRow = $worksheet->getHighestRow();
$data = [];
if ($closure) {
$closure($worksheet);
}
for ($j = $startLine; $j <= (int)$highestRow; $j++) {
$value = [];
foreach ($cellsData as $key => $val) {
if ($v = $worksheet->getCell($val . $j)->getValue()) {
$value[$key] = $v;
}
}
if ($value) {
$data[] = $value;
}
}
return Arr::filterValue($data);
}
/**
*
* execl数据导出
* @param $data 需要导出的数据 格式和以前的可是一样
*
* 特殊处理:合并单元格需要先对数据进行处理
*/
public function setExcelContent($data = [])
{
if (!empty($data) && is_array($data)) {
$column = self::$topNumber + 1;
// 行写入
foreach ($data as $key => $rows) {
$span = 'A';
// 列写入
foreach ($rows as $keyName => $value) {
self::$sheet->setCellValue($span . $column, $this->utf8String($value));
$span++;
}
$column++;
}
self::$sheet->getDefaultRowDimension()->setRowHeight(self::$height);
//设置内容字体样式
self::$sheet->getStyle('A1:' . $span . $column)->applyFromArray(self::$styleArray);
//设置边框
self::$sheet->getStyle('A1:' . $span . ($column - 1))->getBorders()->getAllBorders()->setBorderStyle(\PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN);
//设置自动换行
self::$sheet->getStyle('A4:' . $span . $column)->getAlignment()->setWrapText(true);
}
return $this;
}
/**
* 保存表格数据,直接下载
* @param $filename 文件名称
* @param $suffix 文件后缀名
* @param $is_save 是否保存文件
* @return 保存文件:return string
*/
public function excelSave($fileName = '', $suffix = 'xlsx', $is_save = false)
{
if (empty($fileName)) {
$fileName = date('YmdHis') . time();
}
if (empty($suffix)) {
$suffix = 'xlsx';
}
// 重命名表(UTF8编码不需要这一步)
if (mb_detect_encoding($fileName) != "UTF-8") {
$fileName = iconv("utf-8", "gbk//IGNORE", $fileName);
}
$spreadsheet = self::$spreadsheet;
$writer = new \PhpOffice\PhpSpreadsheet\Writer\Xlsx($spreadsheet);
if (!$is_save) {//直接下载
header('Content-Disposition: attachment;filename="' . $fileName . '.' . $suffix . '"');
header('Cache-Control: max-age=0');
$writer->save('php://output');
// 删除清空 释放内存
// $spreadsheet->disconnectWorksheets();
unset($spreadsheet);
} else {//保存文件
$root_path = app()->getRootPath() . 'public/phpExcel';
if (!is_dir($root_path)) mkdir($root_path, 0700, true);
$path = $root_path . '/' . $fileName . '.' . $suffix;
//$writer = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter($spreadsheet, 'Xlsx');
//$writer->save($path);
$writer->save($path);
// 删除清空 释放内存
// $spreadsheet->disconnectWorksheets();
unset($spreadsheet);
return '/phpExcel/' . $fileName . '.' . $suffix;
}
}
}

View File

@@ -0,0 +1,146 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\services;
use app\services\system\config\SystemConfigServices;
use crmeb\utils\Arr;
use think\facade\Config;
use think\facade\Db;
/** 获取系统配置服务类
* Class SystemConfigService
* @package service
*/
class SystemConfigService
{
/**
* 缓存前缀字符
*/
const CACHE_SYSTEM = 'system_config';
/**
* 过期时间
*/
const EXPIRE_TIME = 30 * 24 * 3600;
/**
* @var int
*/
protected static $relationId = 0;
/**
* @var int
*/
protected static $type = 0;
/**
* 获取配置缓存前缀
* @return string
*/
public static function getTag()
{
return Config::get('cache.stores.redis.tag_prefix') . 'cache_' . self::CACHE_SYSTEM;
}
/**
* @param int $storeId
*/
public static function setStore(int $storeId)
{
self::$relationId = $storeId;
self::$type = 1;
}
/**
* @param int $supplier
*/
public static function setSupplier(int $supplier)
{
self::$relationId = $supplier;
self::$type = 2;
}
/**
* 获取单个配置效率更高
* @param $key
* @param string $default
* @param bool $isCaChe 是否获取缓存配置
* @return bool|mixed|string
*/
public static function get(string $key, $default = '', bool $isCaChe = false)
{
$cacheName = self::CACHE_SYSTEM . ':' . $key . (self::$type ? '_' . self::$type : '') . (self::$relationId ? '_' . self::$relationId : '');
$type = self::$type;
$relationId = self::$relationId;
$callable = function () use ($key, $type, $relationId) {
event('get.config');
/** @var SystemConfigServices $service */
$service = app()->make(SystemConfigServices::class);
return $service->getConfigValue($key, $type, $relationId);
};
try {
if ($isCaChe) {
return $callable();
}
$value = CacheService::redisHandler(self::getTag())->remember($cacheName, $callable, self::EXPIRE_TIME);
self::$relationId = 0;
self::$type = 0;
return $value;
} catch (\Throwable $e) {
return $default;
}
}
/**
* 获取多个配置
* @param array $keys 示例 [['appid','1'],'appkey']
* @param bool $isCaChe 是否获取缓存配置
* @return array
*/
public static function more(array $keys, bool $isCaChe = false)
{
$cacheName = self::CACHE_SYSTEM . ':' . md5(implode(',', $keys) . (self::$type ? '_' . self::$type : '') . (self::$relationId ? '_' . self::$relationId : ''));
$type = self::$type;
$relationId = self::$relationId;
$callable = function () use ($keys, $type, $relationId) {
/** @var SystemConfigServices $service */
$service = app()->make(SystemConfigServices::class);
return Arr::getDefaultValue($keys, $service->getConfigAll($keys, $type, $relationId));
};
try {
if ($isCaChe)
return $callable();
$value = CacheService::redisHandler(self::getTag())->remember($cacheName, $callable, self::EXPIRE_TIME);
self::$relationId = 0;
self::$type = 0;
return $value;
} catch (\Throwable $e) {
return Arr::getDefaultValue($keys);
}
}
/**
* 清空配置缓存
* @return bool|void
*/
public static function clear()
{
try {
return CacheService::redisHandler(self::getTag())->clear();
} catch (\Throwable $e) {
\think\facade\Log::error('清空配置缓存失败:原因:' . $e->getMessage());
return false;
}
}
}

View File

@@ -0,0 +1,148 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\services;
use app\services\system\config\SystemStorageServices;
use crmeb\services\upload\Upload;
/**
* Class UploadService
* @package crmeb\services
*/
class UploadService
{
protected static $upload = [];
/**
* @param null $type
* @return Upload|mixed
*/
public static function init($type = null, $is_cache = false)
{
if (is_null($type)) {
$type = (int)sys_config('upload_type', 1);
}
if ($is_cache && isset(self::$upload['upload_' . $type]) && self::$upload['upload_' . $type]) {
return self::$upload['upload_' . $type];
}
$type = (int)$type;
$config = [];
switch ($type) {
case 2://七牛
$config = [
'accessKey' => sys_config('qiniu_accessKey'),
'secretKey' => sys_config('qiniu_secretKey'),
];
break;
case 3:// oss 阿里云
$config = [
'accessKey' => sys_config('accessKey'),
'secretKey' => sys_config('secretKey'),
];
break;
case 4:// cos 腾讯云
$config = [
'accessKey' => sys_config('tengxun_accessKey'),
'secretKey' => sys_config('tengxun_secretKey'),
'appid' => sys_config('tengxun_appid'),
];
break;
case 5://京东云
$config = [
'accessKey' => sys_config('jd_accessKey'),
'secretKey' => sys_config('jd_secretKey'),
'storageRegion' => sys_config('jd_storage_region'),
];
break;
case 6://华为云
$config = [
'accessKey' => sys_config('hw_accessKey'),
'secretKey' => sys_config('hw_secretKey'),
];
break;
case 7://天翼云
$config = [
'accessKey' => sys_config('ty_accessKey'),
'secretKey' => sys_config('ty_secretKey'),
];
break;
}
$thumb = SystemConfigService::more(['thumb_big_height', 'thumb_big_width', 'thumb_mid_height', 'thumb_mid_width', 'thumb_small_height', 'thumb_small_width',]);
$water = SystemConfigService::more([
'image_watermark_status',
'watermark_type',
'watermark_image',
'watermark_opacity',
'watermark_position',
'watermark_rotate',
'watermark_text',
'watermark_text_angle',
'watermark_text_color',
'watermark_text_size',
'watermark_x',
'watermark_y']);
$config = array_merge($config, ['thumb' => $thumb], ['water' => $water]);
//除了本地存储其他都去获取配置信息
if (1 !== $type) {
/** @var SystemStorageServices $make */
$make = app()->make(SystemStorageServices::class);
$res = $make->getConfig($type);
$config['uploadUrl'] = $res['domain'];
$config['storageName'] = $res['name'];
if ($type != 5) $config['storageRegion'] = $res['region'];
}
return self::$upload['upload_' . $type] = new Upload($type, $config);
}
/**
* 生辰缩略图水印实例化
* @param string $filePath
* @param bool $is_remote_down
* @return Upload
*/
public static function getOssInit(string $filePath, bool $is_remote_down = false)
{
//本地
$uploadUrl = sys_config('site_url');
if ($uploadUrl && strpos($filePath, $uploadUrl) !== false) {
$filePath = explode($uploadUrl, $filePath)[1] ?? '';
return self::init(1)->setFilepath($filePath);
}
$fileArr = parse_url($filePath);
$fileHost = ($fileArr['scheme'] ?? '') . '://' . ($fileArr['host'] ?? '');
/** @var SystemStorageServices $storageServices */
$storageServices = app()->make(SystemStorageServices::class);
$storageArr = $storageServices->cacheTag()->remember('storage_list', function () use ($storageServices) {
return $storageServices->getStorageList([], ['domain','type']);
});
foreach ($storageArr as $item) {
if ($fileHost == $item['domain']) {
return self::init($item['type'])->setFilepath($filePath);
}
}
//远程图片 下载到本地处理
if ($is_remote_down) {
try {
/** @var DownloadImageService $down */
$down = app()->make(DownloadImageService::class);
$data = $down->path('thumb_water')->downloadImage($filePath);
$filePath = $data['path'] ?? '';
} catch (\Throwable $e) {
//下载失败 传入原地址
}
}
return self::init(1)->setFilepath($filePath);
}
}

View File

@@ -0,0 +1,124 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\services;
use think\facade\Config;
use Endroid\QrCode\Color\Color;
use Endroid\QrCode\Encoding\Encoding;
use Endroid\QrCode\ErrorCorrectionLevel\ErrorCorrectionLevelLow;
use Endroid\QrCode\QrCode;
use Endroid\QrCode\Label\Label;
use Endroid\QrCode\Logo\Logo;
use Endroid\QrCode\RoundBlockSizeMode\RoundBlockSizeModeMargin;
use Endroid\QrCode\Writer\PngWriter;
/**
* Class UtilService
* @package crmeb\services
*/
class UtilService
{
/**
* 获取小程序二维码是否生成
* @param $url
* @return array
*/
public static function remoteImage($url)
{
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($curl);
$result = json_decode($result, true);
if (is_array($result)) return ['status' => false, 'msg' => $result['errcode'] . '---' . $result['errmsg']];
return ['status' => true];
}
/**
* 修改 https 和 http 移动到common
* @param $url $url 域名
* @param int $type 0 返回https 1 返回 http
* @return string
*/
public static function setHttpType($url, $type = 0)
{
$domainTop = substr($url, 0, 5);
if ($type) {
if ($domainTop == 'https') $url = 'http' . substr($url, 5, strlen($url));
} else {
if ($domainTop != 'https') $url = 'https:' . substr($url, 5, strlen($url));
}
return $url;
}
/**
* 获取二维码
* @param $url
* @param $name
* @return array|bool|string
*/
public static function getQRCodePath(string $url, string $name, string $savePath = 'wechat')
{
if (!strlen(trim($url)) || !strlen(trim($name))) return false;
try {
$uploadType = sys_config('upload_type');
// 没有选择默认使用本地上传
if (!$uploadType) $uploadType = 1;
$uploadType = (int)$uploadType;
$siteUrl = sys_config('site_url');
if (!$siteUrl) return '请前往后台设置->系统设置->网站域名 填写您的域名格式为:http://域名';
$info = [];
$outfiles = Config::get('qrcode.cache_dir') . '/' . $savePath;
$root_outfile = root_path('public/' . $outfiles);
if (!is_dir($root_outfile))
mkdir($root_outfile, 0777, true);
// Create QR code
$writer = new PngWriter();
$qrCode = QrCode::create($url)
->setEncoding(new Encoding('UTF-8'))
->setErrorCorrectionLevel(new ErrorCorrectionLevelLow())
->setSize(300)
->setMargin(10)
->setRoundBlockSizeMode(new RoundBlockSizeModeMargin())
->setForegroundColor(new Color(0, 0, 0))
->setBackgroundColor(new Color(255, 255, 255));
$writer->write($qrCode)->saveToFile($root_outfile . $name);
if ($uploadType === 1) {
$info["code"] = 200;
$info["name"] = $name;
$info["dir"] = '/' . $outfiles . '/' . $name;
$info["time"] = time();
$info['size'] = 0;
$info['type'] = 'image/png';
$info["image_type"] = 1;
$info['thumb_path'] = '/' . $outfiles . '/' . $name;
return $info;
} else {
$upload = UploadService::init($uploadType);
$content = file_get_contents($root_outfile . $name);
$res = $upload->to($outfiles)->validate()->stream($content, $name);
if ($res === false) {
return $upload->getError();
}
$info = $upload->getUploadInfo();
$info['image_type'] = $uploadType;
return $info;
}
} catch (\Exception $e) {
return $e->getMessage();
}
}
}

View File

@@ -0,0 +1,92 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\services;
use PullWord\PullWord;
/**
* 分词搜索类
* Class VicWordService
* @package crmeb\services
*/
class VicWordService
{
/**
* 请求地址
* @var string
*/
protected $url = 'https://sms.crmeb.net/api/v2/open/keyword';
// protected $url = 'http://test-api.crmeb.com/api/v2/open/keyword';
private static $instance = null;
public function __construct()
{
}
private function __clone()
{
}
public static function instance()
{
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
public function getWord($str)
{
try {
$res = HttpService::getRequest($this->url ,['keyword' => $str]);
$data = json_decode($res, true) ?: [];
$data = array_column($data['data'] ?? [], 0);
} catch (\Throwable $e) {
$data = [];
}
//没有获取分词时,加上原始的词
if (!count($data)) {
$data[] = $str;
}
if ($data) {
foreach ($data as $key => &$item) {
$item = trim($item);
if (!$item) unset($data[$key]);
}
}
return array_merge($data);
}
public function getWordV1($str)
{
try {
$pullWord = new PullWord($str);
$result = $pullWord->pull()->toJson()->get();
$result = json_decode($result, true);
$data = is_array($result) ? array_column($result, 't') : [];
} catch (\Throwable $e) {
$data = [];
}
//没有获取分词时,加上原始的词
if (!count($data)) {
$data[] = $str;
}
return $data;
}
}

39
crmeb/services/ai/Ai.php Normal file
View File

@@ -0,0 +1,39 @@
<?php
namespace crmeb\services\ai;
use crmeb\basic\BaseManager;
use crmeb\services\AccessTokenServeService;
use think\Container;
use think\facade\Config;
class Ai extends BaseManager
{
/**
* 空间名
* @var string
*/
protected string $namespace = '\\crmeb\\services\\ai\\storage\\';
protected function getDefaultDriver()
{
return Config::get('ai.default', 'ai');
}
protected function invokeClass($class)
{
if (!class_exists($class)) {
throw new \RuntimeException('class not exists: ' . $class);
}
$this->getConfigFile();
if (!$this->config) {
$this->config = Config::get($this->configFile . '.stores.' . $this->name, []);
}
$handleAccessToken = new AccessTokenServeService($this->config['access_key'] ?? '', $this->config['secret_key'] ?? '');
$handle = Container::getInstance()->invokeClass($class, [$this->name, $handleAccessToken, $this->configFile]);
$this->config = [];
return $handle;
}
}

View File

@@ -0,0 +1,38 @@
<?php
namespace crmeb\services\ai\storage;
use crmeb\basic\BaseAi;
class Ai extends BaseAi
{
const CONVERSATION = 'v2/chat/conversation';
const CHAT = 'v2/chat/chat';
protected function initialize(array $config = [])
{
parent::initialize($config);
}
public function chat(string $systemContent, string $userContent)
{
$param['messages'] = [
[
'role' => 'system',
'content' => $systemContent
],
[
'role' => 'user',
'content' => $userContent
]
];
$param['max_tokens'] = '4096';
$param['temperature'] = '1';
$param['frequency_penalty'] = '0';
$param['presence_penalty'] = '0';
$param['model'] = 'deepseek-chat';
$param['response_format'] = '{ "type": "json_object" }';
$result = $this->accessToken->httpRequest(self::CHAT, $param);
return str_replace(['```json', '```'], '', $result['data']['choices'][0]['message']['content']);
}
}

View File

@@ -0,0 +1,40 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\services\delivery;
use crmeb\basic\BaseManager;
use think\facade\Config;
/**
* Class Delivery
* @package crmeb\services\delivery
* @mixin \crmeb\services\delivery\storage\Dada
* @mixin \crmeb\services\delivery\storage\Uupt
*/
class Delivery extends BaseManager
{
/**
* 空间名
* @var string
*/
protected string $namespace = '\\crmeb\\services\\delivery\\storage\\';
/**
* 设置默认
* @return mixed
*/
protected function getDefaultDriver()
{
return Config::get('delivery.default', 'dada');
}
}

View File

@@ -0,0 +1,380 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------\
namespace crmeb\services\delivery\storage;
use crmeb\basic\BaseDelivery;
use think\exception\ValidateException;
class Dada extends BaseDelivery
{
const BASE_URL = 'https://newopen.imdada.cn';
const ADD_MERCHANT = '/merchantApi/merchant/add';
const ADD_SHOP = '/api/shop/add';
const UPDATE_SHOP = '/api/shop/update';
const GET_CITY_CODE = '/api/cityCode/list';
const GET_SHOP_DETAIL = '/api/shop/detail';
const GET_ORDER_PRICE = '/api/order/queryDeliverFee';
const ADD_ORDER_AFTER_QUERY = '/api/order/addAfterQuery';
const ADD_ORDER_STSATUS_QUERY = '/api/order/status/query';
const GET_REASONS = '/api/order/cancel/reasons';
const CANCEL_ORDER = '/api/order/formalCancel';
const GET_BALANCE = '/api/balance/query';
const GET_RECHARGE = '/api/recharge';
public $config;
protected array $status = [
1 => '待接单',
2 => '待取货',
3 => '配送中',
4 => '已完成',
5 => '已取消',
8 => '指派单',
9 => '妥投异常之物品返回中',
10 => '妥投异常之物品返回完成',
100 => '骑士到店',
1000 => '创建达达运单失败'
];
public function initialize(array $config)
{
$this->config = $config;
parent::initialize($config);
}
/**
* 创建商户
* @param $data
* @return mixed
*/
public function addMerchant($data)
{
return $this->sendRequest(self::ADD_MERCHANT, $data);
}
/**
* 创建门店
* @param $data
* @return mixed
*/
public function addShop($data)
{
$parmas[] = $data;
return $this->sendRequest(self::ADD_SHOP, $parmas);
}
/**
* 更新门店
* @param $data
* @return mixed
*/
public function updateShop($data)
{
$params['origin_shop_id'] = $data['origin_shop_id'];
if (isset($data['new_shop_id'])) $params['new_shop_id'] = $data['new_shop_id'];
if (isset($data['station_name'])) $params['station_name'] = $data['station_name'];
if (isset($data['business'])) $params['business'] = $data['business'];
if (isset($data['station_address'])) $params['station_address'] = $data['station_address'];
if (isset($data['lng'])) $params['lng'] = $data['lng'];
if (isset($data['lat'])) $params['lat'] = $data['lat'];
if (isset($data['contact_name'])) $params['contact_name'] = $data['contact_name'];
if (isset($data['phone'])) $params['phone'] = $data['phone'];
if (isset($data['status'])) $params['status'] = $data['status'];
return $this->sendRequest(self::UPDATE_SHOP, $params);
}
/**
* 预发布订单
* @param $data
* @return mixed
*/
public function addOrder($data)
{
$params = [
'deliveryNo' => $data['deliveryNo'],
];
return $this->sendRequest(self::ADD_ORDER_AFTER_QUERY, $params);
}
/**
* 计算订单价格
* @param $data
* @return mixed
*/
public function getOrderPrice($data)
{
$params = [
'shop_no' => $data['shop_no'],
'origin_id' => $data['origin_id'],
'city_code' => $data['city_code'],
'cargo_price' => $data['cargo_price'],
'is_prepay' => $data['is_prepay'],
'receiver_name' => $data['receiver_name'],
'receiver_address'=> $data['receiver_address'],
'callback' => $this->callback_url,
'cargo_weight' => $data['cargo_weight'],
'receiver_phone' => $data['receiver_phone'],
'is_finish_code_needed'=> $data['is_finish_code_needed'],
];
return $this->sendRequest(self::GET_ORDER_PRICE, $params);
}
/**
* 获取订单详情
* @param $data
* @return mixed
*/
public function getOrderDetail($data)
{
$params['order_id'] = $data['origin_id'];
$res = $this->sendRequest(self::ADD_ORDER_STSATUS_QUERY, $params);
if($res){
$res['status_name'] = $this->status[$res['statusCode']] ?? '';
$res['porter_name'] = $this->status[$res['transporterName']] ?? '';
$res['porter_phone'] = $this->status[$res['transporterPhone']] ?? '';
}
return $res;
}
/**
* 取消订单
* @param $data
* @return mixed
*/
public function cancelOrder($data)
{
$params['order_id'] = $data['origin_id'];
$params['cancel_reason'] = $data['cancel_reason'] ?? '无';
$params['cancel_reason_id'] = $data['reason'];
return $this->sendRequest(self::CANCEL_ORDER, $params);
}
/**
* 获取充值地址
* @param $data
* @return mixed
*/
public function getRecharge($data =[])
{
$params = [
'amount' => $data['amount'] ?? 100,
'category'=> $data['category'] ?? 'PC',
];
return $this->sendRequest(self::GET_RECHARGE, $params);
}
/**
* 获取余额
* @param $data
* @return mixed
*/
public function getBalance($data)
{
$params['category'] = $data['category'] ?? 3;
$res = $this->sendRequest(self::GET_BALANCE, $params);
return [
'deliverBalance' => $res['deliverBalance']
];
}
/**
* 支付小费
* @param $data
* @return mixed
*/
public function addTip($data)
{
return true;
}
/**
* 取消原因
* @param $data
* @return mixed
*/
public function reasons($data = '')
{
$options = $this->sendRequest(self::GET_REASONS, $data);
foreach ($options as $option) {
$value = $option['id'];
$label = $option['reason'];
$res[] = compact('value','label');
}
return $res;
}
/**
* 获取城市信息
* @param $data
* @return mixed
*/
public function getCity($data = '')
{
$res = $this->sendRequest(self::GET_CITY_CODE, $data);
foreach ($res as $item) {
$data[] = [
'key' => $item['cityName'],
'label' => $item['cityName'],
];
}
return $data;
}
/**
* 获取门店信息
* @param $data
* @return mixed
*/
public function getShopDetail($id)
{
$data = ['origin_shop_id' => $id];
return $this->sendRequest(self::GET_SHOP_DETAIL, $data);
}
public function getBusiness()
{
return [
['key' => 1 , 'label' => '食品小吃'],
['key' => 2 , 'label' => '饮料'],
['key' => 3 , 'label' => '鲜花绿植'],
['key' => 5 , 'label' => '其他'],
['key' => 8 , 'label' => '文印票务'],
['key' => 9 , 'label' => '便利店'],
['key' => 13 , 'label' => '水果生鲜'],
['key' => 19 , 'label' => '同城电商'],
['key' => 20 , 'label' => '医药'],
['key' => 21 , 'label' => '蛋糕'],
['key' => 24 , 'label' => '酒品'],
['key' => 25 , 'label' => '小商品市场'],
['key' => 26 , 'label' => '服装'],
['key' => 27 , 'label' => '汽修零配'],
['key' => 28 , 'label' => '数码家电'],
['key' => 29 , 'label' => '小龙虾/烧烤'],
['key' => 31 , 'label' => '超市'],
['key' => 51 , 'label' => '火锅'],
['key' => 53 , 'label' => '个护美妆'],
['key' => 55 , 'label' => '母婴'],
['key' => 57 , 'label' => '家居家纺'],
['key' => 59 , 'label' => '手机'],
['key' => 61 , 'label' => '家装'],
['key' => 63 , 'label' => '成人用品'],
];
}
public function sendRequest($api, $params)
{
$url = self::BASE_URL . $api;
$params = $this->bulidRequestParams($params);
$response = $this->httpRequestWithPost($url, $params);
$data = $this->getMessage($response);
return $data;
}
/**
* 构造请求数据
* data:业务参数,json字符串
*/
public function bulidRequestParams($params)
{
$requestParams = array();
$requestParams['app_key'] = $this->config['app_key'];
$requestParams['body'] = json_encode($params);
$requestParams['format'] = 'json';
$requestParams['v'] = '1.0';
$requestParams['source_id'] = $this->config['source_id'];
$requestParams['timestamp'] = time();
$requestParams['signature'] = $this->_sign($requestParams);
return json_encode($requestParams);
}
/**
* 签名生成signature
*/
public function _sign($data)
{
//1.升序排序
ksort($data);
//2.字符串拼接
$args = "";
foreach ($data as $key => $value) {
$args .= $key . $value;
}
$args = $this->config['app_secret'] . $args . $this->config['app_secret'];
//3.MD5签名,转为大写
$sign = strtoupper(md5($args));
return $sign;
}
/**
* 发送请求,POST
* @param $url 指定URL完整路径地址
* @param $data 请求的数据
*/
public function httpRequestWithPost($url, $data, $headers = [])
{
$headers = array(
'Content-Type: application/json',
);
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_HEADER, false);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
curl_setopt($curl, CURLOPT_TIMEOUT, 3);
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
$resp = curl_exec($curl);
$info = curl_getinfo($curl);
curl_close($curl);
if (isset($info['http_code']) && $info['http_code'] == 200) {
return $resp;
}
return ;
}
protected function getMessage($json, $message = '未知错误!')
{
$data = json_decode($json, true);
//code=2551 订单创建中
if (!in_array($data['code'], [0, 2551])) {
isset($data['msg']) && $message = $data['msg'];
if ($data['errorCode'] == 7718) {
foreach ($data['result']['failedList'] as $datum) {
$message .= ':'.$datum['shopName'].'/'. $datum['msg'].';';
}
}
throw new ValidateException('【达达错误提示】:'.$message);
} else {
if ($data['status'] == 'success') return $data['result'] ?? $data;
return $data;
}
}
}

Some files were not shown because too many files have changed in this diff Show More