From e996536bf549e02a04dad8b9939e6c085d6e9fef Mon Sep 17 00:00:00 2001 From: ctexthuang Date: Mon, 14 Apr 2025 17:46:06 +0800 Subject: [PATCH] feat : sts --- app/Cache/Redis/Api/ApiRedisKey.php | 10 + app/Cache/Redis/Api/GoodCache.php | 96 ++++++++++ app/Constants/ConfigCode.php | 6 +- app/Controller/Admin/GoodController.php | 8 + app/Controller/Admin/PurchaseController.php | 58 ++++++ app/Model/Purchase.php | 53 +++++ app/Service/Admin/Good/FavorableService.php | 31 +++ app/Service/Admin/Good/PurchaseService.php | 191 +++++++++++++++++++ app/Service/Admin/Good/SkuService.php | 34 +++- app/Service/Api/Good/OptionalListService.php | 11 ++ 10 files changed, 491 insertions(+), 7 deletions(-) create mode 100644 app/Controller/Admin/PurchaseController.php create mode 100644 app/Model/Purchase.php create mode 100644 app/Service/Admin/Good/FavorableService.php create mode 100644 app/Service/Admin/Good/PurchaseService.php diff --git a/app/Cache/Redis/Api/ApiRedisKey.php b/app/Cache/Redis/Api/ApiRedisKey.php index 7b7a690..ff9d98f 100644 --- a/app/Cache/Redis/Api/ApiRedisKey.php +++ b/app/Cache/Redis/Api/ApiRedisKey.php @@ -56,6 +56,16 @@ class ApiRedisKey return 'good:list:stock:cycle_id:'.$cycleId.':kitchen_id:'.$kitchenId; } + /** + * @param int $cycleId + * @param int $kitchenId + * @return string + */ + public static function purchaseGoodListKey(int $cycleId, int $kitchenId): string + { + return 'good:list:purchase:cycle_id:'.$cycleId.':kitchen_id:'.$kitchenId; + } + /** * @param int $userId * @return string diff --git a/app/Cache/Redis/Api/GoodCache.php b/app/Cache/Redis/Api/GoodCache.php index 4a43823..f18b2c1 100644 --- a/app/Cache/Redis/Api/GoodCache.php +++ b/app/Cache/Redis/Api/GoodCache.php @@ -6,6 +6,7 @@ use App\Cache\Redis\RedisCache; use App\Constants\Common\GoodCode; use App\Extend\DateUtil; use App\Model\AdminUser; +use App\Model\Purchase; use App\Model\Sku; use App\Model\Spu; use App\Service\ServiceTrait\Common\OssTrait; @@ -35,6 +36,12 @@ class GoodCache #[Inject] protected Sku $skuModel; + /** + * @var Purchase + */ + #[Inject] + protected Purchase $purchaseModel; + /** * @var int $cycleId */ @@ -61,6 +68,11 @@ class GoodCache */ protected string $mealKey; + /** + * @var string + */ + protected string $purchaseKey; + /** * @var array $stockArr */ @@ -116,6 +128,20 @@ class GoodCache } } + /** + * @return void + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface + */ + private function initPurchaseCacheByCycleId(): void + { + $this->purchaseKey = ApiRedisKey::purchaseGoodListKey($this->cycleId,$this->kitchenId); + + if ($this->checkPurchaseGoodCache()) return; + + $this->setPurchaseGoodCache(); + } + /** * @return void * @throws ContainerExceptionInterface @@ -190,6 +216,30 @@ class GoodCache return $list; } + /** + * @return void + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface + */ + private function setPurchaseGoodCache(): void + { + $list = $this->purchaseModel->getListByCycleIdAndKitchenId($this->cycleId, $this->kitchenId); + + if ($list->isEmpty()) return; + + $list = $list->toArray(); + + $imageIds = array_column($list,'image_id'); + $imageList = $this->getOssObjects($imageIds); + + foreach ($list as &$item) { + $item['url'] = $imageList[$sku['image_id']]['url'] ?? ''; + } + + $this->redis->set($this->purchaseKey, json_encode($list)); + $this->redis->expire($this->purchaseKey,$this->expireTime); + } + /** * @return void * @throws ContainerExceptionInterface @@ -223,6 +273,20 @@ class GoodCache return false; } + /** + * @return bool + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface + */ + private function checkPurchaseGoodCache(): bool + { + if ($this->redis->exists($this->purchaseKey)) return true; + + $this->redis->delete($this->purchaseKey); + + return false; + } + /** * @return bool * @throws ContainerExceptionInterface @@ -257,6 +321,24 @@ class GoodCache return $data; } + /** + * @return mixed + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface + */ + public function getPurchaseGoodList(): mixed + { + $this->initPurchaseCacheByCycleId(); + + $data = $this->redis->get($this->purchaseKey); + + if (empty($data)) return []; + + $data = json_decode($data,true); + + return $data; + } + /** * @param $data * @return mixed @@ -319,4 +401,18 @@ class GoodCache $this->redis->eval($script, $keyArr,count($keyArr)); } + + /** + * @param int $kitchenId + * @param int $cycleId + * @return void + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface + */ + public function delPurchaseCache(int $kitchenId,int $cycleId): void + { + $key = ApiRedisKey::purchaseGoodListKey($cycleId,$kitchenId); + + $this->redis->delete($key); + } } \ No newline at end of file diff --git a/app/Constants/ConfigCode.php b/app/Constants/ConfigCode.php index be4db5c..7b2ead4 100644 --- a/app/Constants/ConfigCode.php +++ b/app/Constants/ConfigCode.php @@ -20,6 +20,8 @@ class ConfigCode const string USER_AGREEMENT = 'UserAgreement'; // 用户使用协议 const string USER_PRIVACY_AGREEMENT = 'UserPrivacyAgreement'; // 用户隐私协议 const string APP_LOGO = 'AppLogo'; // app 图标 + const string ONE_CLICK_SHOPPING_FOR_CATEGORY_NAME = 'OneClickShoppingForCategoryName'; // 一键选购分类名称 + const string ONE_CLICK_SHOPPING_FOR_CATEGORY_IMAGE = 'OneClickShoppingForCategoryImage'; // 一键选购分类图片 /** @@ -52,7 +54,9 @@ class ConfigCode self::BUSINESS_LICENSE => 'https://www.baidu.com', self::USER_AGREEMENT => 'https://www.baidu.com', self::USER_PRIVACY_AGREEMENT => 'https://www.baidu.com', - self::APP_LOGO => 'https://www.baidu.com', + self::APP_LOGO => 0, + self::ONE_CLICK_SHOPPING_FOR_CATEGORY_NAME => '一件选购', + self::ONE_CLICK_SHOPPING_FOR_CATEGORY_IMAGE => 0, //CouponConfiguration self::COUPONS_FOR_NEWCOMERS => '0', self::NEWBIE_COUPON_VALIDITY => '0', diff --git a/app/Controller/Admin/GoodController.php b/app/Controller/Admin/GoodController.php index 9f707ee..eab93fc 100644 --- a/app/Controller/Admin/GoodController.php +++ b/app/Controller/Admin/GoodController.php @@ -10,6 +10,7 @@ use App\Request\Admin\categoryRequest; use App\Request\Admin\GoodRequest; use App\Service\Admin\Good\CategoryService; use App\Service\Admin\Good\CycleService; +use App\Service\Admin\Good\FavorableService; use App\Service\Admin\Good\SkuService; use App\Service\Admin\Good\SpuService; use Exception; @@ -187,4 +188,11 @@ class GoodController extends AbstractController { return (new CategoryService)->add(); } + + + public function addFavorable() + { + //todo + return (new FavorableService())->handle(); + } } diff --git a/app/Controller/Admin/PurchaseController.php b/app/Controller/Admin/PurchaseController.php new file mode 100644 index 0000000..e1a6609 --- /dev/null +++ b/app/Controller/Admin/PurchaseController.php @@ -0,0 +1,58 @@ +add(); + } + + /** + * @return array + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface + */ + #[RequestMapping(path: "del", methods: "GET")] + #[Scene(scene: "del")] + public function del() + { + return (new PurchaseService)->del(); + } + + /** + * @return array + */ + #[RequestMapping(path: "list", methods: "GET")] + #[Scene(scene: "list")] + public function list(): array + { + return (new PurchaseService)->handle(); + } +} diff --git a/app/Model/Purchase.php b/app/Model/Purchase.php new file mode 100644 index 0000000..3b9d68a --- /dev/null +++ b/app/Model/Purchase.php @@ -0,0 +1,53 @@ + 'integer', 'meal_id' => 'integer', 'image_id' => 'integer']; + + const string CREATED_AT = 'create_time'; + const string UPDATED_AT = 'update_time'; + + /** + * @param int $cycleId + * @param int $kitchenId + * @return Builder[]|Collection + */ + public function getListByCycleIdAndKitchenId(int $cycleId, int $kitchenId): Collection|array + { + return $this->where('cycle_id',$cycleId)->where('kitchen_id',$kitchenId)->select('id','name','remark','sku_ids')->get(); + } +} diff --git a/app/Service/Admin/Good/FavorableService.php b/app/Service/Admin/Good/FavorableService.php new file mode 100644 index 0000000..f9a6f77 --- /dev/null +++ b/app/Service/Admin/Good/FavorableService.php @@ -0,0 +1,31 @@ +request->input('sku_id'); + return $this->return->success(); + } +} \ No newline at end of file diff --git a/app/Service/Admin/Good/PurchaseService.php b/app/Service/Admin/Good/PurchaseService.php new file mode 100644 index 0000000..30c4ee1 --- /dev/null +++ b/app/Service/Admin/Good/PurchaseService.php @@ -0,0 +1,191 @@ +request->input('limit', 10); + $cycleId = (int)$this->request->input('cycle_id'); + $kitchenId = (int)$this->request->input('search_kitchen_id'); + $cityId = (int)$this->request->input('search_city_id'); + + $list = $this->spuModel + ->where('cycle_id',$cycleId) + ->where('city_id',$cityId) + ->where('kitchen_id',$kitchenId) + ->paginate($limit) + ->toArray(); + + if (empty($list['data'])) return $this->return->success('success', ['list' => $list]); + + $skuIds = array_unique(explode(',',implode(',',array_column($list['data'],'sku_ids')))); + $skuNameList = $this->skuModel->whereIn('id',$skuIds)->pluck('title','id')->toArray(); + + $imageIds = array_column($list['data'],'image_ids'); + $imageList = $this->getOssObjects($imageIds); + + foreach ($list['data'] as &$one) { + $oneSkuName = []; + foreach (explode(',',$one['sku_ids']) as $skuId) { + $oneSkuName[] = $skuNameList[$skuId] ?? ''; + } + + $one['url'] = $imageList[$one['image_id']]['url'] ?? ''; + $one['sku_name'] = $oneSkuName; + } + + return $this->return->success('success', ['list' => $list]); + } + + /** + * @return array + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface + */ + public function add(): array + { + $cycleId = (int)$this->request->input('cycle_id'); + $kitchenId = (int)$this->request->input('kitchen_id'); + $ids = explode(',', $this->request->input('ids')); + + sort($ids); + + $spuList = $this->spuModel->getListByCycleIdAndType($cycleId, $kitchenId,GoodCode::SPU_TYPE_OPTIONAL); + if ($spuList->isEmpty()) throw new ErrException('今日无菜品数据'); + $spuIds = array_column($spuList->toArray(), 'id'); + $skuList = $this->skuModel->getListBySpuIds($spuIds); + if ($skuList->isEmpty()) throw new ErrException('今日无菜品数据'); + $occupied = array_column($skuList->toArray(), 'occupied','id'); + $skuToSpu = array_column($skuList->toArray(), 'spu_id','id'); + $skuIds = array_keys($skuToSpu); + + $this->check($ids, $skuIds,$skuToSpu,$occupied); + + Db::transaction(function () use ($ids, $cycleId, $kitchenId){ + $insertModel = new Purchase(); + + $insertModel->cycle_id = $cycleId; + $insertModel->kitchen_id = $kitchenId; + $insertModel->city_id = $this->request->input('city_id'); + $insertModel->sku_ids = implode(',', $ids); + $insertModel->image_id = $this->request->input('image_id'); + $insertModel->name = $this->request->input('name'); + $insertModel->remark = $this->request->input('remark'); + + if (!$insertModel->save()) throw new ErrException('添加失败'); + + $this->updateOssObjects([$this->request->input('image_id')]); + }); + + $this->goodCache->delPurchaseCache($kitchenId,$cycleId); + + return $this->return->success(); + } + + /** + * @param array $ids + * @param array $skuIds + * @param array $skuToSpu + * @param array $occupied + * @return void + */ + private function check(array $ids, array $skuIds, array $skuToSpu, array $occupied): void + { + if (empty($ids) || empty($skuIds) || empty($skuToSpu) || empty($occupied)) throw new ErrException('数据异常'); + + $spuArr = []; + $occupiedTwo = 0; + $occupiedOne = 0; + foreach ($ids as $one) { + if (!in_array($one, $skuIds)) throw new ErrException('菜品数据异常-01,添加失败'); + + if (in_array($skuToSpu[$one], $spuArr)) throw new ErrException('不符合四选一的规则,不能重复添加'); + + if (!isset($occupied[$one])) throw new ErrException('菜品数据异常-02,添加失败'); + if ($occupied[$one] == 2) { + $occupiedTwo++; + + if ($occupied > 3) throw new ErrException('不符合目前盒子的规则01,添加失败'); + } elseif ($occupied[$one] == 1) { + $occupiedOne++; + } + + $spuArr[] = $skuToSpu[$one]; + } + + if ($occupiedOne >= (9 - 2 * $occupiedTwo)) throw new ErrException('不符合目前盒子的规则02,添加失败'); + } + + /** + * @var Purchase + */ + #[Inject] + protected Purchase $purchaseModel; + + /** + * @return array + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface + */ + public function del(): array + { + $id = (int)$this->request->input('id'); + + $info = $this->purchaseModel->find($id); + + if (empty($info)) throw new ErrException('数据不存在'); + + $info->delete(); + if (!$info->save()) throw new ErrException('删除失败'); + + $this->goodCache->delPurchaseCache($info->kitchen_id,$info->cycle_id); + + return $this->return->success(); + } +} \ No newline at end of file diff --git a/app/Service/Admin/Good/SkuService.php b/app/Service/Admin/Good/SkuService.php index 3a9eff7..5d08a24 100644 --- a/app/Service/Admin/Good/SkuService.php +++ b/app/Service/Admin/Good/SkuService.php @@ -17,10 +17,12 @@ use App\Constants\Common\GoodCode; use App\Exception\ErrException; use App\Model\AdminUser; use App\Model\Chef; +use App\Model\Purchase; use App\Model\Sku; use App\Model\Spu; use App\Service\Admin\BaseService; use App\Service\ServiceTrait\Common\OssTrait; +use Hyperf\DbConnection\Db; use Hyperf\Di\Annotation\Inject; use Psr\Container\ContainerExceptionInterface; use Psr\Container\NotFoundExceptionInterface; @@ -215,10 +217,14 @@ class SkuService extends BaseService return $this->return->success(); } + /** + * @var Purchase + */ + #[Inject] + protected Purchase $purchaseModel; + /** * @return array - * @throws ContainerExceptionInterface - * @throws NotFoundExceptionInterface */ public function del(): array { @@ -229,12 +235,28 @@ class SkuService extends BaseService $spuInfo = $this->spuModel->getInfoById($skuInfo->spu_id); if (empty($spuInfo)) throw new ErrException('数据出错'); - $skuInfo->is_del = GoodCode::SKU_IS_DELETE; + $purchaseInfo = $this->purchaseModel->getListByCycleIdAndKitchenId($skuInfo->cycle_id,$spuInfo->kitchen_id); + $purchaseIds = []; + if (!empty($purchaseInfo)) { + foreach ($purchaseInfo->toArray() as $one) { + $oneSkuArr = explode(',',$one['sku_ids']); + if (!in_array($skuInfo->id,$oneSkuArr)) continue; - if (!$skuInfo->save()) throw new ErrException('删除失败'); + $purchaseIds = $one['id']; + } + } - //删除缓存 - $this->goodCache->delCache($spuInfo->kitchen_id,$spuInfo->cycle_id); + Db::transaction(function () use ($id,$purchaseIds,$spuInfo,$skuInfo) { + $skuInfo->is_del = GoodCode::SKU_IS_DELETE; + + if (!$skuInfo->save()) throw new ErrException('删除失败'); + + if (!empty($purchaseIds) && !$this->purchaseModel->whereIn('id',$purchaseIds)->delete()) throw new ErrException('删除联动数据失败'); + + //删除缓存 + $this->goodCache->delCache($spuInfo->kitchen_id,$spuInfo->cycle_id); + $this->goodCache->delPurchaseCache($spuInfo->kitchen_id,$spuInfo->cycle_id); + }); return $this->return->success(); } diff --git a/app/Service/Api/Good/OptionalListService.php b/app/Service/Api/Good/OptionalListService.php index 874ce7a..9421c9b 100644 --- a/app/Service/Api/Good/OptionalListService.php +++ b/app/Service/Api/Good/OptionalListService.php @@ -14,6 +14,7 @@ use App\Cache\Redis\Api\ApiRedisKey; use App\Cache\Redis\Api\GoodCache; use App\Cache\Redis\Api\SiteCache; use App\Cache\Redis\RedisCache; +use App\Constants\ConfigCode; use App\Exception\ErrException; use App\Model\Category; use App\Service\Api\BaseService; @@ -87,6 +88,8 @@ class OptionalListService extends BaseService */ private function buildData($data): array { + // 一键选购 + $purchaseData = $this->goodCache->getPurchaseGoodList(); $categoryIds = $this->categoryModel->whereIn('id',array_column($data,'category_id'))->get(); if (empty($categoryIds)) throw new ErrException('数据错误'); @@ -111,6 +114,14 @@ class OptionalListService extends BaseService $res[$item['category_id']]['spu_list'][] = $item; } + if (!empty($purchaseData)) { + array_unshift($res,[ + 'category_name' => $this->configCache->getConfigValueByKey(ConfigCode::ONE_CLICK_SHOPPING_FOR_CATEGORY_NAME), + 'category_image' => $this->getOssObjectById((int)$this->configCache->getConfigValueByKey(ConfigCode::ONE_CLICK_SHOPPING_FOR_CATEGORY_IMAGE)), + 'spu_list' => $purchaseData + ]); + } + return array_values($res); } } \ No newline at end of file