diff --git a/app/Cache/Redis/Common/CommonRedisKey.php b/app/Cache/Redis/Common/CommonRedisKey.php index ba83e74..7ea318f 100644 --- a/app/Cache/Redis/Common/CommonRedisKey.php +++ b/app/Cache/Redis/Common/CommonRedisKey.php @@ -48,4 +48,12 @@ class CommonRedisKey { return '__system:wx:AccessToken:'; } + + /** + * @return string + */ + public static function getCycleList(): string + { + return '__cycle:list'; + } } \ No newline at end of file diff --git a/app/Cache/Redis/Common/CycleCache.php b/app/Cache/Redis/Common/CycleCache.php new file mode 100644 index 0000000..2485ec7 --- /dev/null +++ b/app/Cache/Redis/Common/CycleCache.php @@ -0,0 +1,46 @@ +redis->exists($key,'system')) return; + + $allData = $this->cycleModel->get(); + + if (empty($allData)) return; + + $allData = $allData->toArray(); + + foreach ($allData as $item) { + $this->redis->zAdd($key, $item['id'],$item['dates'],'system'); + } + } +} \ No newline at end of file diff --git a/app/Cache/Redis/RedisCache.php b/app/Cache/Redis/RedisCache.php index 488fdf7..f73ee4d 100644 --- a/app/Cache/Redis/RedisCache.php +++ b/app/Cache/Redis/RedisCache.php @@ -540,6 +540,19 @@ class RedisCache { return $this->getRedis($poolName)->zRem($key, $value); } + + /** + * @param $key + * @param $value + * @param string $poolName + * @return false|int|Redis + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface + */ + public function zRank($key, $value, string $poolName = 'default') + { + return $this->getRedis($poolName)->zRank($key, $value); + } // +-------------------------------------------------------------------------------------------------------------------------------------------- // | geo // +-------------------------------------------------------------------------------------------------------------------------------------------- diff --git a/app/Controller/Admin/GoodController.php b/app/Controller/Admin/GoodController.php index 24e520e..29c3218 100644 --- a/app/Controller/Admin/GoodController.php +++ b/app/Controller/Admin/GoodController.php @@ -7,6 +7,7 @@ namespace App\Controller\Admin; use App\Middleware\Admin\JwtAuthMiddleware; use App\Request\Admin\DriverRequest; use App\Request\Admin\GoodRequest; +use App\Service\Admin\Good\SpuService; use Hyperf\HttpServer\Annotation\Controller; use Hyperf\HttpServer\Annotation\Middlewares; use Hyperf\HttpServer\Annotation\RequestMapping; @@ -27,7 +28,7 @@ class GoodController #[Scene(scene: "add_spu")] public function add_spu(GoodRequest $request) { - + return (new SpuService())->add(); } /** diff --git a/app/Cron/Good/CycleCreateTask.php b/app/Cron/Good/CycleCreateTask.php index 6e2b5cd..0f43722 100644 --- a/app/Cron/Good/CycleCreateTask.php +++ b/app/Cron/Good/CycleCreateTask.php @@ -10,9 +10,16 @@ declare(strict_types=1); namespace App\Cron\Good; +use App\Cache\Redis\Common\CommonRedisKey; +use App\Cache\Redis\Common\CycleCache; +use App\Cache\Redis\RedisCache; +use App\Extend\DateUtil; +use App\Lib\Log; use App\Model\Cycle; use Hyperf\Crontab\Annotation\Crontab; use Hyperf\Di\Annotation\Inject; +use Psr\Container\ContainerExceptionInterface; +use Psr\Container\NotFoundExceptionInterface; #[Crontab(rule: "0 5 * * *", name: "CycleCreateTask", singleton: true , callback: "execute", memo: "创建新的周期任务")] class CycleCreateTask @@ -23,11 +30,72 @@ class CycleCreateTask #[Inject] protected Cycle $cycleModel; - public function execute() - { - //todo Write logic - var_dump(date('Y-m-d H:i:s', time())); + /** + * @var CycleCache $cycleCache + */ + #[Inject] + protected CycleCache $cycleCache; - $maxDate = $this->cycleModel->max('date'); + /** + * @var RedisCache + */ + #[Inject] + protected RedisCache $redis; + + /** + * @var Log + */ + #[Inject] + protected Log $log; + + /** + * 非常重要的逻辑--生成周期 (不可删除) + * @return void + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface + */ + public function execute(): void + { + $maxDate = $this->cycleModel->max('dates') ?? 0; + + $nextMax = date('Ymd',strtotime('+3 day',time())); + + if ($maxDate != 0 && $nextMax <= $maxDate) { + return; + } + + $nextCycleRange = DateUtil::getDateFromRange(date('Ymd'),$nextMax); + + $this->cycleCache->setAllCycleCache(); + + $key = CommonRedisKey::getCycleList(); + $noDataInsertArr = []; + $noDataArr = []; + foreach ($nextCycleRange as $date) { + $one = $this->redis->zScore($key,$date,'system'); + + if ($one) continue; + + $noDataInsertArr[] = [ + 'dates' => $date, + 'create_time' => date('Y-m-d H:i:s'), + ]; + $noDataArr[] = $date; + } + + $insertSql = (new Cycle)->insert($noDataInsertArr); + + if (!$insertSql) $this->log->error('添加周期失败!!!'); + + $res = $this->cycleModel->whereIn('dates',$noDataArr)->get(); + if (empty($res)) return; + + $res = $res->toArray(); + + foreach ($res as $one) { + $this->redis->zAdd($key,$one['id'],$one['dates'],'system'); + } + + $this->log->notice('添加周期成功,添加的周期为'.json_encode($noDataArr,JSON_UNESCAPED_UNICODE)); } } \ No newline at end of file diff --git a/app/Extend/DateUtil.php b/app/Extend/DateUtil.php index a67c046..cccafc1 100644 --- a/app/Extend/DateUtil.php +++ b/app/Extend/DateUtil.php @@ -96,4 +96,32 @@ class DateUtil $msTime = (float)sprintf('%.0f', (floatval($ms) + floatval($sec)) * 1000); return substr($msTime,0,13); } + + /** + * 获取指定日期段内每一天的日期 (开始时间必须小于结束时间) + * @param string $startDate + * @param string $endDate + * @param string $returnFormat + * @return array + */ + static function getDateFromRange(string $startDate, string $endDate, string $returnFormat = 'Y-m-d'): array + { + if (empty($startDate) || empty($endDate)) return []; + + if ($endDate < $startDate) return []; + + $sTimestamp = strtotime($startDate); + $eTimestamp = strtotime($endDate); + // 计算日期段内有多少天 + $days = ($eTimestamp-$sTimestamp)/86400+1; + + // 保存每天日期 + $date = []; + + for($i=0; $i<$days; $i++){ + $date[] = date($returnFormat, $sTimestamp+(86400*$i)); + } + + return $date; + } } \ No newline at end of file diff --git a/app/Model/Cycle.php b/app/Model/Cycle.php index f3db0e6..973cf37 100644 --- a/app/Model/Cycle.php +++ b/app/Model/Cycle.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace App\Model; +use Hyperf\Database\Model\Builder; use Hyperf\DbConnection\Model\Model; /** @@ -24,8 +25,22 @@ class Cycle extends Model */ protected array $fillable = []; + protected array $guarded = []; + /** * The attributes that should be cast to native types. */ protected array $casts = ['id' => 'integer', 'is_use' => 'integer']; + + const string CREATED_AT = 'create_time'; + const null UPDATED_AT = null; + + /** + * @param string $date + * @return Builder|\Hyperf\Database\Model\Model|null + */ + public function getInfoByDate(string $date): \Hyperf\Database\Model\Model|Builder|null + { + return $this->where('dates',$date)->first(); + } } diff --git a/app/Model/Sku.php b/app/Model/Sku.php new file mode 100644 index 0000000..e8f13d5 --- /dev/null +++ b/app/Model/Sku.php @@ -0,0 +1,44 @@ + 'integer', 'spu_id' => 'integer', 'total_stock' => 'integer', 'surplus_stock' => 'integer', 'sales_num' => 'integer', 'order_num' => 'integer', 'cancel_num' => 'integer', 'ahead_refund_num' => 'integer', 'behind_refund_num' => 'integer', 'saleable' => 'integer']; +} diff --git a/app/Model/Spu.php b/app/Model/Spu.php new file mode 100644 index 0000000..5768e58 --- /dev/null +++ b/app/Model/Spu.php @@ -0,0 +1,63 @@ + 'integer', 'cycle_id' => 'integer', 'city_id' => 'integer', 'kitchen_id' => 'integer','chef_id' => 'integer', 'category_id' => 'integer', 'saleable' => 'integer']; + + const string CREATED_AT = 'create_time'; + const string UPDATED_AT = 'update_time'; + + /** + * @param int $cityId + * @param int $cycleId + * @return Builder|\Hyperf\Database\Model\Model|null + */ + public function getInfoByCityIdAndCycleId(int $cityId, int $cycleId): \Hyperf\Database\Model\Model|Builder|null + { + return $this->where('city_id', $cityId)->where('cycle_id', $cycleId)->first(); + } + + /** + * @param int $id + * @return Builder|\Hyperf\Database\Model\Model|null + */ + public function getInfoById(int $id): \Hyperf\Database\Model\Model|Builder|null + { + return $this->where('id', $id)->first(); + } +} diff --git a/app/Service/Admin/Good/SkuService.php b/app/Service/Admin/Good/SkuService.php new file mode 100644 index 0000000..9e3615d --- /dev/null +++ b/app/Service/Admin/Good/SkuService.php @@ -0,0 +1,21 @@ +userInfo = $this->getUserInfo($this->adminId); + $this->cityId = (int)$this->userInfo['city_id']; + } + + + public function handle() + { + + } + + /** + * @var Cycle + */ + #[Inject] + protected Cycle $cycleModel; + + /** + * 添加 spu + * @return array + */ + public function add(): array + { + $date = $this->request->input('date',date('Y-m-d')); + + $cycleInfo = $this->cycleModel->getInfoByDate($date); + + if (empty($cycleInfo)) throw new ErrException('没有该周期,请刷新后重新上传'); + + $info = $this->spuModel->getInfoByCityIdAndCycleId($this->cityId, $cycleInfo->id); + + if (!empty($info)) throw new ErrException('该菜品在当前城市已存在'); + + $this->checkInfo(); + + $insertModel = new Spu(); + + $insertModel->city_id = $this->cityId; + $insertModel->cycle_id = $cycleInfo->id; + $insertModel->kitchen_id = $this->request->input('kitchen_id'); + $insertModel->chef_id = $this->request->input('chef_id'); + $insertModel->title = $this->request->input('title'); + $insertModel->sub_title = $this->request->input('sub_title',''); + $insertModel->category_id = $this->request->input('category_id'); + $insertModel->saleable = $this->request->input('saleable'); + + if (!$insertModel->save()) throw new ErrException('添加菜品失败'); + + return $this->return->success(); + } + + /** + * @var Kitchen + */ + #[Inject] + protected Kitchen $kitchenModel; + + /** + * @var AdminUser + */ + #[Inject] + protected AdminUser $adminUserModel; + + /** + * 信息检测 + * @return void + */ + private function checkInfo(): void + { + $kitchenId = $this->request->input('kitchen_id'); + $kitchenInfo = $this->kitchenModel->getInfoById($kitchenId); + + if ($kitchenInfo->status == SiteCode::KITCHEN_DISABLE) throw new ErrException('该厨房已禁用'); + + $chefId = $this->request->input('chef_id'); + $chefInfo = $this->adminUserModel->getAdminInfoById($chefId); + + if ($chefInfo->status == UserCode::DISABLE) throw new ErrException('该厨师已禁用'); + } + + /** + * 修改 + * @return array + */ + public function edit(): array + { + $editId = $this->request->input('edit_id'); + + $info = $this->spuModel->getInfoById($editId); + if (empty($info)) throw new ErrException('数据不存在'); + + $this->checkInfo(); + + $info->kitchen_id = $this->request->input('kitchen_id'); + $info->chef_id = $this->request->input('chef_id'); + $info->title = $this->request->input('title'); + $info->sub_title = $this->request->input('sub_title',''); + $info->category_id = $this->request->input('category_id'); + $info->saleable = $this->request->input('saleable'); + + if (!$info->save()) throw new ErrException('修改菜品失败'); + + return $this->return->success(); + } + + /** + * spu 删除 + * @return array + * @throws \Exception + */ + public function del(): array + { + $id = $this->request->input('id'); + + $info = $this->spuModel->getInfoById($id); + if (empty($info)) throw new ErrException('数据已删除'); + + //todo 需要联动删除sku 已经有用户下单sku该怎么办 + + //没有直接删除菜 + $info->delete(); + + return $this->return->success(); + } + + /** + * spu 详情 + * @return array + */ + public function view(): array + { + $id = $this->request->input('id'); + + $info = $this->spuModel->getInfoById($id); + if (empty($info)) throw new ErrException('数据不存在'); + + return $this->return->success('success',$info->toArray()); + } +} \ No newline at end of file diff --git a/sync/http/admin/address.http b/sync/http/admin/address.http index b12b1cd..1562e82 100644 --- a/sync/http/admin/address.http +++ b/sync/http/admin/address.http @@ -8,6 +8,11 @@ account=13632877014&password=123456 client.global.set("admin_token", response.body.data.token); %} +### test +GET {{host}}/admin/third/sts/test +Content-Type: application/x-www-form-urlencoded +Authorization: Bearer {{admin_token}} + ###添加城市 POST {{host}}/admin/city/add