【程序目录】更新优惠券可以领取多张,可以设置多个分类,增加飞鹅云小票打印,优化定时任务

This commit is contained in:
吴昊天 2023-01-03 11:46:20 +08:00
parent 10e6a21b35
commit bc6134c6ad
40 changed files with 1482 additions and 188 deletions

View File

@ -67,10 +67,11 @@ class StoreCouponIssue extends AuthController
['is_permanent', 0],
['total_count', 0],
['product_id', ''],
['category_id', 0],
['category_id', []],
['type', 0],
['sort', 0],
['status', 0],
['receive_limit', 1],
]);
$res = $this->services->saveCoupon($data);
if ($res) return app('json')->success(100000);
@ -110,6 +111,12 @@ class StoreCouponIssue extends AuthController
];
}
}
if ($info['category_id'] != '') {
$info['category_id'] = explode(',', $info['category_id']);
foreach ($info['category_id'] as &$category_id) {
$category_id = (int)$category_id;
}
}
return app('json')->success($info);
}

View File

@ -479,9 +479,15 @@ class StoreOrder extends AuthController
$orderInfo = $this->services->tidyOrder($orderInfo->toArray(), true, true);
//核算优惠金额
$vipTruePrice = array_column($orderInfo['cartInfo'], 'vip_sum_truePrice');
$vipTruePrice = round(array_sum($vipTruePrice), 2);
$orderInfo['vip_true_price'] = $vipTruePrice ?: 0;
$vipTruePrice = $levelPrice = $memberPrice = 0;
foreach ($orderInfo['cartInfo'] as $cart) {
$vipTruePrice = bcadd((string)$vipTruePrice, (string)$cart['vip_sum_truePrice'], 2);
if ($cart['price_type'] == 'member') $memberPrice = bcadd((string)$memberPrice, (string)$cart['vip_sum_truePrice'], 2);
if ($cart['price_type'] == 'level') $levelPrice = bcadd((string)$levelPrice, (string)$cart['vip_sum_truePrice'], 2);
}
$orderInfo['vip_true_price'] = $vipTruePrice;
$orderInfo['levelPrice'] = $levelPrice;
$orderInfo['memberPrice'] = $memberPrice;
$orderInfo['total_price'] = bcadd($orderInfo['total_price'], $orderInfo['vip_true_price'], 2);
if ($orderInfo['store_id'] && $orderInfo['shipping_type'] == 2) {
/** @var $storeServices */

View File

@ -0,0 +1,92 @@
<?php
namespace app\adminapi\controller\v1\system;
use app\adminapi\controller\AuthController;
use app\services\system\timer\SystemTimerServices;
use think\facade\App;
class SystemTimer extends AuthController
{
public function __construct(App $app, SystemTimerServices $services)
{
parent::__construct($app);
$this->services = $services;
}
/**
* 获取定时任务列表
* @return mixed
*/
public function getTimerList()
{
$where = ['is_del' => 0];
return app('json')->success($this->services->getTimerList($where));
}
/**
* 获取定时任务详情
* @param $id
* @return mixed
*/
public function getTimerInfo($id)
{
return app('json')->success($this->services->getTimerInfo($id));
}
/**
* 获取定时任务类型
* @return mixed
*/
public function getMarkList()
{
return app('json')->success($this->services->getMarkList());
}
/**
* 保存定时任务
* @return mixed
*/
public function saveTimer()
{
$data = $this->request->postMore([
['id', 0],
['name', ''],
['mark', ''],
['content', ''],
['type', 0],
['is_open', 0],
['week', 0],
['day', 0],
['hour', 0],
['minute', 0],
['second', 0],
]);
$this->services->saveTimer($data);
return app('json')->success(100000);
}
/**
* 删除定时任务
* @param $id
* @return mixed
*/
public function delTimer($id)
{
$this->services->delTimer($id);
return app('json')->success(100002);
}
/**
* 设置定时任务状态
* @param $id
* @param $is_open
* @return mixed
*/
public function setTimerStatus($id, $is_open)
{
$this->services->setTimerStatus($id, $is_open);
return app('json')->success(100014);
}
}

View File

@ -63,18 +63,16 @@ class UserLevel extends AuthController
['icon', ''],
['image', ''],
['is_show', ''],
['explain', ''],
['exp_num', 0]
]);
if ($data['valid_date'] == 0) $data['is_forever'] = 1;//有效时间为0的时候就是永久
if (!$data['name']) return app('json')->fail(400324);
if (!$data['grade']) return app('json')->fail(400325);
if (!$data['explain']) return app('json')->fail(400326);
if (!$data['icon']) return app('json')->fail(400327);
if (!$data['image']) return app('json')->fail(400328);
if (!$data['exp_num']) return app('json')->fail(400329);
return app('json')->success($this->services->save((int)$data['id'], $data));
$this->services->save((int)$data['id'], $data);
return app('json')->success(100000);
}
/*

View File

@ -96,6 +96,21 @@ Route::group('system', function () {
Route::get('upgrade_export/:id/:type', 'UpgradeController/export')->option(['real_name' => '导出备份']);
//文件管理登录
Route::post('file/login', 'v1.system.SystemFile/login')->option(['real_name' => '文件管理登录']);
/** 定时任务 */
//定时任务列表
Route::get('timer/list', 'v1.system.SystemTimer/getTimerList')->option(['real_name' => '定时任务列表']);
//定时任务类型
Route::get('timer/mark', 'v1.system.SystemTimer/getMarkList')->option(['real_name' => '定时任务类型']);
//定时任务详情
Route::get('timer/info/:id', 'v1.system.SystemTimer/getTimerInfo')->option(['real_name' => '定时任务详情']);
//定时任务添加编辑
Route::post('timer/save', 'v1.system.SystemTimer/saveTimer')->option(['real_name' => '定时任务添加编辑']);
//删除定时任务
Route::delete('timer/del/:id', 'v1.system.SystemTimer/delTimer')->option(['real_name' => '删除定时任务']);
//定时任务是否开启开关
Route::get('timer/set_open/:id/:is_open', 'v1.system.SystemTimer/setTimerStatus')->option(['real_name' => '定时任务是否开启开关']);
})->middleware([
\app\http\middleware\AllowOriginMiddleware::class,
\app\adminapi\middleware\AdminAuthTokenMiddleware::class,

View File

@ -60,7 +60,7 @@ class StoreCouponsController
/** @var StoreCouponIssueServices $couponIssueService */
$couponIssueService = app()->make(StoreCouponIssueServices::class);
$couponIssueService->issueUserCoupon($couponId, $request->user());
$couponIssueService->issueUserCoupon($couponId, $request->user(), true);
return app('json')->success(410319);
}

View File

@ -55,7 +55,8 @@ class StoreProductController
[['type', 0], 0],
['ids', ''],
['selectId', ''],
['productId', '']
['productId', ''],
['coupon_category_id', '']
]);
if ($where['selectId'] && (!$where['sid'] || !$where['cid'])) {
if ($services->value(['id' => $where['selectId']], 'pid')) {

View File

@ -101,7 +101,9 @@ class StoreCouponIssueDao extends BaseDao
}])
->where('type', $type)
->when($type == 1, function ($query) use ($typeId) {
if ($typeId) $query->where('category_id', 'in', $typeId);
if ($typeId) $query->where('id', 'in', function ($query) use ($typeId) {
$query->name('store_coupon_product')->whereIn('category_id', $typeId)->field(['coupon_id'])->select();
})->whereOr('category_id', 'in', $typeId);
})
->when($type == 2, function ($query) use ($typeId) {
if ($typeId) $query->whereFindinSet('product_id', $typeId);
@ -138,7 +140,9 @@ class StoreCouponIssueDao extends BaseDao
$query->where('uid', $uid);
}])->where(function ($query) use ($product_id, $cate_ids) {
if ($product_id != 0 && $cate_ids != []) {
$query->whereFindinSet('product_id', $product_id)->whereOr('category_id', 'in', $cate_ids)->whereOr('type', 0);
$query->whereFindinSet('product_id', $product_id)->whereOr('id', 'in', function ($query) use ($cate_ids) {
$query->name('store_coupon_product')->whereIn('category_id', $cate_ids)->field(['coupon_id'])->select();
})->whereOr('category_id', 'in', $cate_ids)->whereOr('type', 0);
}
})->when($limit > 0, function ($query) use ($limit) {
$query->limit($limit);

View File

@ -164,18 +164,24 @@ class StoreCategoryDao extends BaseDao
/**
* 通过分类id 获取(自己以及下级)的所有分类
* @param int $id
* @param $id
* @param string $field
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getAllById(int $id, string $field = 'id')
public function getAllById($id, string $field = 'id')
{
return $this->getModel()->where(function ($query) use ($id) {
$query->where('id', $id)->whereOr('pid', $id);
})->where('is_show', 1)->field($field)->select()->toArray();
if (is_array($id)) {
return $this->getModel()->where(function ($query) use ($id) {
$query->whereIn('id', $id)->whereOr('pid', 'in', $id);
})->where('is_show', 1)->field($field)->select()->toArray();
} else {
return $this->getModel()->where(function ($query) use ($id) {
$query->where('id', $id)->whereOr('pid', $id);
})->where('is_show', 1)->field($field)->select()->toArray();
}
}
/**

View File

@ -124,6 +124,12 @@ class StoreProductDao extends BaseDao
$query->name('store_category')->where('pid', $where['cid'])->field('id')->select();
})->field('product_id')->select();
});
})->when(isset($where['coupon_category_id']) && $where['coupon_category_id'] != '', function ($query) use ($where) {
$query->whereIn('id', function ($query) use ($where) {
$query->name('store_product_cate')->whereIn('cate_id', function ($query) use ($where) {
$query->name('store_category')->whereIn('pid', $where['coupon_category_id'])->field('id')->select();
})->whereOr('cate_id', 'in', $where['coupon_category_id'])->field('product_id')->select();
});
})->when(isset($where['ids']) && $where['ids'], function ($query) use ($where) {
if ((isset($where['priceOrder']) && $where['priceOrder'] != '') || (isset($where['salesOrder']) && $where['salesOrder'] != '')) {
$query->whereIn('id', $where['ids']);

View File

@ -0,0 +1,18 @@
<?php
namespace app\dao\system\timer;
use app\dao\BaseDao;
use app\model\system\timer\SystemTimer;
class SystemTimerDao extends BaseDao
{
/**
* 设置模型
* @return string
*/
protected function setModel(): string
{
return SystemTimer::class;
}
}

View File

@ -39,10 +39,8 @@ return [
'user.userVisit' => [\app\listener\user\UserVisit::class], //用户访问事件
'notice.notice' => [\app\listener\notice\Notice::class], //通知->消息事件
'pay.notify' => [\app\listener\pay\Notify::class],//支付异步回调
'SystemTimer' => [\app\listener\timer\SystemTimer::class],//定时任务事件
],
'subscribe' => [
\app\subscribes\TaskSubscribe::class,//定时任务事件订阅类
]
];

View File

@ -0,0 +1,192 @@
<?php
namespace app\listener\timer;
use app\services\activity\combination\StorePinkServices;
use app\services\activity\live\LiveGoodsServices;
use app\services\activity\live\LiveRoomServices;
use app\services\agent\AgentManageServices;
use app\services\order\StoreOrderServices;
use app\services\order\StoreOrderTakeServices;
use app\services\product\product\StoreProductServices;
use app\services\system\attachment\SystemAttachmentServices;
use app\services\system\timer\SystemTimerServices;
use crmeb\interfaces\ListenerInterface;
use think\facade\Log;
use Workerman\Crontab\Crontab;
class SystemTimer implements ListenerInterface
{
public function handle($event): void
{
new Crontab('*/6 * * * * *', function () {
file_put_contents(runtime_path() . '.timer', time());
});
/** @var SystemTimerServices $systemTimerServices */
$systemTimerServices = app()->make(SystemTimerServices::class);
$list = $systemTimerServices->selectList(['is_del' => 0, 'is_open' => 1])->toArray();
foreach ($list as &$item) {
//获取定时任务时间字符串
$timeStr = $this->getTimerStr($item);
Log::error('mark:'.$item['mark']);
Log::error($timeStr);
if ($item['mark'] == 'order_cancel') {
new Crontab($timeStr, function () {
Log::error('每隔30秒执行一次自动取消订单 '.date('Y-m-d H:i:s'));
//未支付自动取消订单
try {
/** @var StoreOrderServices $orderServices */
$orderServices = app()->make(StoreOrderServices::class);
$orderServices->orderUnpaidCancel();
} catch (\Throwable $e) {
Log::error('自动取消订单失败,失败原因:' . $e->getMessage());
}
});
}
if ($item['mark'] == 'pink_expiration') {
new Crontab($timeStr, function () {
Log::error('每隔1分钟执行一次拼团到期订单处理 '.date('Y-m-d H:i:s'));
//拼团到期订单处理
try {
/** @var StorePinkServices $storePinkServices */
$storePinkServices = app()->make(StorePinkServices::class);
$storePinkServices->statusPink();
} catch (\Throwable $e) {
Log::error('拼团到期订单处理失败,失败原因:' . $e->getMessage());
}
});
}
if ($item['mark'] == 'agent_unbind') {
new Crontab($timeStr, function () {
Log::error('每隔1分钟执行一次自动解除上级绑定 '.date('Y-m-d H:i:s'));
//自动解绑上级绑定
try {
/** @var AgentManageServices $agentManage */
$agentManage = app()->make(AgentManageServices::class);
$agentManage->removeSpread();
} catch (\Throwable $e) {
Log::error('自动解除上级绑定失败,失败原因:' . $e->getMessage());
}
});
}
if ($item['mark'] == 'live_product_status') {
new Crontab($timeStr, function () {
Log::error('每隔3分钟执行一次更新直播商品状态 '.date('Y-m-d H:i:s'));
//更新直播商品状态
try {
/** @var LiveGoodsServices $liveGoods */
$liveGoods = app()->make(LiveGoodsServices::class);
$liveGoods->syncGoodStatus();
} catch (\Throwable $e) {
Log::error('更新直播商品状态失败,失败原因:' . $e->getMessage());
}
});
}
if ($item['mark'] == 'live_room_status') {
new Crontab($timeStr, function () {
Log::error('每隔3分钟执行一次更新直播间状态 '.date('Y-m-d H:i:s'));
//更新直播间状态
try {
/** @var LiveRoomServices $liveRoom */
$liveRoom = app()->make(LiveRoomServices::class);
$liveRoom->syncRoomStatus();
} catch (\Throwable $e) {
Log::error('更新直播间状态失败,失败原因:' . $e->getMessage());
}
});
}
if ($item['mark'] == 'take_delivery') {
new Crontab($timeStr, function () {
Log::error('每隔5分钟执行一次自动收货 '.date('Y-m-d H:i:s'));
//自动收货
try {
/** @var StoreOrderTakeServices $services */
$services = app()->make(StoreOrderTakeServices::class);
$services->autoTakeOrder();
} catch (\Throwable $e) {
Log::error('自动收货失败,失败原因:' . $e->getMessage());
}
});
}
if ($item['mark'] == 'advance_off') {
new Crontab($timeStr, function () {
Log::error('每隔5分钟执行一次查询预售到期商品自动下架 '.date('Y-m-d H:i:s'));
//查询预售到期商品自动下架
try {
/** @var StoreProductServices $product */
$product = app()->make(StoreProductServices::class);
$product->downAdvance();
} catch (\Throwable $e) {
Log::error('预售到期商品自动下架失败,失败原因:' . $e->getMessage());
}
});
}
if ($item['mark'] == 'product_replay') {
new Crontab($timeStr, function () {
Log::error('每隔5分钟执行一次自动好评 '.date('Y-m-d H:i:s'));
//自动好评
try {
/** @var StoreOrderServices $orderServices */
$orderServices = app()->make(StoreOrderServices::class);
$orderServices->autoComment();
} catch (\Throwable $e) {
Log::error('自动好评失败,失败原因:' . $e->getMessage());
}
});
}
if ($item['mark'] == 'product_replay') {
new Crontab($timeStr, function () {
Log::error('每天0时30分0秒执行一次清除昨日海报 '.date('Y-m-d H:i:s'));
//清除昨日海报
try {
/** @var SystemAttachmentServices $attach */
$attach = app()->make(SystemAttachmentServices::class);
$attach->emptyYesterdayAttachment();
} catch (\Throwable $e) {
Log::error('清除昨日海报失败,失败原因:' . $e->getMessage());
}
});
}
}
}
public function getTimerStr($data): string
{
$timeStr = '';
switch ($data['type']) {
case 1:
$timeStr = '*/' . $data['second'] . ' * * * * *';
break;
case 2:
$timeStr = '0 */' . $data['minute'] . ' * * * *';
break;
case 3:
$timeStr = '0 0 */' . $data['hour'] . ' * * *';
break;
case 4:
$timeStr = '0 0 0 */' . $data['day'] . ' * *';
break;
case 5:
$timeStr = $data['second'] . ' ' . $data['minute'] . ' ' . $data['hour'] . ' * * *';
break;
case 6:
$timeStr = $data['second'] . ' ' . $data['minute'] . ' ' . $data['hour'] . ' * * ' . ($data['week'] == 7 ? 0 : $data['week']);
break;
case 7:
$timeStr = $data['second'] . ' ' . $data['minute'] . ' ' . $data['hour'] . ' ' . $data['day'] . ' * *';
break;
}
return $timeStr;
}
}

View File

@ -42,7 +42,7 @@ class StoreCouponIssue extends BaseModel
*/
public function used()
{
return $this->hasOne(StoreCouponIssueUser::class, 'issue_coupon_id', 'id')->field('issue_coupon_id');
return $this->hasMany(StoreCouponIssueUser::class, 'issue_coupon_id', 'id');
}
/**

View File

@ -0,0 +1,23 @@
<?php
namespace app\model\system\timer;
use crmeb\basic\BaseModel;
use crmeb\traits\ModelTrait;
class SystemTimer extends BaseModel
{
use ModelTrait;
/**
* 数据表主键
* @var string
*/
protected $pk = 'id';
/**
* 模型名称
* @var string
*/
protected $name = 'system_timer';
}

View File

@ -68,7 +68,8 @@ class StoreCouponIssueServices extends BaseServices
return compact('list', 'count');
}
/**获取会员优惠券列表
/**
* 获取会员优惠券列表
* @param array $where
* @return array
* @throws \think\db\exception\DataNotFoundException
@ -117,17 +118,25 @@ class StoreCouponIssueServices extends BaseServices
$data['end_time'] = strtotime((string)$data['end_time']);
$data['title'] = $data['coupon_title'];
$data['remain_count'] = $data['total_count'];
$data['category_id'] = implode(',', $data['category_id']);
if ($data['receive_type'] == 2 || $data['receive_type'] == 3) {
$data['is_permanent'] = 1;
$data['total_count'] = 0;
}
$data['add_time'] = time();
$res = $this->dao->save($data);
if ($data['product_id'] !== '' && $res) {
$productIds = explode(',', $data['product_id']);
if (($data['product_id'] !== '' || $data['category_id'] !== '') && $res) {
$couponData = [];
foreach ($productIds as $product_id) {
$couponData[] = ['product_id' => $product_id, 'coupon_id' => $res->id];
if ($data['product_id'] !== '') {
$productIds = explode(',', $data['product_id']);
foreach ($productIds as $product_id) {
$couponData[] = ['product_id' => $product_id, 'coupon_id' => $res->id];
}
} elseif ($data['category_id'] !== '') {
$categoryIds = explode(',', $data['category_id']);
foreach ($categoryIds as $category_id) {
$couponData[] = ['category_id' => $category_id, 'coupon_id' => $res->id];
}
}
/** @var StoreCouponProductServices $storeCouponProductService */
$storeCouponProductService = app()->make(StoreCouponProductServices::class);
@ -237,30 +246,27 @@ class StoreCouponIssueServices extends BaseServices
$ids = array_column($couponList, 'id');
/** @var StoreCouponIssueUserServices $issueUser */
$issueUser = app()->make(StoreCouponIssueUserServices::class);
$userCouponIds = $issueUser->getColumn([['uid', '=', $uid], ['issue_coupon_id', 'in', $ids]], 'issue_coupon_id') ?? [];
foreach ($couponList as $item) {
if (!$userCouponIds || !in_array($item['id'], $userCouponIds)) {
$data['cid'] = $item['id'];
$data['uid'] = $uid;
$data['coupon_title'] = $item['title'];
$data['coupon_price'] = $item['coupon_price'];
$data['use_min_price'] = $item['use_min_price'];
if ($item['coupon_time']) {
$data['add_time'] = $time;
$data['end_time'] = $data['add_time'] + $item['coupon_time'] * 86400;
} else {
$data['add_time'] = $item['start_use_time'];
$data['end_time'] = $item['end_use_time'];
}
$data['type'] = 'get';
$issue['uid'] = $uid;
$issue['issue_coupon_id'] = $item['id'];
$issue['add_time'] = $time;
$issueUserData[] = $issue;
$couponData[] = $data;
unset($data);
unset($issue);
$data['cid'] = $item['id'];
$data['uid'] = $uid;
$data['coupon_title'] = $item['title'];
$data['coupon_price'] = $item['coupon_price'];
$data['use_min_price'] = $item['use_min_price'];
if ($item['coupon_time']) {
$data['add_time'] = $time;
$data['end_time'] = $data['add_time'] + $item['coupon_time'] * 86400;
} else {
$data['add_time'] = $item['start_use_time'];
$data['end_time'] = $item['end_use_time'];
}
$data['type'] = 'get';
$issue['uid'] = $uid;
$issue['issue_coupon_id'] = $item['id'];
$issue['add_time'] = $time;
$issueUserData[] = $issue;
$couponData[] = $data;
unset($data);
unset($issue);
}
if ($couponData) {
/** @var StoreCouponUserServices $storeCouponUser */
@ -326,10 +332,10 @@ class StoreCouponIssueServices extends BaseServices
foreach ($list as &$v) {
$v['coupon_price'] = floatval($v['coupon_price']);
$v['use_min_price'] = floatval($v['use_min_price']);
$v['is_use'] = $uid && isset($v['used']);
$v['is_use'] = count($v['used']);
if ($v['end_use_time']) {
$v['start_use_time'] = date('Y/m/d', $v['start_use_time']);
$v['end_use_time'] = $v['end_use_time'] ? date('Y/m/d', $v['end_use_time']) : date('Y/m/d', time() + 86400);
$v['end_use_time'] = date('Y/m/d', $v['end_use_time']);
}
if ($v['start_time']) {
$v['start_time'] = date('Y/m/d', $v['start_time']);
@ -341,7 +347,16 @@ class StoreCouponIssueServices extends BaseServices
return $data;
}
public function issueUserCoupon($id, $user)
/**
* 领取优惠券
* @param $id
* @param $user
* @param bool $is_receive
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function issueUserCoupon($id, $user, bool $is_receive = false)
{
$issueCouponInfo = $this->dao->getInfo((int)$id);
$uid = $user->uid;
@ -354,9 +369,14 @@ class StoreCouponIssueServices extends BaseServices
}
/** @var StoreCouponIssueUserServices $issueUserService */
$issueUserService = app()->make(StoreCouponIssueUserServices::class);
if ($is_receive) {
$alreadyReceived = $issueUserService->count(['uid' => $uid, 'issue_coupon_id' => $id]);
if ($alreadyReceived >= $issueCouponInfo['receive_limit']) {
throw new ApiException(400518);
}
}
/** @var StoreCouponUserServices $couponUserService */
$couponUserService = app()->make(StoreCouponUserServices::class);
if ($issueUserService->getOne(['uid' => $uid, 'issue_coupon_id' => $id])) throw new ApiException(400517);
if ($issueCouponInfo->remain_count <= 0 && !$issueCouponInfo->is_permanent) throw new ApiException(400518);
$this->transaction(function () use ($issueUserService, $uid, $id, $couponUserService, $issueCouponInfo) {
$issueUserService->save(['uid' => $uid, 'issue_coupon_id' => $id, 'add_time' => time()]);
@ -432,29 +452,24 @@ class StoreCouponIssueServices extends BaseServices
$storeCouponUser = app()->make(StoreCouponUserServices::class);
/** @var StoreCouponIssueUserServices $storeCouponIssueUser */
$storeCouponIssueUser = app()->make(StoreCouponIssueUserServices::class);
$uids = $storeCouponIssueUser->getColumn(['issue_coupon_id' => $coupon['id']], 'uid');
foreach ($user as $k => $v) {
if (in_array($v, $uids)) {
continue;
$data[$k]['cid'] = $coupon['id'];
$data[$k]['uid'] = $v;
$data[$k]['coupon_title'] = $coupon['title'];
$data[$k]['coupon_price'] = $coupon['coupon_price'];
$data[$k]['use_min_price'] = $coupon['use_min_price'];
$data[$k]['add_time'] = time();
if ($coupon['coupon_time']) {
$data[$k]['start_time'] = $data[$k]['add_time'];
$data[$k]['end_time'] = $data[$k]['add_time'] + $coupon['coupon_time'] * 86400;
} else {
$data[$k]['cid'] = $coupon['id'];
$data[$k]['uid'] = $v;
$data[$k]['coupon_title'] = $coupon['title'];
$data[$k]['coupon_price'] = $coupon['coupon_price'];
$data[$k]['use_min_price'] = $coupon['use_min_price'];
$data[$k]['add_time'] = time();
if ($coupon['coupon_time']) {
$data[$k]['start_time'] = $data[$k]['add_time'];
$data[$k]['end_time'] = $data[$k]['add_time'] + $coupon['coupon_time'] * 86400;
} else {
$data[$k]['start_time'] = $coupon['start_use_time'];
$data[$k]['end_time'] = $coupon['end_use_time'];
}
$data[$k]['type'] = 'send';
$issueData[$k]['uid'] = $v;
$issueData[$k]['issue_coupon_id'] = $coupon['id'];
$issueData[$k]['add_time'] = time();
$data[$k]['start_time'] = $coupon['start_use_time'];
$data[$k]['end_time'] = $coupon['end_use_time'];
}
$data[$k]['type'] = 'send';
$issueData[$k]['uid'] = $v;
$issueData[$k]['issue_coupon_id'] = $coupon['id'];
$issueData[$k]['add_time'] = time();
}
if (!empty($data)) {
if (!$storeCouponUser->saveAll($data)) {
@ -464,8 +479,6 @@ class StoreCouponIssueServices extends BaseServices
throw new AdminException(100031);
}
return true;
} else {
throw new AdminException(400519);
}
}

View File

@ -8,7 +8,7 @@
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
declare (strict_types = 1);
declare (strict_types=1);
namespace app\services\activity\coupon;
@ -42,6 +42,10 @@ class StoreCouponIssueUserServices extends BaseServices
{
[$page, $limit] = $this->getPageValue();
$list = $this->dao->getList($where, $page, $limit);
$site_url = sys_config('site_url');
foreach ($list as &$item) {
$item['avatar'] = strpos($item['avatar'], 'http') === false ? ($site_url . $item['avatar']) : $item['avatar'];
}
$count = $this->dao->count($where);
return compact('list', 'count');
}

View File

@ -145,9 +145,10 @@ class StoreCouponUserServices extends BaseServices
case 1://品类券
/** @var StoreCategoryServices $storeCategoryServices */
$storeCategoryServices = app()->make(StoreCategoryServices::class);
$cateGorys = $storeCategoryServices->getAllById((int)$coupon['category_id']);
if ($cateGorys) {
$cateIds = array_column($cateGorys, 'id');
$coupon_category = explode(',', $coupon['category_id']);
$category_ids = $storeCategoryServices->getAllById($coupon_category);
if ($category_ids) {
$cateIds = array_column($category_ids, 'id');
foreach ($cartInfo as $cart) {
if (isset($cart['productInfo']['cate_id']) && array_intersect(explode(',', $cart['productInfo']['cate_id']), $cateIds)) {
$price += bcmul((string)$cart['truePrice'], (string)$cart['cart_num'], 2);
@ -302,18 +303,6 @@ class StoreCouponUserServices extends BaseServices
}
[$page, $limit] = $this->getPageValue();
$list = $this->dao->getCouponListByOrder($where, 'status ASC,add_time DESC', $page, $limit);
/** @var StoreCategoryServices $categoryServices */
$categoryServices = app()->make(StoreCategoryServices::class);
$category = $categoryServices->getColumn([], 'pid,cate_name', 'id');
foreach ($list as &$item) {
if ($item['category_id']) {
$item['category_type'] = $category[$item['category_id']]['pid'] == 0 ? 1 : 2;
$item['category_name'] = $category[$item['category_id']]['cate_name'];
} else {
$item['category_type'] = '';
$item['category_name'] = '';
}
}
return $list ? $this->tidyCouponList($list) : [];
}

View File

@ -83,21 +83,32 @@ class NoticeService extends BaseServices
if (!$product) {
throw new AdminException(400463);
}
$configdata = [
'clientId' => sys_config('printing_client_id', ''),
'apiKey' => sys_config('printing_api_key', ''),
'partner' => sys_config('develop_id', ''),
'terminal' => sys_config('terminal_number', '')
];
$switch = (bool)sys_config('pay_success_printing_switch');
if (!$switch) {
throw new AdminException(400464);
}
if (!$configdata['clientId'] || !$configdata['apiKey'] || !$configdata['partner'] || !$configdata['terminal']) {
throw new AdminException(400465);
if (sys_config('print_type', 1) == 1) {
$name = 'yi_lian_yun';
$configData = [
'clientId' => sys_config('printing_client_id', ''),
'apiKey' => sys_config('printing_api_key', ''),
'partner' => sys_config('develop_id', ''),
'terminal' => sys_config('terminal_number', '')
];
if (!$configData['clientId'] || !$configData['apiKey'] || !$configData['partner'] || !$configData['terminal']) {
throw new AdminException(400465);
}
} else {
$name = 'fei_e_yun';
$configData = [
'feyUser' => sys_config('fey_user', ''),
'feyUkey' => sys_config('fey_ukey', ''),
'feySn' => sys_config('fey_sn', '')
];
if (!$configData['feyUser'] || !$configData['feyUkey'] || !$configData['feySn']) {
throw new AdminException(400465);
}
}
PrintJob::dispatch('doJob', ['yi_lian_yun', $configdata, $order, $product]);
PrintJob::dispatch('doJob', [$name, $configData, $order, $product]);
}
}

View File

@ -16,7 +16,6 @@ use app\services\activity\advance\StoreAdvanceServices;
use app\services\BaseServices;
use app\dao\order\StoreCartDao;
use app\services\activity\coupon\StoreCouponIssueServices;
use app\services\activity\coupon\StoreCouponIssueUserServices;
use app\services\shipping\ShippingTemplatesNoDeliveryServices;
use app\services\system\SystemUserLevelServices;
use app\services\user\member\MemberCardServices;
@ -172,11 +171,6 @@ class StoreCartServices extends BaseServices
if (!$issueCoupon->getCount(['id' => $attrInfo['coupon_id'], 'status' => 1, 'is_del' => 0])) {
throw new ApiException(410234);
}
/** @var StoreCouponIssueUserServices $issueUserCoupon */
$issueUserCoupon = app()->make(StoreCouponIssueUserServices::class);
if ($issueUserCoupon->getCount(['uid' => $uid, 'issue_coupon_id' => $attrInfo['coupon_id']])) {
throw new ApiException(410235);
}
}
$stockNum = $this->dao->value(['product_id' => $productId, 'product_attr_unique' => $unique, 'uid' => $uid, 'status' => 1], 'cart_num') ?: 0;
if ($nowStock < ($cartNum + $stockNum)) {

View File

@ -175,9 +175,10 @@ class StoreOrderComputedServices extends BaseServices
case 1://品类券
/** @var StoreCategoryServices $storeCategoryServices */
$storeCategoryServices = app()->make(StoreCategoryServices::class);
$cateGorys = $storeCategoryServices->getAllById((int)$couponInfo['category_id']);
if ($cateGorys) {
$cateIds = array_column($cateGorys, 'id');
$coupon_category = explode(',', $couponInfo['category_id']);
$category_ids = $storeCategoryServices->getAllById($coupon_category);
if ($category_ids) {
$cateIds = array_column($category_ids, 'id');
foreach ($cartInfo as $cart) {
if (isset($cart['productInfo']['cate_id']) && array_intersect(explode(',', $cart['productInfo']['cate_id']), $cateIds)) {
$price = bcadd($price, bcmul((string)$cart['truePrice'], (string)$cart['cart_num'], 2), 2);
@ -318,7 +319,9 @@ class StoreOrderComputedServices extends BaseServices
$sumPrice = $this->getOrderSumPrice($cartInfo, 'sum_price');//获取订单原总金额
$totalPrice = $this->getOrderSumPrice($cartInfo, 'truePrice');//获取订单svip、用户等级优惠之后总金额
$costPrice = $this->getOrderSumPrice($cartInfo, 'costPrice');//获取订单成本价
$vipPrice = $this->getOrderSumPrice($cartInfo, 'vip_truePrice');//获取订单会员优惠金额
$vipPrice = $this->getOrderSumPrice($cartInfo, 'vip_truePrice');//获取订单等级和付费会员总优惠金额
$levelPrice = $this->getOrderSumPrice($cartInfo, 'level');//获取会员等级优惠
$memberPrice = $this->getOrderSumPrice($cartInfo, 'member');//获取付费会员优惠
// 判断商品包邮和固定运费
foreach ($cartInfo as $key => &$item) {
@ -513,7 +516,7 @@ class StoreOrderComputedServices extends BaseServices
$storePostage = $storePostage;
}
}
return compact('storePostage', 'storeFreePostage', 'isStoreFreePostage', 'sumPrice', 'totalPrice', 'costPrice', 'vipPrice', 'storePostageDiscount', 'cartInfo');
return compact('storePostage', 'storeFreePostage', 'isStoreFreePostage', 'sumPrice', 'totalPrice', 'costPrice', 'vipPrice', 'storePostageDiscount', 'cartInfo', 'levelPrice', 'memberPrice');
}
/**
@ -529,7 +532,13 @@ class StoreOrderComputedServices extends BaseServices
foreach ($cartInfo as $cart) {
if (isset($cart['cart_info'])) $cart = $cart['cart_info'];
if ($is_unit) {
$SumPrice = bcadd($SumPrice, bcmul($cart['cart_num'], $cart[$key], 2), 2);
if ($key == 'level' || $key == 'member') {
if ($cart['price_type'] == $key) {
$SumPrice = bcadd($SumPrice, bcmul($cart['cart_num'], $cart['vip_truePrice'], 2), 2);
}
} else {
$SumPrice = bcadd($SumPrice, bcmul($cart['cart_num'], $cart[$key], 2), 2);
}
} else {
$SumPrice = bcadd($SumPrice, $cart[$key], 2);
}

View File

@ -650,9 +650,10 @@ class StoreOrderCreateServices extends BaseServices
case 1://品类券
/** @var StoreCategoryServices $storeCategoryServices */
$storeCategoryServices = app()->make(StoreCategoryServices::class);
$cateGorys = $storeCategoryServices->getAllById((int)$couponInfo['category_id']);
if ($cateGorys) {
$cateIds = array_column($cateGorys, 'id');
$coupon_category = explode(',', $couponInfo['category_id']);
$category_ids = $storeCategoryServices->getAllById($coupon_category);
if ($category_ids) {
$cateIds = array_column($category_ids, 'id');
foreach ($cartInfo as $cart) {
if (isset($cart['productInfo']['cate_id']) && array_intersect(explode(',', $cart['productInfo']['cate_id']), $cateIds)) {
$total_price = bcadd((string)$total_price, (string)bcmul((string)$cart['truePrice'], (string)$cart['cart_num'], 4), 2);

View File

@ -1454,16 +1454,29 @@ HTML;
if (!$product) {
throw new AdminException(400533);
}
$data = [
'clientId' => sys_config('printing_client_id', ''),
'apiKey' => sys_config('printing_api_key', ''),
'partner' => sys_config('develop_id', ''),
'terminal' => sys_config('terminal_number', '')
];
if (!$data['clientId'] || !$data['apiKey'] || !$data['partner'] || !$data['terminal']) {
throw new AdminException(400099);
if (sys_config('print_type', 1) == 1) {
$name = 'yi_lian_yun';
$configData = [
'clientId' => sys_config('printing_client_id', ''),
'apiKey' => sys_config('printing_api_key', ''),
'partner' => sys_config('develop_id', ''),
'terminal' => sys_config('terminal_number', '')
];
if (!$configData['clientId'] || !$configData['apiKey'] || !$configData['partner'] || !$configData['terminal']) {
throw new AdminException(400465);
}
} else {
$name = 'fei_e_yun';
$configData = [
'feyUser' => sys_config('fey_user', ''),
'feyUkey' => sys_config('fey_ukey', ''),
'feySn' => sys_config('fey_sn', '')
];
if (!$configData['feyUser'] || !$configData['feyUkey'] || !$configData['feySn']) {
throw new AdminException(400465);
}
}
$printer = new Printer('yi_lian_yun', $data);
$printer = new Printer($name, $configData);
$res = $printer->setPrinterContent([
'name' => sys_config('site_name'),
'orderInfo' => is_object($order) ? $order->toArray() : $order,
@ -2334,9 +2347,11 @@ HTML;
$order['ali_pay_status'] = (bool)sys_config('ali_pay_status');//支付包支付 1 开启 0 关闭
$order['friend_pay_status'] = (int)sys_config('friend_pay_status') ?? 0;//好友代付 1 开启 0 关闭
$orderData = $this->tidyOrder($order, true, true);
$vipTruePrice = 0;
$vipTruePrice = $memberPrice = $levelPrice = 0;
foreach ($orderData['cartInfo'] ?? [] as $key => $cart) {
$vipTruePrice = bcadd((string)$vipTruePrice, (string)$cart['vip_sum_truePrice'], 2);
if ($cart['price_type'] == 'member') $memberPrice = bcadd((string)$memberPrice, (string)$cart['vip_sum_truePrice'], 2);
if ($cart['price_type'] == 'level') $levelPrice = bcadd((string)$levelPrice, (string)$cart['vip_sum_truePrice'], 2);
if (isset($splitNum[$cart['id']])) {
$orderData['cartInfo'][$key]['cart_num'] = $cart['cart_num'] - $splitNum[$cart['id']];
if ($orderData['cartInfo'][$key]['cart_num'] == 0) unset($orderData['cartInfo'][$key]);
@ -2344,6 +2359,8 @@ HTML;
}
$orderData['cartInfo'] = array_merge($orderData['cartInfo']);
$orderData['vip_true_price'] = $vipTruePrice;
$orderData['levelPrice'] = $levelPrice;
$orderData['memberPrice'] = $memberPrice;
$economize = $services->get(['order_id' => $order['order_id']], ['postage_price', 'member_price']);
if ($economize) {
$orderData['postage_price'] = $economize['postage_price'];

View File

@ -0,0 +1,187 @@
<?php
namespace app\services\system\timer;
use app\dao\system\timer\SystemTimerDao;
use app\services\BaseServices;
use crmeb\exceptions\AdminException;
class SystemTimerServices extends BaseServices
{
/**
* 定时任务类型
* @var string[]
*/
private $markList = [
'order_cancel' => '未支付自动取消订单',
'pink_expiration' => '拼团到期订单处理',
'agent_unbind' => '到期自动解绑上级',
'live_product_status' => '自动更新直播商品状态',
'live_room_status' => '自动更新直播间状态',
'take_delivery' => '订单自动收货',
'advance_off' => '预售商品到期自动下架',
'product_replay' => '订单商品自动好评',
'clear_poster' => '清除昨日海报',
];
public function __construct(SystemTimerDao $dao)
{
$this->dao = $dao;
}
/**
* 定时任务列表
* @param array $where
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getTimerList(array $where = [])
{
[$page, $limit] = $this->getPageValue();
$list = $this->dao->selectList($where, '*', $page, $limit, 'id desc');
foreach ($list as &$item) {
$item['next_execution_time'] = date('Y-m-d H:i:s', $item['next_execution_time']);
$item['last_execution_time'] = $item['last_execution_time'] != 0 ? date('Y-m-d H:i:s', $item['last_execution_time']) : '暂未执行';
}
$count = $this->dao->count($where);
return compact('list', 'count');
}
/**
* 定时任务详情
* @param $id
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getTimerInfo($id)
{
$info = $this->dao->get($id);
if (!$info) throw new AdminException(100026);
return $info->toArray();
}
/**
* 定时任务类型
* @return string[]
*/
public function getMarkList(): array
{
return $this->markList;
}
/**
* 保存定时任务
* @param array $data
* @return bool
*/
public function saveTimer(array $data = [])
{
if (!$data['id'] && $this->dao->getCount(['mark' => $data['mark'], 'is_del' => 0])) {
throw new AdminException('该定时任务已存在,请勿重复添加');
}
$data['name'] = $this->markList[$data['mark']];
$data['add_time'] = time();
if (!$data['id']) {
unset($data['id']);
$res = $this->dao->save($data);
} else {
$res = $this->dao->update(['id' => $data['id']], $data);
}
if (!$res) throw new AdminException(100006);
return true;
}
/**
* 删除定时任务
* @param $id
* @return bool
*/
public function delTimer($id)
{
$res = $this->dao->update(['id' => $id], ['is_del' => 1]);
if (!$res) throw new AdminException(100008);
return true;
}
/**
* 设置定时任务状态
* @param $id
* @param $is_open
* @return bool
*/
public function setTimerStatus($id, $is_open)
{
$res = $this->dao->update(['id' => $id], ['is_open' => $is_open]);
if (!$res) throw new AdminException(100014);
return true;
}
/**
* 计算定时任务下次执行时间(弃用)
* @param $data
* @param int $time
* @return false|float|int|mixed
*/
public function getTimerCycleTime($data, $time = 0)
{
if (!$time) $time = time();
switch ($data['type']) {
case 1: // 每隔几秒
$cycle_time = $time + $data['second'];
break;
case 2: // 每隔几分
$cycle_time = $time + ($data['minute'] * 60);
break;
case 3: // 每隔几时
$cycle_time = $time + ($data['hour'] * 3600);
break;
case 4: // 每隔几日
$cycle_time = $time + ($data['day'] * 86400);
break;
case 5: // 每日几时几分几秒
$cycle_time = strtotime(date('Y-m-d ' . $data['hour'] . ':' . $data['minute'] . ':' . $data['second'], time()));
if ($time >= $cycle_time) {
$cycle_time = $cycle_time + 86400;
}
break;
case 6: // 每周周几几时几分几秒
$todayStart = strtotime(date('Y-m-d 00:00:00', time()));
$w = date("w");
if ($w > $data['week']) {
$cycle_time = $todayStart + ((7 - $w + $data['week']) * 86400) + ($data['hour'] * 3600) + ($data['minute'] * 60) + $data['second'];
} else if ($w == $data['week']) {
$cycle_time = $todayStart + ($data['hour'] * 3600) + ($data['minute'] * 60) + $data['second'];
if ($time >= $cycle_time) {
$cycle_time = $cycle_time + (7 * 86400);
}
} else {
$cycle_time = $todayStart + (($data['week'] - $w) * 86400) + ($data['hour'] * 3600) + ($data['minute'] * 60) + $data['second'];
}
break;
case 7: // 每月几日几时几分几秒
$d = date("d");
$firstDate = date('Y-m-01', time());
$maxDay = date('d', strtotime("$firstDate + 1 month -1 day"));
$todayStart = strtotime(date('Y-m-d 00:00:00', time()));
if ($d > $data['day']) {
$cycle_time = $todayStart + (($maxDay - $d + $data['day']) * 86400) + ($data['hour'] * 3600) + ($data['minute'] * 60) + $data['second'];
} elseif ($d == $data['day']) {
$cycle_time = $todayStart + ($data['hour'] * 3600) + ($data['minute'] * 60) + $data['second'];
if ($time >= $cycle_time) {
$cycle_time = $cycle_time + (($maxDay - $d + $data['day']) * 86400) + ($data['hour'] * 3600) + ($data['minute'] * 60) + $data['second'];
}
} else {
$cycle_time = $todayStart + (($data['day'] - $d) * 86400) + ($data['hour'] * 3600) + ($data['minute'] * 60) + $data['second'];
}
break;
default:
$cycle_time = 0;
break;
}
return $cycle_time;
}
}

View File

@ -8,7 +8,7 @@
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
declare (strict_types = 1);
declare (strict_types=1);
namespace app\services\user;
@ -206,10 +206,10 @@ class UserLevelServices extends BaseServices
{
if ($id) {
$vipinfo = app()->make(SystemUserLevelServices::class)->getlevel($id);
$vipinfo->image = set_file_url($vipinfo->image);
$vipinfo->icon = set_file_url($vipinfo->icon);
if (!$vipinfo) {
$vipInfo = app()->make(SystemUserLevelServices::class)->getlevel($id);
$vipInfo->image = set_file_url($vipInfo->image);
$vipInfo->icon = set_file_url($vipInfo->icon);
if (!$vipInfo) {
throw new AdminException(100026);
}
$field[] = Form::hidden('id', $id);
@ -217,15 +217,13 @@ class UserLevelServices extends BaseServices
} else {
$msg = '添加用户等级';
}
$field[] = Form::input('name', '等级名称', isset($vipinfo) ? $vipinfo->name : '')->col(24)->required();
// $field[] = Form::number('valid_date', '有效时间(天)', isset($vipinfo) ? $vipinfo->valid_date : 0)->min(0)->col(12);
$field[] = Form::number('grade', '等级', isset($vipinfo) ? $vipinfo->grade : 0)->min(0)->precision(0)->col(8)->required();
$field[] = Form::number('discount', '享受折扣', isset($vipinfo) ? $vipinfo->discount : 100)->min(0)->max(100)->col(8)->placeholder('输入折扣数100,代表原价,90代表9折')->required();
$field[] = Form::number('exp_num', '解锁需经验值达到', isset($vipinfo) ? $vipinfo->exp_num : 0)->min(0)->precision(0)->col(8)->required();
$field[] = Form::frameImage('icon', '图标', Url::buildUrl('admin/widget.images/index', array('fodder' => 'icon')), isset($vipinfo) ? $vipinfo->icon : '')->icon('ios-add')->width('950px')->height('505px')->modal(['footer-hide' => true]);
$field[] = Form::frameImage('image', '用户等级背景', Url::buildUrl('admin/widget.images/index', array('fodder' => 'image')), isset($vipinfo) ? $vipinfo->image : '')->icon('ios-add')->width('950px')->height('505px')->modal(['footer-hide' => true]);
$field[] = Form::radio('is_show', '是否显示', isset($vipinfo) ? $vipinfo->is_show : 0)->options([['label' => '显示', 'value' => 1], ['label' => '隐藏', 'value' => 0]])->col(24);
$field[] = Form::textarea('explain', '等级说明', isset($vipinfo) ? $vipinfo->explain : '')->required();
$field[] = Form::input('name', '等级名称', isset($vipInfo) ? $vipInfo->name : '')->col(24)->required();
$field[] = Form::number('grade', '等级', isset($vipInfo) ? $vipInfo->grade : 0)->min(0)->precision(0)->col(8)->required();
$field[] = Form::number('discount', '享受折扣', isset($vipInfo) ? $vipInfo->discount : 100)->min(0)->max(100)->col(8)->placeholder('输入折扣数100,代表原价,90代表9折')->required();
$field[] = Form::number('exp_num', '解锁需经验值达到', isset($vipInfo) ? $vipInfo->exp_num : 0)->min(0)->precision(0)->col(8)->required();
$field[] = Form::frameImage('icon', '图标', Url::buildUrl('admin/widget.images/index', array('fodder' => 'icon')), isset($vipInfo) ? $vipInfo->icon : '')->icon('ios-add')->width('950px')->height('505px')->modal(['footer-hide' => true]);
$field[] = Form::frameImage('image', '用户等级背景', Url::buildUrl('admin/widget.images/index', array('fodder' => 'image')), isset($vipInfo) ? $vipInfo->image : '')->icon('ios-add')->width('950px')->height('505px')->modal(['footer-hide' => true]);
$field[] = Form::radio('is_show', '是否显示', isset($vipInfo) ? $vipInfo->is_show : 0)->options([['label' => '显示', 'value' => 1], ['label' => '隐藏', 'value' => 0]])->col(24);
return create_form($msg, $field, Url::buildUrl('/user/user_level'), 'POST');
}
@ -260,7 +258,7 @@ class UserLevelServices extends BaseServices
if (!$systemUserLevel->update($id, $data)) {
throw new AdminException(100007);
}
return '修改成功';
return true;
} else {
if ($levelOne || $levelThree) {
throw new AdminException(400675);
@ -273,7 +271,7 @@ class UserLevelServices extends BaseServices
if (!$systemUserLevel->save($data)) {
throw new AdminException(100022);
}
return '添加成功';
return true;
}
}
@ -291,7 +289,7 @@ class UserLevelServices extends BaseServices
if (!$systemUserLevel->update($id, ['is_del' => 1]))
throw new AdminException(100008);
}
return '删除成功';
return 100002;
}
/**

View File

@ -27,7 +27,7 @@ class Timer extends Command
/**
* @var int|float
*/
protected $interval = 2;
protected $interval = 1;
protected function configure()
{
@ -59,35 +59,11 @@ class Timer extends Command
$this->init($input, $output);
Worker::$pidFile = app()->getRootPath().'runtime/timer.pid';
$task = new Worker();
date_default_timezone_set('PRC');
$task->count = 1;
event('Task_6');
$task->onWorkerStart = [$this, 'start'];
$task->onWorkerStart = function () {
event('SystemTimer');
};
$task->runAll();
}
public function stop()
{
\Workerman\Lib\Timer::del($this->timer);
}
public function start()
{
$last = time();
$task = [6 => $last, 10 => $last, 30 => $last, 60 => $last, 180 => $last, 300 => $last];
$this->timer = \Workerman\Lib\Timer::add($this->interval, function () use (&$task) {
try {
$now = time();
event('Task_2');
foreach ($task as $sec => $time) {
if ($now - $time >= $sec) {
event('Task_' . $sec);
$task[$sec] = $now;
}
}
} catch (\Throwable $e) {
}
});
}
}

View File

@ -20,7 +20,7 @@ use think\facade\Config;
/**
* 第三方支付
* Class Pay
* Class AllinPay
* @package crmeb\services\pay
* @mixin AliPay
* @mixin WechatPay

View File

@ -14,7 +14,6 @@ namespace crmeb\services\printer;
use app\services\other\CacheServices;
use crmeb\exceptions\AdminException;
use crmeb\services\HttpService;
use think\facade\Config;
use think\helper\Str;
/**
@ -72,12 +71,33 @@ class AccessToken extends HttpService
*/
protected $apiKey;
/**
* 飞鹅云SN
* @var string
*/
protected $feySn;
/**
* 飞鹅云UYEK
* @var string
*/
protected $feyUkey;
/**
* 飞鹅云USER
* @var string
*/
protected $feyUser;
public function __construct(array $config = [], string $name, string $configFile)
{
$this->clientId = $config['clientId'] ?? null;
$this->apiKey = $config['apiKey'] ?? null;
$this->partner = $config['partner'] ?? null;
$this->machineCode = $config['terminal'] ?? null;
$this->feyUser = $config['feyUser'] ?? null;
$this->feyUkey = $config['feyUkey'] ?? null;
$this->feySn = $config['feySn'] ?? null;
$this->name = $name;
$this->configFile = $configFile;
}
@ -150,7 +170,7 @@ class AccessToken extends HttpService
*/
public function __get($name)
{
if (in_array($name, ['clientId', 'apiKey', 'accessToken', 'partner', 'terminal', 'machineCode'])) {
if (in_array($name, ['clientId', 'apiKey', 'accessToken', 'partner', 'terminal', 'machineCode', 'feyUser', 'feyUkey', 'feySn'])) {
return $this->{$name};
}
}

View File

@ -0,0 +1,161 @@
<?php
namespace crmeb\services\printer\storage;
use crmeb\services\printer\BasePrinter;
class FeiEYun extends BasePrinter
{
/**
* 初始化
* @param array $config
* @return mixed|void
*/
protected function initialize(array $config)
{
}
/**
* 开始打印
* @return bool|mixed|string
* @throws \Exception
*/
public function startPrinter()
{
if (!$this->printerContent) {
return $this->setError('Missing print');
}
$time = time();
$request = $this->accessToken->postRequest('http://api.feieyun.cn/Api/Open/', [
'user' => $this->accessToken->feyUser,
'stime' => $time,
'sig' => sha1($this->accessToken->feyUser . $this->accessToken->feyUkey . $time),
'apiname' => 'Open_printMsg',
'sn' => $this->accessToken->feySn,
'content' => $this->printerContent,
'times' => 1
]);
$res = json_decode($request, true);
if ($res['msg'] == 'ok') {
return $res;
} else {
return $this->setError($res['msg']);
}
}
/**
* 设置打印内容
* @param array $config
* @return YiLianYun
*/
public function setPrinterContent(array $config): self
{
$printTime = date('Y-m-d H:i:s', time());
$product = $config['product'];
$orderInfo = $config['orderInfo'];
$orderTime = date('Y-m-d H:i:s', $orderInfo['pay_time']);
$this->printerContent = '<CB>**' . $config['name'] . '**</CB><BR>';
$this->printerContent .= '--------------------------------<BR>';
$this->printerContent .= '订单编号:' . $orderInfo['order_id'] . '<BR>';
$this->printerContent .= '打印时间: ' . $printTime . '<BR>';
$this->printerContent .= '付款时间: ' . $orderTime . '<BR>';
$this->printerContent .= '姓 名: ' . $orderInfo['real_name'] . '<BR>';
$this->printerContent .= '电 话: ' . $orderInfo['user_phone'] . '<BR>';
$this->printerContent .= '地 址: ' . $orderInfo['user_address'] . '<BR>';
$this->printerContent .= '赠送积分: ' . $orderInfo['gain_integral'] . '<BR>';
$this->printerContent .= '订单备注:' . $orderInfo['mark'] . '<BR>';
$this->printerContent .= '**************商品**************<BR>';
$this->printerContent .= '名称 单价 数量 金额<BR>';
$this->printerContent .= '--------------------------------<BR>';
foreach ($product as $item) {
$name = $item['productInfo']['store_name'];
$price = $item['truePrice'];
$num = $item['cart_num'];
$prices = bcmul((string)$item['cart_num'], (string)$item['truePrice'], 2);
$kw3 = '';
$kw1 = '';
$kw2 = '';
$kw4 = '';
$str = $name;
$blankNum = 14;//名称控制为14个字节
$lan = mb_strlen($str, 'utf-8');
$m = 0;
$j = 1;
$blankNum++;
$result = array();
if (strlen($price) < 6) {
$k1 = 6 - strlen($price);
for ($q = 0; $q < $k1; $q++) {
$kw1 .= ' ';
}
$price = $price . $kw1;
}
if (strlen($num) < 3) {
$k2 = 3 - strlen($num);
for ($q = 0; $q < $k2; $q++) {
$kw2 .= ' ';
}
$num = $num . $kw2;
}
if (strlen($prices) < 6) {
$k3 = 6 - strlen($prices);
for ($q = 0; $q < $k3; $q++) {
$kw4 .= ' ';
}
$prices = $prices . $kw4;
}
for ($i = 0; $i < $lan; $i++) {
$new = mb_substr($str, $m, $j, 'utf-8');
$j++;
if (mb_strwidth($new, 'utf-8') < $blankNum) {
if ($m + $j > $lan) {
$m = $m + $j;
$tail = $new;
$lenght = iconv("UTF-8", "GBK//IGNORE", $new);
$k = 14 - strlen($lenght);
for ($q = 0; $q < $k; $q++) {
$kw3 .= ' ';
}
if ($m == $j) {
$tail .= $kw3 . ' ' . $price . ' ' . $num . ' ' . $prices;
} else {
$tail .= $kw3 . '<BR>';
}
break;
} else {
$next_new = mb_substr($str, $m, $j, 'utf-8');
if (mb_strwidth($next_new, 'utf-8') < $blankNum) continue;
else {
$m = $i + 1;
$result[] = $new;
$j = 1;
}
}
}
}
$head = '';
foreach ($result as $key => $value) {
if ($key < 1) {
$v_lenght = iconv("UTF-8", "GBK//IGNORE", $value);
$v_lenght = strlen($v_lenght);
if ($v_lenght == 13) $value = $value . " ";
$head .= $value . ' ' . $price . ' ' . $num . ' ' . $prices;
} else {
$head .= $value . '<BR>';
}
}
$this->printerContent .= $head . $tail;
unset($price);
}
$this->printerContent .= '--------------------------------<BR>';
$this->printerContent .= '合计:' . number_format($orderInfo['total_price'], 1) . '元<BR>';
$this->printerContent .= '邮费:' . number_format($orderInfo['pay_postage'], 1) . '元<BR>';
$this->printerContent .= '优惠:' . number_format($orderInfo['coupon_price'], 1) . '元<BR>';
$this->printerContent .= '抵扣:' . number_format($orderInfo['deduction_price'], 1) . '元<BR>';
$this->printerContent .= '实际支付:' . number_format($orderInfo['pay_price'], 1) . '元<BR>';
$this->printerContent .= '<QR>' . $config['url'] . '</QR>';//把解析后的二维码生成的字符串用标签套上即可自动生成二维码
return $this;
}
}

View File

@ -27857,6 +27857,7 @@ CREATE TABLE IF NOT EXISTS `eb_store_coupon_issue` (
`end_time` int(10) NOT NULL DEFAULT '0' COMMENT '优惠券领取结束时间',
`total_count` int(10) NOT NULL DEFAULT '0' COMMENT '优惠券领取数量',
`remain_count` int(10) NOT NULL DEFAULT '0' COMMENT '优惠券剩余领取数量',
`receive_limit` int(10) NOT NULL DEFAULT '0' COMMENT '每个人个领取的优惠券数量',
`is_permanent` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否无限张数',
`status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '1 正常 0 未开启 -1 已无效',
`is_give_subscribe` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否首次关注赠送 0-否(默认) 1-是',
@ -27901,8 +27902,7 @@ INSERT INTO `eb_store_coupon_issue` (`id`, `cid`, `coupon_title`, `start_time`,
CREATE TABLE IF NOT EXISTS `eb_store_coupon_issue_user` (
`uid` int(10) NOT NULL DEFAULT '0' COMMENT '领取优惠券用户ID',
`issue_coupon_id` int(10) NOT NULL DEFAULT '0' COMMENT '优惠券前台领取ID',
`add_time` int(10) NOT NULL DEFAULT '0' COMMENT '领取时间',
UNIQUE KEY `uid` (`uid`,`issue_coupon_id`) USING BTREE
`add_time` int(10) NOT NULL DEFAULT '0' COMMENT '领取时间'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='优惠券前台用户领取记录表';
-- --------------------------------------------------------
@ -27914,6 +27914,7 @@ CREATE TABLE IF NOT EXISTS `eb_store_coupon_issue_user` (
CREATE TABLE IF NOT EXISTS `eb_store_coupon_product` (
`coupon_id` int(11) NOT NULL DEFAULT '0' COMMENT '优惠卷模板id',
`product_id` int(11) NOT NULL DEFAULT '0' COMMENT '商品id',
`category_id` int(11) NOT NULL DEFAULT '0' COMMENT '分类id',
KEY `coupon_id` (`coupon_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='优惠卷模板关联列表';
@ -33177,7 +33178,7 @@ INSERT INTO `eb_system_config` (`id`, `menu_name`, `type`, `input_type`, `config
(383, 'tengxun_appid', 'text', 'input', 82, '', 0, '', 0, 0, '\"\"', '腾讯云APPID', '腾讯云APPID', 0, 1),
(384, 'extract_type', 'checkbox', 'input', 74, '0=>银行卡\n1=>微信\n2=>支付宝', 1, '', 0, 0, '[\"0\",\"1\",\"2\"]', '提现方式', '提现方式', 0, 1),
(385, 'integral_frozen', 'text', 'input', 11, '', 1, '', 100, 0, '\"0\"', '积分冻结(天)', '积分冻结(天)', 0, 1),
(386, 'print_type', 'radio', 'input', 86, '1=>易联云', 1, '', 0, 0, '\"1\"', '平台选择', '平台选择', 0, 1),
(386, 'print_type', 'radio', 'input', 86, '1=>易联云\n2=>飞鹅云', 1, '', 0, 0, '1', '平台选择', '平台选择', 0, 1),
(387, 'config_export_type', 'radio', 'input', 93, '1=>一号通', 1, '', 0, 0, '\"1\"', '电子面单类型', '电子面单类型', 0, 1),
(388, 'customer_corpId', 'text', 'input', 69, '', 1, '', 100, 0, '\"\"', '企业ID', '小程序需要跳转企业微信客服的话需要配置此项', 0, 1),
(389, 'create_wechat_user', 'radio', 'input', 2, '1=>开启\r\n0=>关闭', 1, '', 0, 0, '0', '关注公众号是否生成用户', '关注公众号是否生成用户', 0, 1),
@ -33203,7 +33204,11 @@ INSERT INTO `eb_system_config` (`id`, `menu_name`, `type`, `input_type`, `config
(416, 'reward_money', 'text', 'number', 105, '', 1, '', 0, 0, '\"0\"', '赠送余额(元)', '新用户奖励金额,必须大于等于0,0为不赠送', 0, 1),
(417, 'reward_integral', 'text', 'number', 105, '', 1, '', 0, 0, '\"0\"', '赠送积分', '新用户奖励积分,必须大于等于0,0为不赠送', 0, 1),
(418, 'hs_accesskey', 'text', 'input', 106, '', 1, '', 0, 0, '\"AKLTMzkzZTEzNjg3OTg2NDViM2IwNmFlYzhmNzE4MmI4YmI\"', '火山翻译AccessKey', '机器翻译仅支持火山翻译', 1, 1),
(419, 'hs_secretkey', 'text', 'input', 106, '', 1, '', 0, 0, '\"TVRneU16STFOVFV4WVRkbE5ERTJaV0pqWm1aaU1UaGlNVFppWldZeE1HUQ==\"', '火山翻译SecretKey', '机器翻译仅支持火山翻译', 0, 1);
(419, 'hs_secretkey', 'text', 'input', 106, '', 1, '', 0, 0, '\"TVRneU16STFOVFV4WVRkbE5ERTJaV0pqWm1aaU1UaGlNVFppWldZeE1HUQ==\"', '火山翻译SecretKey', '机器翻译仅支持火山翻译', 0, 1),
(420, 'fey_user', 'text', 'input', 107, '', 1, '', 0, 0, '\"\"', '飞鹅云USER', '飞鹅云后台注册账号', 10, 1),
(421, 'fey_ukey', 'text', 'input', 107, '', 1, '', 0, 0, '\"\"', '飞鹅云UYEK', '飞鹅云后台注册账号后生成的UKEY 【备注:这不是填打印机的KEY】', 7, 1),
(422, 'fey_sn', 'text', 'input', 107, '', 1, '', 100, 0, '\"\"', '飞鹅云SN', '打印机标签上的编号,必须要在管理后台里添加打印机或调用API接口添加之后,才能调用API', 0, 1);
-- --------------------------------------------------------
--
@ -33284,7 +33289,8 @@ INSERT INTO `eb_system_config_tab` (`id`, `pid`, `title`, `eng_title`, `status`,
(103, 102, '基础配置', 'out_basic', 1, 0, '', 3, 0),
(104, 102, '推送配置', 'out_push', 1, 0, '', 3, 0),
(105, 100, '新用户设置', 'new_user_setting', 1, 0, '', 0, 0),
(106, 5, '机器翻译配置', 'online_translation', 1, 0, '', 0, 0);
(106, 5, '机器翻译配置', 'online_translation', 1, 0, '', 0, 0),
(107, 21, '飞鹅云配置', 'fey_config', 1, 0, '', 0, 0);
-- --------------------------------------------------------
@ -34331,7 +34337,8 @@ INSERT INTO `eb_system_menus` (`id`, `pid`, `icon`, `menu_name`, `module`, `cont
(1071, 56, '', '文件管理', 'admin', '', '', '', '', '[]', 0, 1, 0, 1, '/admin/system/maintain/system_file/opendir', '25/56', 1, '', 0, 'system-maintain-system-file', 0),
(1072, 1064, '', '接口文档', 'admin', '', '', '', '', '[]', 0, 1, 0, 1, '/admin/setting/system_out_interface/index', '56/1064', 1, '', 0, 'setting-system-out-interface-index', 0),
(1073, 25, '', '数据维护', 'admin', '', '', '', '', '[]', 7, 1, 0, 1, 'system/database/index', '25', 1, '', 0, 'system-database-index', 0),
(1075, 731, '', '会员配置', 'admin', '', '', '', '', '[]', 6, 1, 0, 1, '/admin/marketing/member/system_config/3/67', '27/731', 1, '', 0, 'marketing-member-system_config', 0);
(1075, 731, '', '会员配置', 'admin', '', '', '', '', '[]', 6, 1, 0, 1, '/admin/marketing/member/system_config/3/67', '27/731', 1, '', 0, 'marketing-member-system_config', 0),
(1076, 56, '', '定时任务', 'admin', '', '', '', '', '[]', 0, 1, 0, 1, '/admin/system/crontab', '25/56', 1, '', 0, 'system-crontab-index', 0);
-- --------------------------------------------------------
@ -34530,6 +34537,46 @@ CREATE TABLE IF NOT EXISTS `eb_system_store_staff` (
-- --------------------------------------------------------
--
-- 表的结构 `eb_system_timer`
--
CREATE TABLE IF NOT EXISTS `eb_system_timer` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL DEFAULT '' COMMENT '定时器名称',
`mark` varchar(255) NOT NULL DEFAULT '' COMMENT '标签',
`content` varchar(255) NOT NULL DEFAULT '' COMMENT '说明',
`type` tinyint(1) NOT NULL DEFAULT '0' COMMENT '周期状态 1=每隔多少秒 2=每隔多少分钟 3=每隔多少小时 4=每隔多少天 5=每天几点执行 6=每周周几几点执行 7=每月几号几点执行',
`week` int(11) NOT NULL DEFAULT '0' COMMENT '周',
`day` int(11) NOT NULL DEFAULT '0' COMMENT '日',
`hour` int(11) NOT NULL DEFAULT '0' COMMENT '时',
`minute` int(11) NOT NULL DEFAULT '0' COMMENT '分',
`second` int(11) NOT NULL DEFAULT '0' COMMENT '秒',
`last_execution_time` int(11) NOT NULL DEFAULT '0' COMMENT '上次执行时间',
`next_execution_time` int(11) NOT NULL DEFAULT '0' COMMENT '下次执行时间',
`add_time` int(11) NOT NULL DEFAULT '0' COMMENT '添加时间',
`is_del` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否删除',
`is_open` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否开启',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8 COMMENT='定时器';
--
-- 转存表中的数据 `eb_system_timer`
--
INSERT INTO `eb_system_timer` (`id`, `name`, `mark`, `content`, `type`, `week`, `day`, `hour`, `minute`, `second`, `last_execution_time`, `next_execution_time`, `add_time`, `is_del`, `is_open`) VALUES
(1, '未支付自动取消订单', 'order_cancel', '每隔30秒执行自动取消到期未支付的订单', 1, 1, 1, 1, 30, 30, 0, 1670642407, 1670642377, 0, 1),
(2, '拼团到期订单处理', 'pink_expiration', '每隔1分钟拼团到期之后的操作', 2, 1, 1, 1, 1, 0, 0, 1670642487, 1670642427, 0, 1),
(3, '到期自动解绑上级', 'agent_unbind', '每隔1分钟执行到期的绑定关系的解除', 2, 1, 1, 1, 1, 0, 0, 1670642534, 1670642474, 0, 1),
(4, '自动更新直播商品状态', 'live_product_status', '每隔3分钟执行更新直播商品状态', 2, 1, 1, 1, 3, 0, 0, 1670642694, 1670642514, 0, 1),
(5, '自动更新直播间状态', 'live_room_status', '每隔3分钟执行更新直播间状态', 2, 1, 1, 1, 3, 0, 0, 1670642709, 1670642529, 0, 1),
(6, '订单自动收货', 'take_delivery', '每隔5分钟执行订单到期自动收货', 2, 1, 1, 1, 5, 0, 0, 1670642891, 1670642591, 0, 1),
(7, '预售商品到期自动下架', 'advance_off', '每隔5分钟执行预售商品到期下架', 2, 1, 1, 1, 5, 0, 0, 1670642913, 1670642613, 0, 1),
(8, '订单商品自动好评', 'product_replay', '每隔5分钟执行订单到期商品好评', 2, 1, 1, 1, 5, 0, 0, 1670642933, 1670642633, 0, 1),
(9, '清除昨日海报', 'clear_poster', '每天0时30分0秒执行一次清除昨日海报', 5, 1, 1, 0, 30, 0, 0, 1670862600, 1670815378, 0, 1);
-- --------------------------------------------------------
--
-- 表的结构 `eb_system_user_level`
--

View File

@ -16,6 +16,7 @@ return array(
'crmeb\\' => array($baseDir . '/crmeb'),
'app\\' => array($baseDir . '/app'),
'ZipStream\\' => array($vendorDir . '/maennchen/zipstream-php/src'),
'Workerman\\Crontab\\' => array($vendorDir . '/workerman/crontab/src'),
'Workerman\\' => array($vendorDir . '/workerman/workerman'),
'Volc\\' => array($vendorDir . '/volcengine/volc-sdk-php/src'),
'Test\\' => array($vendorDir . '/volcengine/volc-sdk-php/tests'),

View File

@ -119,6 +119,7 @@ class ComposerStaticInitf16474ac994ccc25392f403933800b79
),
'W' =>
array (
'Workerman\\Crontab\\' => 18,
'Workerman\\' => 10,
),
'V' =>
@ -291,6 +292,10 @@ class ComposerStaticInitf16474ac994ccc25392f403933800b79
array (
0 => __DIR__ . '/..' . '/maennchen/zipstream-php/src',
),
'Workerman\\Crontab\\' =>
array (
0 => __DIR__ . '/..' . '/workerman/crontab/src',
),
'Workerman\\' =>
array (
0 => __DIR__ . '/..' . '/workerman/workerman',

View File

@ -5358,6 +5358,65 @@
"homepage": "http://www.workerman.net",
"install-path": "../workerman/channel"
},
{
"name": "workerman/crontab",
"version": "v1.0.2",
"version_normalized": "1.0.2.0",
"source": {
"type": "git",
"url": "https://github.com/walkor/crontab.git",
"reference": "28106241415049ee340a8a7cd9b640165240a2fa"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/walkor/crontab/zipball/28106241415049ee340a8a7cd9b640165240a2fa",
"reference": "28106241415049ee340a8a7cd9b640165240a2fa",
"shasum": "",
"mirrors": [
{
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
"preferred": true
}
]
},
"require": {
"php": ">=7.0",
"workerman/workerman": ">=3.5.0"
},
"time": "2021-10-06T14:18:14+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-4": {
"Workerman\\Crontab\\": "./src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "walkor",
"email": "walkor@workerman.net",
"homepage": "http://www.workerman.net",
"role": "Developer"
}
],
"description": "A crontab written in PHP based on workerman",
"homepage": "http://www.workerman.net",
"keywords": [
"crontab"
],
"support": {
"email": "walkor@workerman.net",
"forum": "http://wenda.workerman.net/",
"issues": "https://github.com/walkor/workerman/issues",
"source": "https://github.com/walkor/crontab",
"wiki": "http://doc.workerman.net/"
},
"install-path": "../workerman/crontab"
},
{
"name": "workerman/workerman",
"version": "v3.5.19",

View File

@ -1,9 +1,9 @@
<?php return array(
'root' => array(
'name' => 'topthink/think',
'pretty_version' => '4.6.0.x-dev',
'version' => '4.6.0.9999999-dev',
'reference' => '24e1593a45135b3f38cacaa456385e38a370f0e6',
'pretty_version' => '4.7.0.x-dev',
'version' => '4.7.0.9999999-dev',
'reference' => 'a788475ebfcfc447b5f262ea3f803a6fd9b89a8d',
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
@ -827,9 +827,9 @@
'dev_requirement' => false,
),
'topthink/think' => array(
'pretty_version' => '4.6.0.x-dev',
'version' => '4.6.0.9999999-dev',
'reference' => '24e1593a45135b3f38cacaa456385e38a370f0e6',
'pretty_version' => '4.7.0.x-dev',
'version' => '4.7.0.9999999-dev',
'reference' => 'a788475ebfcfc447b5f262ea3f803a6fd9b89a8d',
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
@ -934,6 +934,15 @@
'aliases' => array(),
'dev_requirement' => false,
),
'workerman/crontab' => array(
'pretty_version' => 'v1.0.2',
'version' => '1.0.2.0',
'reference' => '28106241415049ee340a8a7cd9b640165240a2fa',
'type' => 'library',
'install_path' => __DIR__ . '/../workerman/crontab',
'aliases' => array(),
'dev_requirement' => false,
),
'workerman/workerman' => array(
'pretty_version' => 'v3.5.19',
'version' => '3.5.19.0',

View File

@ -1,5 +1,5 @@
<?php
// This file is automatically generated at:2022-11-17 19:08:04
// This file is automatically generated at:2022-12-10 14:44:41
declare (strict_types = 1);
return array (
0 => 'think\\captcha\\CaptchaService',

View File

@ -0,0 +1,29 @@
# Crontab
A crontab with precision in seconds written in PHP based on [workerman](https://github.com/walkor/workerman).
# Install
```
composer require workerman/crontab
```
# Usage
start.php
```php
<?php
use Workerman\Worker;
require __DIR__ . '/../vendor/autoload.php';
use Workerman\Crontab\Crontab;
$worker = new Worker();
$worker->onWorkerStart = function () {
// Execute the function in the first second of every minute.
new Crontab('1 * * * * *', function(){
echo date('Y-m-d H:i:s')."\n";
});
};
Worker::runAll();
```
Run with commands `php start.php start` or php `start.php start -d`

View File

@ -0,0 +1,34 @@
{
"name": "workerman/crontab",
"type": "library",
"keywords": [
"crontab"
],
"homepage": "http://www.workerman.net",
"license": "MIT",
"description": "A crontab written in PHP based on workerman",
"authors": [
{
"name": "walkor",
"email": "walkor@workerman.net",
"homepage": "http://www.workerman.net",
"role": "Developer"
}
],
"support": {
"email": "walkor@workerman.net",
"issues": "https://github.com/walkor/workerman/issues",
"forum": "http://wenda.workerman.net/",
"wiki": "http://doc.workerman.net/",
"source": "https://github.com/walkor/crontab"
},
"require": {
"php": ">=7.0",
"workerman/workerman": ">=3.5.0"
},
"autoload": {
"psr-4": {
"Workerman\\Crontab\\": "./src"
}
}
}

View File

@ -0,0 +1,16 @@
<?php
use Workerman\Worker;
require __DIR__ . '/../vendor/autoload.php';
use Workerman\Crontab\Crontab;
$worker = new Worker();
$worker->onWorkerStart = function () {
// Execute the function in the first second of every minute.
new Crontab('1 * * * * *', function(){
echo date('Y-m-d H:i:s')."\n";
});
};
Worker::runAll();

View File

@ -0,0 +1,177 @@
<?php
/**
* This file is part of workerman.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @author walkor<walkor@workerman.net>
* @copyright walkor<walkor@workerman.net>
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Workerman\Crontab;
use Workerman\Lib\Timer;
/**
* Class Crontab
* @package Workerman\Crontab
*/
class Crontab
{
/**
* @var string
*/
protected $_rule;
/**
* @var callable
*/
protected $_callback;
/**
* @var string
*/
protected $_name;
/**
* @var int
*/
protected $_id;
/**
* @var array
*/
protected static $_instances = [];
/**
* Crontab constructor.
* @param $rule
* @param $callback
* @param null $name
*/
public function __construct($rule, $callback, $name = null)
{
$this->_rule = $rule;
$this->_callback = $callback;
$this->_name = $name;
$this->_id = static::createId();
static::$_instances[$this->_id] = $this;
static::tryInit();
}
/**
* @return string
*/
public function getRule()
{
return $this->_rule;
}
/**
* @return callable
*/
public function getCallback()
{
return $this->_callback;
}
/**
* @return string
*/
public function getName()
{
return $this->_name;
}
/**
* @return int
*/
public function getId()
{
return $this->_id;
}
/**
* @return bool
*/
public function destroy()
{
return static::remove($this->_id);
}
/**
* @return array
*/
public static function getAll()
{
return static::$_instances;
}
/**
* @param $id
* @return bool
*/
public static function remove($id)
{
if ($id instanceof Crontab) {
$id = $id->getId();
}
if (!isset(static::$_instances[$id])) {
return false;
}
unset(static::$_instances[$id]);
return true;
}
/**
* @return int
*/
protected static function createId()
{
static $id = 0;
return ++$id;
}
/**
* tryInit
*/
protected static function tryInit()
{
static $inited = false;
if ($inited) {
return;
}
$inited = true;
$parser = new Parser();
$callback = function () use ($parser, &$callback) {
foreach (static::$_instances as $crontab) {
$rule = $crontab->getRule();
$cb = $crontab->getCallback();
if (!$cb || !$rule) {
continue;
}
$times = $parser->parse($rule);
$now = time();
foreach ($times as $time) {
$t = $time-$now;
if ($t <= 0) {
$t = 0.000001;
}
Timer::add($t, $cb, null, false);
}
}
Timer::add(60 - time()%60, $callback, null, false);
};
$next_time = time()%60;
if ($next_time == 0) {
$next_time = 0.00001;
} else {
$next_time = 60 - $next_time;
}
Timer::add($next_time, $callback, null, false);
}
}

View File

@ -0,0 +1,171 @@
<?php
/**
* @author: Jan Konieczny <jkonieczny@gmail.com>, group@hyperf.io
* @license: http://www.gnu.org/licenses/
* @license: https://github.com/hyperf/hyperf/blob/master/LICENSE
*
* This is a simple script to parse crontab syntax to get the execution time
*
* Eg.: $timestamp = Crontab::parse('12 * * * 1-5');
*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Provides basic cron syntax parsing functionality
*
* @author: Jan Konieczny <jkonieczny@gmail.com>, group@hyperf.io
* @license: http://www.gnu.org/licenses/
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
namespace Workerman\Crontab;
/**
* Class Parser
* @package Workerman\Crontab
*/
class Parser
{
/**
* Finds next execution time(stamp) parsin crontab syntax.
*
* @param string $crontab_string :
* 0 1 2 3 4 5
* * * * * * *
* - - - - - -
* | | | | | |
* | | | | | +----- day of week (0 - 6) (Sunday=0)
* | | | | +----- month (1 - 12)
* | | | +------- day of month (1 - 31)
* | | +--------- hour (0 - 23)
* | +----------- min (0 - 59)
* +------------- sec (0-59)
*
* @param null|int $start_time
* @throws \InvalidArgumentException
* @return int[]
*/
public function parse($crontab_string, $start_time = null)
{
if (! $this->isValid($crontab_string)) {
throw new \InvalidArgumentException('Invalid cron string: ' . $crontab_string);
}
$start_time = $start_time ? $start_time : time();
$date = $this->parseDate($crontab_string);
if (in_array((int) date('i', $start_time), $date['minutes'])
&& in_array((int) date('G', $start_time), $date['hours'])
&& in_array((int) date('j', $start_time), $date['day'])
&& in_array((int) date('w', $start_time), $date['week'])
&& in_array((int) date('n', $start_time), $date['month'])
) {
$result = [];
foreach ($date['second'] as $second) {
$result[] = $start_time + $second;
}
return $result;
}
return [];
}
public function isValid(string $crontab_string): bool
{
if (! preg_match('/^((\*(\/[0-9]+)?)|[0-9\-\,\/]+)\s+((\*(\/[0-9]+)?)|[0-9\-\,\/]+)\s+((\*(\/[0-9]+)?)|[0-9\-\,\/]+)\s+((\*(\/[0-9]+)?)|[0-9\-\,\/]+)\s+((\*(\/[0-9]+)?)|[0-9\-\,\/]+)\s+((\*(\/[0-9]+)?)|[0-9\-\,\/]+)$/i', trim($crontab_string))) {
if (! preg_match('/^((\*(\/[0-9]+)?)|[0-9\-\,\/]+)\s+((\*(\/[0-9]+)?)|[0-9\-\,\/]+)\s+((\*(\/[0-9]+)?)|[0-9\-\,\/]+)\s+((\*(\/[0-9]+)?)|[0-9\-\,\/]+)\s+((\*(\/[0-9]+)?)|[0-9\-\,\/]+)$/i', trim($crontab_string))) {
return false;
}
}
return true;
}
/**
* Parse each segment of crontab string.
*/
protected function parseSegment(string $string, int $min, int $max, int $start = null)
{
if ($start === null || $start < $min) {
$start = $min;
}
$result = [];
if ($string === '*') {
for ($i = $start; $i <= $max; ++$i) {
$result[] = $i;
}
} elseif (strpos($string, ',') !== false) {
$exploded = explode(',', $string);
foreach ($exploded as $value) {
if (strpos($value, '/') !== false || strpos($string, '-') !== false) {
$result = array_merge($result, $this->parseSegment($value, $min, $max, $start));
continue;
}
if (trim($value) === '' || ! $this->between((int) $value, (int) ($min > $start ? $min : $start), (int) $max)) {
continue;
}
$result[] = (int) $value;
}
} elseif (strpos($string, '/') !== false) {
$exploded = explode('/', $string);
if (strpos($exploded[0], '-') !== false) {
[$nMin, $nMax] = explode('-', $exploded[0]);
$nMin > $min && $min = (int) $nMin;
$nMax < $max && $max = (int) $nMax;
}
$start < $min && $start = $min;
for ($i = $start; $i <= $max;) {
$result[] = $i;
$i += $exploded[1];
}
} elseif (strpos($string, '-') !== false) {
$result = array_merge($result, $this->parseSegment($string . '/1', $min, $max, $start));
} elseif ($this->between((int) $string, $min > $start ? $min : $start, $max)) {
$result[] = (int) $string;
}
return $result;
}
/**
* Determire if the $value is between in $min and $max ?
*/
private function between(int $value, int $min, int $max): bool
{
return $value >= $min && $value <= $max;
}
private function parseDate(string $crontab_string): array
{
$cron = preg_split('/[\\s]+/i', trim($crontab_string));
if (count($cron) == 6) {
$date = [
'second' => $this->parseSegment($cron[0], 0, 59),
'minutes' => $this->parseSegment($cron[1], 0, 59),
'hours' => $this->parseSegment($cron[2], 0, 23),
'day' => $this->parseSegment($cron[3], 1, 31),
'month' => $this->parseSegment($cron[4], 1, 12),
'week' => $this->parseSegment($cron[5], 0, 6),
];
} else {
$date = [
'second' => [1 => 0],
'minutes' => $this->parseSegment($cron[0], 0, 59),
'hours' => $this->parseSegment($cron[1], 0, 23),
'day' => $this->parseSegment($cron[2], 1, 31),
'month' => $this->parseSegment($cron[3], 1, 12),
'week' => $this->parseSegment($cron[4], 0, 6),
];
}
return $date;
}
}