'desc', 'id' => 'desc']; $type = $params['type'] ?? '';//type为空时 默认为商品管理 包含除积分商品外所有类型 if (!empty($type)) { $whereMap[] = ['activity_type', '=', $type]; } switch ($type) { case Spu::TYPE_NORMAL: $whereMap[] = ['is_activity', '=', Spu::COMMON_OFF]; $whereMap[] = ['is_score', '=', Spu::COMMON_OFF]; break; case Spu::TYPE_SCORE: $whereMap[] = ['is_activity', '=', Spu::COMMON_OFF]; $whereMap[] = ['is_score', '=', Spu::COMMON_ON]; break; case Spu::TYPE_GROUP_MAKE: case Spu::TYPE_GROUP_BUY: case Spu::TYPE_LIMIT_TIME: $whereMap[] = ['is_activity', '=', Spu::COMMON_ON]; $whereMap[] = ['is_score', '=', Spu::COMMON_OFF]; break; default: $whereMap[] = ['is_score', '=', Spu::COMMON_OFF]; // $whereMap[] = ['is_activity', '=', Spu::COMMON_OFF]; } if (isset($params['saleable'])) { $whereMap[] = ['saleable', '=', $params['saleable']]; } if (isset($params['keyword']) && !empty($params['keyword'])) { $whereMap[] = ['name|subtitle', 'like', '%'.$params['keyword'].'%']; } if (isset($params['spu_type']) && !empty($params['spu_type'])) { $whereMap[] = ['spu_type', '=', $params['spu_type']]; } $whereMap[] = ['deleted_at', '=', null]; $params['page'] = $params['page'] ?? 1; $params['size'] = $params['size'] ?? 20; $fields = $params['fields'] ?? []; return Spu::findList($whereMap, $fields, $params['page'], $params['size'], null, $order); } /** * 获取活动商品列表【后台使用】 * * @param array $params * @return array * @throws Exception */ public function activityList(array $params = []): array { $whereMap = []; $order = $params['order'] ?? ['sort' => 'desc', 'id' => 'desc']; $type = $params['type'] ?? '';//type为空时 默认为商品管理 包含除积分商品外所有类型 if (!empty($type)) { $whereMap[] = ['activity_type', '=', $type]; } if (isset($params['saleable'])) { $whereMap[] = ['saleable', '=', $params['saleable']]; } if (isset($params['keyword']) && !empty($params['keyword'])) { $whereMap[] = ['name|subtitle', 'like', '%'.$params['keyword'].'%']; } if (isset($params['spu_type']) && !empty($params['spu_type'])) { $whereMap[] = ['spu_type', '=', $params['spu_type']]; } $whereMap[] = ['deleted_at', '=', null]; $params['page'] = $params['page'] ?? 1; $params['size'] = $params['size'] ?? 20; $fields = $params['fields'] ?? []; return SpuActivity::findList($whereMap, $fields, $params['page'], $params['size'], null, $order); } /** * 前端商品列表 * * @throws Exception */ public function listForFront(array $params = [], callable $callback = null, array $order = [], array $where = []): array { $page = $params['page'] ?? 1; $size = $params['size'] ?? 0; $page = (!is_numeric($page) || $page <= 0) ? 1 : $page; $size = (!is_numeric($size) || $size <= 0) ? 10 : $size; $size = 0; event('SpuCheck'); $searchMap = $where; // 商品名称模糊搜索 if (isset($params['keyword']) && !empty($params['keyword'])) { $searchMap[] = ['name', 'like', '%'.$params['keyword'].'%']; } // 活动类型搜索 if (isset($params['activity']) && !empty($params['activity'])) { $searchMap[] = ['activity_type', 'in', explode(',', $params['activity'])]; if (!in_array($params['activity'], [Spu::TYPE_NORMAL, Spu::TYPE_SCORE])) { $searchMap[] = ['is_activity', '=', Spu::COMMON_ON]; } } // 价格区间开始 if (isset($params['price_from']) && is_numeric($params['price_from'])) { $searchMap[] = ['price', '>=', $params['price_from']]; } // 价格区间结束 if (isset($params['price_to']) && is_numeric($params['price_to'])) { $searchMap[] = ['price', '<=', $params['price_to']]; } $searchMap[] = ['saleable', '=', Spu::COMMON_ON]; // 是否积分 if (isset($params['is_score'])) { $searchMap[] = ['is_score', '=', $params['is_score']]; } // 是否热门 if (isset($params['is_hot'])) { $searchMap[] = ['is_hot', '=', $params['is_hot']]; } // 是否推荐到首页 if (isset($params['is_home']) && in_array($params['is_home'], [0, 1])) { $searchMap[] = ['is_home', '=', $params['is_home']]; } // 指定分类 if (isset($params['category_id']) && !empty($params['category_id'])) { // 多个分类逗号分割 $spuIds = SpuCategoryPivot::whereIn('category_id', explode(',', $params['category_id']))->column('spu_id'); if ($spuIds) { $searchMap[] = ['id', 'in', array_unique($spuIds)]; }else{ $searchMap[] = ['id', '=', 0]; } } $fields = $params['fields'] ?? ['id', 'name', 'price', 'original_price', 'cover', 'activity_type']; if (empty($order)) { $order = ['published_at' => 'desc']; } $list = Spu::findList($searchMap, $fields, $page, $size, $callback, $order); $activityText = Spu::activityTextList(); $list['list'] = $list['list']->each(function ($item) use ($activityText) { $spuSkuList = $this->spuSkuList($item->id); $item->skuId = $spuSkuList[0]["id"] ?? 0; $item->tag = $activityText[$item->activity_type] ?? ''; }); return $list; } /** * 内容详情 * * @param int $id * @param int $accountId * @return array * @throws DataNotFoundException * @throws DbException * @throws ModelNotFoundException * @throws RepositoryException * @throws Exception */ public function detail(int $id, int $accountId = 0): array { $field = [ 'id', 'activity_id', 'activity_type', 'name', 'subtitle', 'price', 'original_price', 'unit','limit_num', 'cover', 'images', 'share_img', 'is_activity', 'stock', 'amount', 'multi_spec', 'content' ]; if (!$spu = $this->findById($id, $field)) { throw new RepositoryException('数据不存在'); } $spu = $spu->toArray(); if ($spu['is_activity'] == Spu::COMMON_ON) { switch ($spu['activity_type']) { case SpuLimitTime::TYPE: $activityInfo = SpuLimitTime::findById($spu['activity_id']); break; default: $activityInfo = null; } if (!$activityInfo) { throw new RepositoryException('活动不存在'); } if ($activityInfo['status'] != Spu::COMMON_ON) { throw new RepositoryException('活动已下架'); } $now = date('Y-m-d H:i:s'); if ($activityInfo['end_at'] < $now || $activityInfo['begin_at'] > $now) { throw new RepositoryException('不在活动时间内'); } $spu['name'] = $activityInfo['name']; $spu['subtitle'] = $activityInfo['subtitle']; $spu['begin_at'] = $activityInfo['begin_at']; $spu['end_at'] = $activityInfo['end_at']; } if (isset($spu['is_score']) && $spu['is_score']) { $spu['activity_type'] = Spu::TYPE_NORMAL; } $spu['activity_text'] = ''; $spu['tag'] = ''; // 活动标签 if ($spu['is_activity'] && isset($spu['activity_type'])) { $spu['activity_text'] = Spu::activityTextList()[$spu['activity_type']] ?? ''; $spu['tag'] = Spu::activityTextList()[$spu['activity_type']] ?? ''; } // 规格列表 $skuList = $spu['is_activity'] == Spu::COMMON_ON ? $this->spuSkuList($spu['activity_id'], $spu['activity_type'], true) : $this->spuSkuList($id); if ($spu['is_activity'] == Spu::COMMON_ON) { $default = $skuList->where('is_default', Spu::COMMON_ON)->first(); $spu['original_price'] = $spu['price']; $spu['price'] = $default['price']; } $spu["skuId"] = $skuList[0]["id"] ?? 0; $res['detail'] = $spu; // $res['sku'] = $skuList; return $res; } /** * 获取商品规格列表 * * @param int $id ID * @param string $activityType 活动类型 normal=普通 limit_time=限时折扣 * @param bool $isActivity 是否活动 * @return Sku[]|array|Collection * @throws DataNotFoundException * @throws DbException * @throws ModelNotFoundException */ public function spuSkuList(int $id, string $activityType = Spu::TYPE_NORMAL, bool $isActivity = false) { $skuFields = ['id', 'coding', 'title', 'stock', 'price', 'original_price', 'score', 'is_default']; $where = []; $where[] = ['type', '=', $activityType]; if ($isActivity) { $where[] = ['spu_activity_id', '=', $id]; } else { $where[] = ['spu_id', '=', $id]; } return Sku::where($where)->field($skuFields)->select(); } /** * 获取商品 相关产品推荐 * * @param int $spuId * @param bool $isScore 是否积分商品 * @param int $page * @param int $size * @return mixed * @throws Exception */ public function spuProduct(int $spuId, bool $isScore = false, int $page = 1, int $size = 10) { $params = []; $params['is_score'] = $isScore; $params['page'] = $page; $params['size'] = $size; $params['fields'] = $isScore ? Spu::scoreListFields() : Spu::spuListFields(); return $this->listForFront($params, function ($q) use ($spuId) { return $q->where('id', '<>', $spuId)->order('published_at', 'desc'); })['list']; } /** * 添加SPU商品信息 * * @param array $data 基础信息 * @param array $sku 规格信息 * @return Model * @throws RepositoryException */ public function addSpu(array $data, array $sku): Model { Db::startTrans(); try { $now = date('Y-m-d H:i:s'); $data['saleable'] = $data['saleable'] ?? Spu::COMMON_ON; $data['published_at'] = $data['published_at'] ?? $now; $data['created_at'] = $now; if (isset($data['init_amount']) && $data['init_amount'] > 0) { $data['amount'] += $data['init_amount']; } $categoryIds = $data['category_id'] ?? ''; $categoryIds = explode(',', $categoryIds); $multiSpec = (bool) $data['multi_spec']; $spu = $this->create($data); $skuData = $this->handleSku($spu['id'], $sku, [], 'normal', $multiSpec); (new Sku())->saveAll($skuData['data']); $spu->save([ 'stock' => $skuData['stock'], 'price' => $skuData['price'], 'original_price' => $skuData['original_price'], 'score' => $skuData['score'], 'spec' => json_encode($skuData['spec'], JSON_UNESCAPED_UNICODE) ]); // 中间表 $this->setCategory($spu->id, $categoryIds); Db::commit(); return $spu; } catch (RepositoryException $e) { // 回滚事务 Db::rollback(); throw $e; } catch (Exception $e) { SpuRepository::log($e->getMessage(), $e); // 回滚事务 Db::rollback(); throw new RepositoryException('商品创建失败'); } } /** * 编辑商品信息 * * @param int $id * @param array $data 基础信息 * @param array $sku 规格信息 * @param array $originalSkuList 原始规格列表 * @throws RepositoryException */ public function editSpu(int $id, array $data, array $sku, array $originalSkuList) { Db::startTrans(); try { $spu = $this->findById($id); if (empty($spu)) { throw new RepositoryException('没有相关的商品记录'); } if (isset($data['init_amount']) && $data['init_amount'] > 0) { $data['amount'] = $spu['amount'] - $spu['init_amount']; $data['amount'] = $data['amount'] > 0 ? $data['amount'] : 0; $data['amount'] += $data['init_amount']; } $now = date('Y-m-d H:i:s'); $data['saleable'] = $data['saleable'] ?? Spu::COMMON_ON; $data['published_at'] = $data['published_at'] ?? $now; $data['updated_at'] = $now; $categoryIds = $data['category_id'] ?? ''; $categoryIds = explode(',', $categoryIds); $multiSpec = (bool) $data['multi_spec']; $skuData = $this->handleSku($id, $sku, array_column($originalSkuList, 'id'), 'normal', $multiSpec); (new Sku())->saveAll($skuData['data']); (new Sku())->where('id', 'in', $skuData['delete'])->delete(); $data['stock'] = $skuData['stock']; $data['price'] = $skuData['price']; $data['original_price'] = $skuData['original_price']; $data['score'] = $skuData['score']; $data['spec'] = json_encode($skuData['spec'], JSON_UNESCAPED_UNICODE); $spu->save($data); $this->setCategory($id, $categoryIds); Db::commit(); } catch (RepositoryException $e) { // 回滚事务 Db::rollback(); throw $e; } catch (Exception $e) { // 回滚事务 Db::rollback(); throw new RepositoryException('商品信息修改失败'); } } /** * 删除SPU商品信息 软删除 * * @param array $ids * @return bool * @throws RepositoryException */ public function deleteSpu(array $ids): bool { try { return $this->model->whereIn('id', $ids)->save(['deleted_at' => date('Y-m-d H:i:s')]); } catch (Exception $e) { throw new RepositoryException('删除失败'.$e->getMessage()); } } /** * 处理SKU数据 * * @param int $id spu_id或spu_activity_id * @param array $data * @param array $originalSkuIds 原始skuID列表 * @param string $type normal=普通商品 limit_time=限时折扣 * @param bool $isMulti 是否多规格 默认是· * @return array * @throws RepositoryException */ public function handleSku(int $id, array $data, array $originalSkuIds = [], string $type = 'normal', bool $isMulti = true): array { if (empty($data)) { throw new RepositoryException('规格不能为空'); } $stock = 0;//总库存 $defaultNum = 0;//默认规格数量 $defaultPrice = 0;//默认规格价格 $defaultOriginalPrice = 0;//默认规格原价 $defaultScore = 0;//默认规格积分 $deleteIds = array_diff($originalSkuIds, array_column($data, 'id'));;//待删除待skuID列表 // 获取所有规格值及其相关规格 $specValueList = SpecValue::alias('sv')->leftJoin('spec_param sp', 'sv.spec_id = sp.id') ->where('sv.status', SpecValue::COMMON_ON) ->where('sp.status', SpecParam::COMMON_ON) ->field('sv.id as value_id, sv.title as value_title, sv.spec_id,sp.title as spec_title') ->order('sv.sort', 'desc') ->order('sv.id', 'asc') ->select(); $valueKvList = $isMulti ? $specValueList->column('value_title', 'value_id') : []; $value2Spec = $isMulti ? $specValueList->column('spec_id', 'value_id') : []; $value2SpecTitle = $isMulti ? $specValueList->column('spec_title', 'value_id') : []; $specValueIds = [];// 该商品启用的规格值 // 验证规格 foreach ($data as $key => &$spec) { // ID为空的表示新增 去掉id字段 saveAll时 自动识别更新或新增 if (empty($spec['id'])) { unset($spec['id']); } if ($isMulti) { $keys = explode('-', $key); $spec['indexes'] = $key; $spec['title'] = ''; $specText = []; $specValueIds = array_merge($specValueIds, $keys); foreach ($keys as $k) { $spec['title'] .= ' '.($valueKvList[$k] ?? ''); $specText[] = [$value2SpecTitle[$k] => $valueKvList[$k]]; } $spec['spec_text'] = json_encode($specText, JSON_UNESCAPED_UNICODE); } if (!isset($spec['stock']) || !isset($spec['is_default'])) { throw new RepositoryException('规格信息不完整'); } if (empty($spec['stock'])) { throw new RepositoryException('请填写库存'); } $spec['price'] = $spec['original_price'] ?? 0; if (isset($spec['price']) && $spec['price'] < 0) { throw new RepositoryException('规格价格必须大于等于0'); } if (!isset($spec['price']) && !isset($spec['score'])) { throw new RepositoryException('规格价格|积分不能为空'); } $spec['original_price'] = $spec['original_price'] ?: $spec['price']; if ($spec['is_default'] == 1) { $defaultNum += 1; $defaultPrice = $spec['price']; $defaultOriginalPrice = $spec['original_price']; $defaultScore = $spec['score'] ?? 0; } if ($type == 'normal') { if (!isset($spec['spu_id'])) { $spec['spu_id'] = $id; } } else { if (!isset($spec['spu_activity_id'])) { $spec['spu_activity_id'] = $id; } $spec['type'] = $type; } if (!isset($spec['coding']) || empty($spec['coding'])) { $spec['coding'] = generateCode(); } $stock += $spec['stock']; } $specInfo = [];// 该商品的启用的规格及其规格值 $specValueIds = array_unique($specValueIds); foreach ($specValueIds as $valueId) { $specId = $value2Spec[$valueId] ?? 0; if ($specId > 0 && !isset($specInfo[$specId])) { $specInfo[$specId] = []; } $specInfo[$specId][] = $valueId; } if ($defaultNum !== 1) { throw new RepositoryException('默认规格有且仅有一个'); } return [ 'data' => $data, 'stock' => $stock, 'price' => $defaultPrice, 'original_price' => $defaultOriginalPrice, 'score' => $defaultScore, 'delete' => $deleteIds, 'spec' => $specInfo ]; } /** * 添加SPU活动商品信息 * * @param string $type * @param array $data 活动基础信息 * @param int $spuId * @param array $sku 规格信息 * @return Model * @throws RepositoryException */ public function addActivity(string $type, array $data, int $spuId, array $sku): Model { Db::startTrans(); try { if (!$spu = Spu::findById($spuId)) { throw new RepositoryException('商品不存在'); } $insert = $spu->toArray(); unset($insert['id']); $allowFields = [ 'name', 'subtitle', 'saleable', 'price', 'original_price', 'score', 'level_id', 'is_hot', 'has_postage', 'cover', 'images', 'share_img', 'video', 'spu_type', 'content', 'views', ]; $now = date('Y-m-d H:i:s'); $insert = arrayKeysFilter($insert, $allowFields); $insert['activity_type'] = $type; $insert['cover'] = $data['cover'] ?: $insert['cover']; $insert['activity_begin_at'] = $data['activity_begin_at']; $insert['activity_end_at'] = $data['activity_end_at']; $insert['limit_time'] = $data['limit_time'] ?? 0; $insert['limit_num'] = $data['limit_num'] ?? 0; $insert['group_base_num'] = $data['group_base_num'] ?? 0; $insert['group_num'] = $data['group_num'] ?? 0; $insert['group_time'] = $data['group_time'] ?? 0; $insert['virtual_group'] = $data['virtual_group'] ?? 0; $insert['open_one'] = $data['open_one'] ?? 0; $insert['amount'] = 0;//销量设为0 $insert['spu_id'] = $spuId; $insert['created_at'] = $now; $insert['updated_at'] = $now; $insert['published_at'] = $now; $spuActivity = SpuActivity::create($insert); $spu->save([ 'activity_id' => $spuActivity['id'], 'is_activity' => Spu::COMMON_ON, 'activity_type' => $type, ]); $skuData = $this->handleSku($spuActivity['id'], $sku, [], 'activity'); (new Sku())->saveAll($skuData['data']); $spuActivity->save([ 'stock' => $skuData['stock'], 'price' => $skuData['price'], 'original_price' => $skuData['original_price'], 'score' => $skuData['score'], ]); Db::commit(); return $spu; } catch (RepositoryException $e) { // 回滚事务 Db::rollback(); throw $e; } catch (Exception $e) { SpuRepository::log($e->getMessage(), $e); // 回滚事务 Db::rollback(); throw new RepositoryException('活动商品创建失败'); } } /** * 编辑活动商品信息 * * @param int $id * @param array $data 基础信息 * @param array $sku 规格信息 * @param array $originalSkuList 原始规格列表 * @throws RepositoryException */ public function editActivity(int $id, array $data, array $sku, array $originalSkuList) { Db::startTrans(); try { if (!$spuActivity = SpuActivity::findById($id)) { throw new RepositoryException('没有相关的活动商品记录'); } $now = date('Y-m-d H:i:s'); $data['updated_at'] = $now; $skuData = $this->handleSku($id, $sku, array_column($originalSkuList, 'id'), 'activity'); (new Sku())->saveAll($skuData['data']); (new Sku())->where('id', 'in', $skuData['delete'])->delete(); $data['stock'] = $skuData['stock']; $data['price'] = $skuData['price']; $data['original_price'] = $skuData['original_price']; $data['score'] = $skuData['score']; $spuActivity->save($data); Db::commit(); } catch (RepositoryException $e) { // 回滚事务 Db::rollback(); throw $e; } catch (Exception $e) { // 回滚事务 Db::rollback(); throw new RepositoryException('活动商品信息修改失败'.$e->getLine()); } } /** * 获取活动商品的订单列表 * * @throws Exception */ public function getActivityOrderList(int $activityId, string $type = Spu::TYPE_LIMIT_TIME, int $page = 1, int $size = 0): array { $where = []; $where[] = ['spu_activity_id', '=', $activityId]; $where[] = ['deleted_at', '=', null]; $where[] = ['type', '=', $type]; $res = OrderActivity::findList($where, [], $page, $size, function ($q) { return $q->with(['orderInfo', 'account']); }, ['id' => 'desc']); $res['list'] = $res['list']->each(function ($item) { $item->activity_text = Spu::activityTextList()[$item->activity_type] ?? ''; $item->created_at = $item->orderInfo->created_at ?? ''; $item->phone = $item->orderInfo->phone ?? ''; $item->status = $item->orderInfo->status ?? ''; $item->status_text = Order::statusTextList()[$item->status] ?? ''; $item->nickname = $item->account->nickname ?? ''; $item->real_name = $item->account->real_name ?? ''; }); return $res; } /** * 商品分类 构造xmSelect 需要的数据[xmSelect使用时需要json_encode处理] * * @param array $selected * @param array $disabled * @param bool $excludeParent 拥有下级的节点是否不可勾选 默认false * @return array * @throws DataNotFoundException * @throws DbException * @throws ModelNotFoundException */ public function categoryXmSelect(array $selected = [], array $disabled = [], bool $excludeParent = false): array { $category = Category::order('sort', 'desc') ->field('id,pid,title') ->select()->toArray(); foreach ($category as $k => $m) { $category[$k]['selected'] = in_array($m['id'], $selected); $category[$k]['disabled'] = in_array($m['id'], $disabled); } $category = CmsRepository::getInstance()->buildMenuChild(0, $category, 'children', $excludeParent); return CmsRepository::getInstance()->handleSelectedList($category); } /** * 商品分类 * * @param int $pid * @param array $fields * @return Category[]|array|Collection * @throws DataNotFoundException * @throws DbException * @throws ModelNotFoundException */ public function category(int $pid = 0, array $fields = ['id', 'title']) { return Category::where('pid', $pid) ->field($fields) ->order('sort', 'desc') ->order('id', 'asc') ->withAttr("cover",function ($value){ return resourceJoin($value,request()->domain()); }) ->select(); } public function categoryAll(array $fields = ['id', 'title']) { $list = Category::field($fields) ->order('sort', 'desc') ->order('id', 'asc') ->select() ->withAttr("cover",function ($value){ return resourceJoin($value,request()->domain()); }) ->toArray(); return list_to_tree($list); } /** * 设置商品分类 * * @param int $spuId * @param array $categoryIds */ public function setCategory(int $spuId, array $categoryIds) { SpuCategoryPivot::where('spu_id', $spuId)->delete(); if ($categoryIds) { $insert = []; foreach ($categoryIds as $categoryId) { $insert[] = [ 'spu_id' => $spuId, 'category_id' => $categoryId ]; } (new SpuCategoryPivot())->insertAll($insert); } } /** * 获取商品分类ID列表 * * @param int $spuId * @return array */ public function getCategoryIdList(int $spuId): array { return SpuCategoryPivot::where('spu_id', $spuId)->column('category_id'); } /** * 获取商品规格信息 * * @param int $spuId * @return array * @throws DataNotFoundException * @throws DbException * @throws ModelNotFoundException * @throws RepositoryException */ public function getSpec(int $spuId): array { if (!$spu = Spu::findById($spuId)) { throw new RepositoryException('商品不存在'); } $res = []; if ($spu['is_activity'] == Spu::COMMON_ON) { $where[] = ['spu_activity_id', '=', $spu['activity_id']]; $where[] = ['type', '=', $spu['activity_type']]; } else { $where[] = ['spu_id', '=', $spuId]; } $fields = ['id', 'spu_id', 'indexes', 'title', 'coding', 'stock', 'price', 'original_price', 'is_default']; $skuList = Sku::where($where)->field($fields)->select(); $res['sku_list'] = $skuList;//SKU列表 $res['sku'] = $skuList->where('is_default', Sku::COMMON_ON)->first();//默认SKU $res['spec'] = [];//规格 if ($spu['multi_spec'] > 0) { $spec = json_decode($spu['spec'], true); $specIds = array_keys($spec); $valueIds = []; foreach (array_values($spec) as $arr) { $valueIds = array_merge($valueIds, $arr); } $specList = SpecParam::whereIn('id', $specIds)->order('sort', 'desc')->order('id', 'asc')->select()->toArray(); $specValueList = SpecValue::whereIn('id', $valueIds)->order('sort', 'desc')->order('id', 'asc')->select()->toArray(); foreach ($specList as $sl) { $arr = []; $arr['id'] = $sl['id']; $arr['title'] = $sl['title']; $children = []; foreach ($specValueList as $vl) { if ($vl['spec_id'] == $sl['id']) { $children[] = [ 'id' => $vl['id'], 'title' => $vl['title'], ]; } } $arr['children'] = $children; $res['spec'][] = $arr; } } return $res; } /** * [{"颜色": "红色"},{"尺寸": "L"}] 转成 ["颜色:红色","尺寸:L"] * * @param $specArr * @return array */ public function convertSpecInfo($specArr): array { if (!$specArr) { return []; } $arr = []; foreach ($specArr as $s) { $k = key($s); $arr[] = sprintf("%s:%s", $k, $s[$k] ?? ''); } return $arr; } }