Initial commit: queue workspace

Made-with: Cursor
This commit is contained in:
apple
2026-03-21 02:55:24 +08:00
commit 78de918c37
12388 changed files with 1840126 additions and 0 deletions

View File

@@ -0,0 +1,47 @@
<?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\traits;
/**
*
* Class BaseError
* @package crmeb\basic
*/
trait ErrorTrait
{
/**
* 错误信息
* @var mixed
*/
protected mixed $error = '';
/**
* 设置错误信息
* @param string|null $error
* @return bool
*/
protected function setError(?string $error = null): bool
{
$this->error = $error ?: '未知错误';
return false;
}
/**
* 获取错误信息
* @return string
*/
public function getError(): string
{
$error = $this->error;
$this->error = null;
return $error;
}
}

View File

@@ -0,0 +1,69 @@
<?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\traits;
use Firebase\JWT\BeforeValidException;
use Firebase\JWT\ExpiredException;
use Firebase\JWT\JWT;
use Firebase\JWT\SignatureInvalidException;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\facade\Env;
use UnexpectedValueException;
trait JwtAuthModelTrait
{
/**
* @param string $type
* @param array $params
* @return array
*/
public function getToken(string $type, array $params = []): array
{
$id = $this->{$this->getPk()};
$host = app()->request->host();
$time = time();
$params += [
'iss' => $host,
'aud' => $host,
'iat' => $time,
'nbf' => $time,
'exp' => strtotime('+ 3hour'),
];
$params['jti'] = compact('id', 'type');
$token = JWT::encode($params, env('APP_APP_KEY', 'default'), 'HS256');
return compact('token', 'params');
}
/**
* @param string $jwt
* @return array
*
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public static function parseToken(string $jwt): array
{
JWT::$leeway = 60;
$headers = array('HS256');
$data = JWT::decode($jwt, Env::get('app.app_key', 'default'), $headers);
$model = new self();
return [$model->where($model->getPk(), $data->jti->id)->find(), $data->jti->type];
}
}

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\traits;
use app\Request;
/**
* Trait MacroTrait
* @package crmeb\traits
* @property Request $request
*/
trait MacroTrait
{
/**
* 获取request内的值
* @param string $name
* @param null $default
* @return null
*/
public function getMacro(string $name, $default = null)
{
return $this->request->hasMacro($name) ? $this->request->{$name}() : $default;
}
}

View File

@@ -0,0 +1,91 @@
<?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\traits;
use crmeb\exceptions\BadMethodCallException;
/**
* Trait Macroable
* @package crmeb\traits
*/
trait Macroable
{
protected static array $macros = [];
/**
* Register a custom macro.
*
* @param string $name
* @param callable|object $macro
*/
public static function macro(string $name, callable|object $macro)
{
static::$macros[$name] = $macro;
}
/**
* Mix another object into the class.
*
* @param object $mixin
* @throws \ReflectionException
*/
public static function mixin($mixin)
{
$methods = (new \ReflectionClass($mixin))->getMethods(
\ReflectionMethod::IS_PUBLIC | \ReflectionMethod::IS_PROTECTED
);
foreach ($methods as $method) {
$method->setAccessible(true);
static::macro($method->name, $method->invoke($mixin));
}
}
public static function hasMacro(string $name): bool
{
return isset(static::$macros[$name]);
}
public static function __callStatic($method, $parameters)
{
if (!static::hasMacro($method)) {
throw new BadMethodCallException("Method {$method} does not exist.");
}
$macro = static::$macros[$method];
if ($macro instanceof \Closure) {
return call_user_func_array(\Closure::bind($macro, null, static::class), $parameters);
}
return call_user_func_array($macro, $parameters);
}
public function __call($method, $parameters)
{
if (!static::hasMacro($method)) {
throw new BadMethodCallException("Method {$method} does not exist.");
}
$macro = static::$macros[$method];
if ($macro instanceof \Closure) {
return call_user_func_array($macro->bindTo($this, static::class), $parameters);
}
return call_user_func_array($macro, $parameters);
}
}

View File

@@ -0,0 +1,129 @@
<?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\traits;
use think\Model;
/**
* Trait ModelTrait
* @package crmeb\traits
*/
trait ModelTrait
{
/**
* 时间段搜索器
* @param Model $query
* @param $value
*/
public function searchTimeAttr($query, $value, $data)
{
if ($value) {
$timeKey = $data['timeKey'] ?? (property_exists($this, 'timeKey') && $this->timeKey ? $this->timeKey : 'add_time');
if (is_array($value)) {
$startTime = $value[0] ?? 0;
$endTime = $value[1] ?? 0;
if ($startTime || $endTime) {
try {
date('Y-m-d', $startTime);
} catch (\Throwable) {
$startTime = strtotime($startTime);
}
try {
date('Y-m-d', $endTime);
} catch (\Throwable) {
$endTime = strtotime($endTime);
}
if ($startTime == $endTime || $endTime == strtotime(date('Y-m-d', $endTime))) {
$endTime = $endTime + 86400;
}
$query->whereBetween($timeKey, [$startTime, $endTime]);
}
} elseif (is_string($value)) {
switch ($value) {
case 'today':
case 'week':
case 'month':
case 'year':
case 'yesterday':
case 'last year':
case 'last week':
case 'last month':
$query->whereTime($timeKey, $value);
break;
case 'quarter':
[$startTime, $endTime] = $this->getMonth();
$query->whereBetween($timeKey, [strtotime($startTime), strtotime($endTime)]);
break;
case 'lately7':
$query->whereBetween($timeKey, [strtotime("-7 day"), time()]);
break;
case 'lately30':
$query->whereBetween($timeKey, [strtotime("-30 day"), time()]);
break;
default:
if (strstr($value, '-') !== false) {
[$startTime, $endTime] = explode('-', $value);
$startTime = trim($startTime) ? strtotime($startTime) : 0;
$endTime = trim($endTime) ? strtotime($endTime) : 0;
if ($startTime && $endTime) {
if ($startTime == $endTime || $endTime == strtotime(date('Y-m-d', $endTime))) {
$endTime = $endTime + 86400;
}
$query->whereBetween($timeKey, [$startTime, $endTime]);
} else if (!$startTime && $endTime) {
$query->whereTime($timeKey, '<', $endTime + 86400);
} else if ($startTime && !$endTime) {
$query->whereTime($timeKey, '>=', $startTime);
}
}
break;
}
}
}
}
/**
* 获取本季度 time
* @param int $ceil
* @return array
*/
public function getMonth(int $ceil = 0)
{
if ($ceil != 0) {
$season = ceil(date('n') / 3) - $ceil;
} else {
$season = ceil(date('n') / 3);
}
$firstday = date('Y-m-01', mktime(0, 0, 0, ($season - 1) * 3 + 1, 1, date('Y')));
$lastday = date('Y-m-t', mktime(0, 0, 0, $season * 3, 1, date('Y')));
return [$firstday, $lastday];
}
/**
* 获取某个字段内的值
* @param $value
* @param string $filed
* @param string $valueKey
* @param array|string[] $where
* @return mixed
*/
public function getFieldValue($value, string $filed, ?string $valueKey = '', ?array $where = [])
{
$model = $this->where($filed, $value);
if ($where) {
$model->where(...$where);
}
return $model->value($valueKey ?: $filed);
}
}

View File

@@ -0,0 +1,53 @@
<?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\traits;
/**
* 设置参数
* Trait OptionTrait
* @package crmeb\traits
*/
trait OptionTrait
{
protected array $item = [];
/**
* @param string $key
* @param $default
* @return mixed
*/
public function getItem(string $key, $default = null)
{
return $this->item[$key] ?? $default;
}
/**
* @param string $key
* @param $value
* @return $this
*/
public function setItem(string $key, $value): static
{
$this->item[$key] = $value;
return $this;
}
/**
* 重置
*/
public function reset()
{
$this->item = [];
}
}

View File

@@ -0,0 +1,145 @@
<?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\traits;
use think\facade\Queue;
/**
* 快捷加入消息队列
* Trait QueueTrait
* @package crmeb\traits
*/
trait QueueTrait
{
/**
* 错误次数
* @var int
*/
protected static int $errorCount = 3;
/**
* @var string
*/
protected static string $defaultDo = 'doJob';
/**
* 列名
* @return string
*/
protected static function queueName()
{
return null;
}
/**
* 加入队列
* @param $action
* @param array $data
* @param string|null $queueName
* @return mixed
*/
public static function dispatch($action = null, array $data = [], string $queueName = null)
{
$do = '';
if (is_array($action)) {
$data = $action;
} else if (is_string($action)) {
$do = $action;
}
if (self::queueName()) {
$queueName = self::queueName();
}
if (!$do) {
$do = self::$defaultDo;
}
return self::queuePush($do, $data, null, $queueName);
}
/**
* 延迟加入消息队列
* @param int $secs
* @param $action
* @param array $data
* @param string|null $queueName
* @return mixed
*/
public static function dispatchSece(int $secs, $action = null, array $data = [], string $queueName = null)
{
$do = '';
if (is_array($action)) {
$data = $action;
} else if (is_string($action)) {
$do = $action;
}
if (self::queueName()) {
$queueName = self::queueName();
}
if (!$do) {
$do = self::$defaultDo;
}
return self::queuePush($do, $data, $secs, $queueName);
}
/**
* 加入小队列
* @param string $do
* @param array $data
* @param int|null $secs
* @param string|null $queueName
* @return mixed
*/
public static function dispatchDo(string $do, array $data = [], int $secs = null, string $queueName = null)
{
if (self::queueName()) {
$queueName = self::queueName();
}
return self::queuePush($do, $data, $secs, $queueName);
}
/**
* 放入消息队列
* @param string $do
* @param array $data
* @param int|null $secs
* @param string|null $queueName
* @return mixed|null
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/28
*/
protected static function queuePush(string $do, array $data = [], int $secs = null, string $queueName = null)
{
$job = __CLASS__ . '@fire';
$jobData = [
'data' => $data,
'do' => $do,
'errorCount' => self::$errorCount,
];
if ($secs) {
$res = Queue::later($secs, $job, $jobData, $queueName);
} else {
$res = Queue::push($job, $jobData, $queueName);
}
return $res;
}
}

View File

@@ -0,0 +1,94 @@
<?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\traits;
use app\dao\BaseDao;
use crmeb\basic\BaseAuth;
use crmeb\basic\BaseModel;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
/**
* Trait SearchDaoTrait
* @package crmeb\traits
* @mixin BaseDao
*/
trait SearchDaoTrait
{
/**
* 搜索没有进入搜索器的自动进入where条件
* @param array $where
* @param bool $authWhere
* @return BaseModel
*/
public function searchWhere(array $where, bool $authWhere = true)
{
[$with, $whereKey] = app()->make(BaseAuth::class)->________(array_keys($where), $this->setModel());
$whereData = [];
foreach ($whereKey as $key) {
if (isset($where[$key]) && 'timeKey' !== $key) {
$whereData[$key] = $where[$key];
}
}
return $this->getModel()->withSearch($with, $where)->when($authWhere && $whereData, function ($query) use ($whereData) {
$query->where($whereData);
});
}
/**
* @param array $where
* @param bool $authWhere
* @return int
* @throws DbException
*/
public function count(array $where = [], bool $authWhere = true): int
{
return $this->searchWhere($where, $authWhere)->count();
}
/**
* 搜索
* @param array $where
* @param array|string[] $field
* @param int $page
* @param int $limit
* @param null $sort
* @param array $with
* @return array
* @throws DbException
* @throws DataNotFoundException
* @throws ModelNotFoundException
*/
public function getDataList(array $where, array $field = ['*'], int $page = 0, int $limit = 0, $sort = null, array $with = [])
{
return $this->searchWhere($where)->when($page && $limit, function ($query) use ($page, $limit) {
$query->page($page, $limit);
})->when(!$page && $limit, function ($query) use ($limit) {
$query->limit($limit);
})->when($sort, function ($query, $sort) {
if (is_array($sort)) {
foreach ($sort as $k => $v) {
if (is_numeric($k)) {
$query->order($v, 'desc');
} else {
$query->order($k, $v);
}
}
} else {
$query->order($sort, 'desc');
}
})->field($field)->with($with)->select()->toArray();
}
}

View File

@@ -0,0 +1,42 @@
<?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\traits;
use crmeb\basic\BaseModel;
use think\Model;
/**
* Trait ServicesTrait
* @package crmeb\traits
* @method array|Model|null get($id, ?array $field = [], ?array $with = []) 获取一条数据
* @method array|Model|null getOne(array $where, ?string $field = '*', ?array $with = []) 获取一条数据(不走搜素器)
* @method string|null batchUpdate(array $ids, array $data, ?string $key = null) 批量修改
* @method float sum(array $where, string $field, bool $search = false) 求和
* @method mixed update($id, array $data, ?string $field = null) 修改数据
* @method bool be($map, string $field = '') 查询一条数据是否存在
* @method mixed value(array $where, string $field) 获取指定条件下的数据
* @method int count(array $where = [], string $filed = '*') 读取数据条数
* @method int getCount(array $where = []) 获取某些条件总数(不走搜素器)
* @method array getColumn(array $where, string $field, string $key = '') 获取某个字段数组(不走搜素器)
* @method mixed delete($id, ?string $key = null) 删除
* @method BaseModel|Model save(array $data) 保存数据
* @method mixed saveAll(array $data) 批量保存数据
* @method bool bcInc($key, string $incField, string $inc, string $keyField = null, int $acc = 2) 高精度加法
* @method bool bcDec($key, string $decField, string $dec, string $keyField = null, int $acc = 2, bool $dec_return_false = true) 高精度 减法
* @method mixed decStockIncSales(array $where, int $num, string $stock = 'stock', string $sales = 'sales') 减库存加销量
* @method mixed incStockDecSales(array $where, int $num, string $stock = 'stock', string $sales = 'sales') 加库存减销量
* @method mixed incUpdate($where, string $field, int $number = 1) 自增单个数据
* @method mixed decUpdate($where, string $field, int $number = 1) 自减单个数据
*/
trait ServicesTrait
{
}

View File

@@ -0,0 +1,521 @@
<?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\traits\dao;
use crmeb\services\CacheService;
use crmeb\utils\Tag;
use think\cache\TagSet;
use think\Container;
use think\facade\Log;
use think\Model;
/**
* Trait CacheDaoTrait
* @package crmeb\traits\dao
* @method Model getModel()
* @method Model getPk()
*/
trait CacheDaoTrait
{
/**
* 获取redis
* @return \Redis
* @author 等风来
* @email 136327134@qq.com
* @date 2022/10/29
*/
private function getRedisConnect()
{
return CacheService::redisHandler()->handler();
}
/**
* 获取缓存
* @return TagSet|\think\facade\Cache
* @author 等风来
* @email 136327134@qq.com
* @date 2022/11/10
*/
private function getCacheHander()
{
return CacheService::redisHandler();
}
/**
* 对外开放方法
* @return TagSet|\think\facade\Cache
* @author 等风来
* @email 136327134@qq.com
* @date 2022/11/10
*/
public function cacheHander()
{
return $this->getCacheHander();
}
/**
* 缓存标签
* @param null $tag
* @return Tag
* @author 等风来
* @email 136327134@qq.com
* @date 2022/11/10
*/
public function cacheTag($tag = null)
{
$key = $this->cacheKey() . 'tag';
$tag = $tag ? $key . ':' . $tag : $key;
$redis = CacheService::redisHandler($tag);
return new Tag($redis, $tag);
}
/**
* 总缓存数据量
* @return mixed
*/
public function cacheCount()
{
$cacheKey = $this->cacheKey();
$rds = $this->getRedisConnect();
return $rds->hLen($cacheKey . 'map');
}
/**
* 读取缓存全部数据
* @return mixed
*/
public function cacheList(string $key = '')
{
$cacheKey = $this->cacheKey() . $key;
$rds = $this->getRedisConnect();
$map = $rds->hGetAll($cacheKey . 'map');
//key排序
ksort($map);
$list = array_values($map) ?: [];
foreach ($list as $key => $item) {
$list[$key] = $this->unserialize($item);
}
return $list;
}
/**
* 读取缓存分页数据
* @param int $page
* @param int $limit
* @param string $key
* @return array
*/
public function cachePageData(int $page = 1, int $limit = 10, string $key = '')
{
$cacheKey = $this->cacheKey() . $key;
$rds = $this->getRedisConnect();
$page = max($page, 1);
$limit = max($limit, 1);
//先读排序
$pageList = $rds->zRangeByScore($cacheKey . 'page', ($page - 1) * $limit, ($page * $limit) - 1);
//再读数据
$list = $rds->hMGet($cacheKey . 'map', $pageList) ?: [];
if (is_array($list)) {
$newList = [];
foreach ($list as $value) {
$newList[] = $this->unserialize($value);
}
$list = $newList;
}
$count = $rds->hLen($cacheKey . 'map');
return compact('list', 'count');
}
/**
* 单个查询数据
* @param int|string $id
* @return false|string|array
*/
public function cacheInfoById($id)
{
$cacheKey = $this->cacheKey();
$rds = $this->getRedisConnect();
$value = $rds->hGet($cacheKey . 'map', $id);
return $value === null ? null : $this->unserialize($value);
}
/**
* 批量查询数据
* @param $ids
* @return mixed
*/
public function cacheInfoByIds(array $ids)
{
$cacheKey = $this->cacheKey();
$rds = $this->getRedisConnect();
$arr = $rds->hMGet($cacheKey . 'map', $ids);
if (is_array($arr)) {
$newList = [];
foreach ($arr as $key => $value) {
$arr[$key] = $this->unserialize($value);
}
$arr = $newList;
}
return $arr;
}
/**
* 更新单个缓存
* @param $info
* @return false|mixed
*/
public function cacheUpdate(array $info, $key = null)
{
$pk = $this->getPk();
if ((empty($info) || !isset($info[$pk])) && !$key) {
return false;
}
$cacheKey = $this->cacheKey();
$rds = $this->getRedisConnect();
$key = $key ?: $info[$pk];
return $rds->hSet($cacheKey . 'map', $key, $this->serialize($info));
}
/**
* 序列化数据
* @param $value
* @return string
* @author 等风来
* @email 136327134@qq.com
* @date 2022/11/10
*/
private function serialize($value)
{
try {
return serialize($value);
} catch (\Throwable $e) {
Log::error('序列化发生错误:' . $e->getMessage());
return $value;
}
}
/**
* 反序列化数据
* @param $value
* @return mixed
* @author 等风来
* @email 136327134@qq.com
* @date 2022/11/10
*/
private function unserialize($value)
{
try {
return unserialize($value);
} catch (\Throwable $e) {
Log::error('反序列化发生错误:' . $e->getMessage());
return $value;
}
}
/**
* @param int $id
* @param $field
* @param null $value
* @return false|mixed
* @author 等风来
* @email 136327134@qq.com
* @date 2022/11/1
*/
public function cacheSaveValue(int $id, $field, $value = null)
{
$pk = $this->getPk();
$info = $this->cacheInfoById($id);
if (!$info) {
$newInfo = $this->get($id);
$info = $newInfo ? $newInfo->toArray() : [];
}
if (is_array($field)) {
foreach ($field as $k => $v) {
$info[$k] = $v;
}
} else {
$info[$field] = $value;
}
$info[$pk] = $id;
return $this->cacheUpdate($info);
}
/**
* 不存在则写入,存在则返回
* @param $key
* @param callable|null $fn
* @param null $default
* @return array|false|mixed|string|null
* @author 等风来
* @email 136327134@qq.com
* @date 2022/11/1
*/
public function cacheRemember($key, callable $fn = null, $default = null)
{
//不开启数据缓存直接返回
if (!app()->config->get('cache.is_data')) {
if ($fn instanceof \Closure) {
return Container::getInstance()->invokeFunction($fn);
} else {
return $default;
}
}
$info = $this->cacheInfoById($key);
if ((null === $info || false === $info) && is_callable($fn)) {
//读取数据库缓存
$newInfo = $fn();
if (null !== $newInfo) {
//缓存数据存在则更新
$this->cacheUpdate($newInfo, $key);
}
$info = $newInfo;
}
return null !== $info ? $info : $default;
}
/**
* 批量更新缓存
* @param $list
* @return false|mixed
*/
public function cacheUpdateList(array $list, string $key = '')
{
if (empty($list)) {
return false;
}
$cacheKey = $this->cacheKey() . $key;
$pk = $this->getPk();
$rds = $this->getRedisConnect();
$map = [];
foreach ($list as $item) {
if (empty($item) || !isset($item[$pk])) {
continue;
}
$map[$item[$pk]] = $this->serialize($item);
}
return $rds->hMSet($cacheKey . 'map', $map);
}
/**
* 删除单条缓存
* @param $id
*/
public function cacheDelById(int $id)
{
$cacheKey = $this->cacheKey();
$rds = $this->getRedisConnect();
$rds->hDel($cacheKey . 'map', $id);
$rds->zRem($cacheKey . 'page', $id);
}
/**
* 批量删除缓存
* @param $ids
*/
public function cacheDelByIds(array $ids)
{
$cacheKey = $this->cacheKey();
$rds = $this->getRedisConnect();
foreach ($ids as $id) {
$rds->hDel($cacheKey . 'map', $id);
$rds->zRem($cacheKey . 'page', $id);
}
}
/**
* 创建缓存
* @param array $list
* @author 等风来
* @email 136327134@qq.com
* @date 2022/10/29
*/
public function cacheCreate(array $list, string $key = '')
{
$pk = $this->getPk();
$cacheKey = $this->cacheKey() . $key;
$rds = $this->getRedisConnect();
//启动事务
$rds->multi();
//删除旧数据
$rds->del($cacheKey . 'map');
$rds->del($cacheKey . 'page');
//组合数据
$map = [];
foreach ($list as $i => $item) {
$map[$item[$pk]] = $item;
//存zset 排序
$rds->zAdd($cacheKey . 'page', $i, $item[$pk]);
}
foreach ($map as $k => &$item) {
$item = $this->serialize($item);
}
//存hmset 数据
$rds->hMSet($cacheKey . 'map', $map);
//执行事务
$rds->exec();
}
protected function cacheKey()
{
return 'mc:' . $this->getModel()->getName() . ':';
}
/**
*
* @param $key
* @return string
* @author 等风来
* @email 136327134@qq.com
* @date 2022/11/10
*/
public function getCacheKey($key)
{
return $this->cacheKey() . $key;
}
/**
* 更新缓存
* @param string $key
* @param $value
* @return bool
* @author 等风来
* @email 136327134@qq.com
* @date 2022/11/1
*/
public function cacheStrUpdate(string $key, $value, int $expire = null)
{
return $this->getCacheHander()->set($this->cacheKey() . 'str:' . $key, $value, $expire);
}
/**
* 获取缓存
* @param string $key
* @return false|mixed|string
* @author 等风来
* @email 136327134@qq.com
* @date 2022/11/1
*/
public function cacheStrGet(string $key)
{
return $this->getCacheHander()->get($this->cacheKey() . 'str:' . $key);
}
/**
* 获取表缓存是否有数据
* @return false|mixed|string
* @author 等风来
* @email 136327134@qq.com
* @date 2022/11/1
*/
public function cacheStrTable()
{
return $this->getRedisConnect()->get($this->cacheKey());
}
/**
* 设置表缓存是否有数据
* @param int $value
* @return bool
* @author 等风来
* @email 136327134@qq.com
* @date 2022/11/1
*/
public function cacheStrSetTable(int $value = 1)
{
return $this->getRedisConnect()->set($this->cacheKey(), $value);
}
/**
* 删除缓存
* @param string $key
* @return int
* @author 等风来
* @email 136327134@qq.com
* @date 2022/11/1
*/
public function cacheStrDel(string $key)
{
return $this->getCacheHander()->delete($this->cacheKey() . $this->tagStr . $key);
}
/**
* 获取缓存,没有则写入缓存并返回
* @param string $key
* @param callable|null $fn
* @param null $default
* @return false|mixed|string|null
* @author 等风来
* @email 136327134@qq.com
* @date 2022/11/1
*/
public function cacheStrRemember(string $key, callable $fn = null, int $expire = null, $default = null)
{
//不开启数据缓存直接返回
if (!app()->config->get('cache.is_data')) {
if ($fn instanceof \Closure) {
return Container::getInstance()->invokeFunction($fn);
} else {
return $default;
}
}
$value = $this->cacheStrGet($key);
if ((null === $value || false === $value) && is_callable($fn)) {
$newValue = $fn();
if (null !== $newValue) {
$this->cacheStrUpdate($key, $value, $expire);
}
$value = $newValue;
}
return null !== $value ? $value : $default;
}
}

View File

@@ -0,0 +1,206 @@
<?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\traits\service;
use app\dao\BaseDao;
use app\services\work\WorkMediaServices;
use crmeb\services\wechat\ErrorMessage;
use crmeb\services\wechat\WechatResponse;
use crmeb\services\wechat\Work;
use EasyWeChat\Kernel\Exceptions\InvalidConfigException;
use GuzzleHttp\Exception\GuzzleException;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\exception\ValidateException;
/**
* 客户联系
* Trait ContactWayQrCode
* @package crmeb\traits\service
* @property BaseDao $dao
*/
trait ContactWayQrCode
{
/**
* 检测欢迎语字段
* @param array $welcomeWords
* @param int $type
*/
public function checkWelcome(array $welcomeWords, int $type)
{
if (1 === $type) {
return;
}
if (empty($welcomeWords['text']['content']) && empty($welcomeWords['attachments'])) {
throw new ValidateException('请填写欢迎语');
}
if (!empty($welcomeWords['text']['content']) && strlen($welcomeWords['text']['content']) > 3000) {
throw new ValidateException('内容不能超过4000字');
}
foreach ($welcomeWords['attachments'] as $item) {
switch ($item['msgtype']) {
case 'image':
if (empty($item['image']['pic_url'])) {
throw new ValidateException('请上传欢迎语图片');
}
break;
case 'link':
if (empty($item['link']['title'])) {
throw new ValidateException('请填写连接标题');
}
if (empty($item['link']['url'])) {
throw new ValidateException('请填写连接地址');
}
break;
case 'miniprogram':
if (empty($item['miniprogram']['title'])) {
throw new ValidateException('请填写小程序消息标题');
}
if (empty($item['miniprogram']['appid'])) {
throw new ValidateException('请填写小程序Appid');
}
if (empty($item['miniprogram']['page'])) {
throw new ValidateException('请填写小程序页面路径');
}
if (empty($item['miniprogram']['pic_url'])) {
throw new ValidateException('请选择小程序消息封面图');
}
break;
case 'video':
if (empty($item['video']['url'])) {
throw new ValidateException('请上传视频文件');
}
break;
case 'file':
if (empty($item['file']['url'])) {
throw new ValidateException('请上传文件');
}
break;
}
}
}
/**
* 执行创建或者修改【联系我】成员情况
* @param int $channleId
* @param array $userIds
* @param bool $skipVerify
* @param string|null $wxConfigId
* @throws TransportExceptionInterface
*/
public function handleQrCode(int $channleId, array $userIds, bool $skipVerify = true, string $wxConfigId = null)
{
if (!$wxConfigId) {
$qrCodeRes = Work::createQrCode($channleId, $userIds, $skipVerify);
} else {
$qrCodeRes = Work::updateQrCode($channleId, $userIds, $wxConfigId, $skipVerify);
}
if ($qrCodeRes['errcode'] !== 0) {
throw new ValidateException(ErrorMessage::getWorkMessage($qrCodeRes['errcode'], $qrCodeRes['errmsg'] ?? '生成企业渠道码失败'));
}
if (!$wxConfigId) {
$this->dao->update($channleId, [
'qrcode_url' => $qrCodeRes['qr_code'],
'config_id' => $qrCodeRes['config_id']
]);
}
}
/**
* 创建企业微信群发
* @param array $externalUserid
* @param array $attachments
* @param string $chatType
* @param string|null $sender
* @return WechatResponse
* @throws TransportExceptionInterface
* @throws InvalidConfigException
* @throws GuzzleException
* @throws ClientExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ServerExceptionInterface
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function sendMsgTemplate(array $externalUserid, array $attachments, string $chatType = 'single', string $sender = null)
{
$msg = [
'chat_type' => $chatType,
'external_userid' => $externalUserid,
];
if ('group' == $chatType) {
if (!$sender) {
throw new ValidateException('群发消息成员userid为必须填写');
}
}
if ($sender) {
$msg['sender'] = $sender;
}
if (empty($msg['external_userid'])) {
unset($msg['external_userid']);
}
//转换欢迎语当中的图片为素材库中
/** @var WorkMediaServices $mediaService */
$mediaService = app()->make(WorkMediaServices::class);
$attachments = $mediaService->resolvingWelcome($attachments);
$msg = array_merge($msg, $attachments);
return Work::addMsgTemplate($msg);
}
/**
* 创建发送朋友圈
* @param array $attachments
* @param array $userIds
* @param array $tag
* @return WechatResponse
* @throws ClientExceptionInterface
* @throws DataNotFoundException
* @throws DbException
* @throws GuzzleException
* @throws InvalidConfigException
* @throws ModelNotFoundException
* @throws RedirectionExceptionInterface
* @throws ServerExceptionInterface
* @throws TransportExceptionInterface
*/
public function addMomentTask(array $attachments, array $userIds = [], array $tag = [])
{
//转换欢迎语当中的图片为素材库中
/** @var WorkMediaServices $mediaService */
$mediaService = app()->make(WorkMediaServices::class);
$data = $mediaService->resolvingWelcome($attachments, 1);
if ($userIds) {
$data['visible_range']['sender_list']['user_list'] = $userIds;
}
if ($tag) {
$data['visible_range']['external_contact_list']['tag_list'] = $tag;
}
return Work::addMomentTask($data);
}
}