[]]], tags: ['SkuOrigins'], parameters: [ new OA\Parameter(name: 'page', in: 'query', required: false, schema: new OA\Schema(type: 'integer', default: 1)), new OA\Parameter(name: 'per_page', in: 'query', required: false, schema: new OA\Schema(type: 'integer', default: 15, maximum: 100)), new OA\Parameter(name: 'company_id', in: 'query', required: false, description: '公司 ID 精确筛选', schema: new OA\Schema(type: 'integer')), new OA\Parameter(name: 'sku', in: 'query', required: false, description: 'SKU 编码模糊搜索', schema: new OA\Schema(type: 'string')), new OA\Parameter(name: 'name', in: 'query', required: false, description: '产品名称模糊搜索', schema: new OA\Schema(type: 'string')), new OA\Parameter(name: 'barcode', in: 'query', required: false, description: '条形码模糊搜索', schema: new OA\Schema(type: 'string')), ], responses: [ new OA\Response( response: 200, description: '获取成功', content: new OA\JsonContent(properties: [ new OA\Property(property: 'code', type: 'integer', example: 0), new OA\Property(property: 'message', type: 'string', example: '获取成功'), new OA\Property(property: 'data', properties: [ new OA\Property(property: 'items', type: 'array', items: new OA\Items(ref: '#/components/schemas/SkuOrigin')), new OA\Property(property: 'total', type: 'integer', example: 100), new OA\Property(property: 'page', type: 'integer', example: 1), new OA\Property(property: 'per_page', type: 'integer', example: 15), ], type: 'object'), ]) ), new OA\Response(response: 401, description: '未认证', content: new OA\JsonContent(ref: '#/components/schemas/ErrorResponse')), new OA\Response(response: 403, description: '无权限', content: new OA\JsonContent(ref: '#/components/schemas/ErrorResponse')), ] )] #[RequestMapping(path: "", methods: "GET")] public function index(): array { $query = SkuOrigin::query()->select([ 'id', 'company_id', 'sku', 'barcode', 'name', 'label', 'hs', 'created_at', 'updated_at', ]); // DataScope 过滤 $this->applyDataScope($query); // 筛选条件 $company_id = $this->request->input('company_id'); if ($company_id !== null && $company_id !== '') { $query->where('company_id', (int) $company_id); } $sku = $this->request->input('sku'); if ($sku !== null && $sku !== '') { $query->where('sku', 'ilike', "%{$sku}%"); } $name = $this->request->input('name'); if ($name !== null && $name !== '') { $query->where(function ($q) use ($name): void { $q->where('name', 'ilike', "%{$name}%") ->orWhere('label', 'ilike', "%{$name}%"); }); } $barcode = $this->request->input('barcode'); if ($barcode !== null && $barcode !== '') { $query->where('barcode', 'ilike', "%{$barcode}%"); } $query->orderBy('created_at', 'desc'); // 分页 $per_page = min(max((int) $this->request->input('per_page', 15), 1), 100); $page = max((int) $this->request->input('page', 1), 1); $total = $query->count(); $items = $query->offset(($page - 1) * $per_page)->limit($per_page)->get(); return [ 'code' => 0, 'message' => '获取成功', 'data' => [ 'items' => $items, 'total' => $total, 'page' => $page, 'per_page' => $per_page, ], ]; } /** * SKU 详情 */ #[OA\Get( path: '/sku-origins/{id}', summary: '客户内部 SKU 详情', security: [['bearerAuth' => []]], tags: ['SkuOrigins'], parameters: [ new OA\Parameter(name: 'id', in: 'path', required: true, schema: new OA\Schema(type: 'integer')), ], responses: [ new OA\Response( response: 200, description: '获取成功', content: new OA\JsonContent(properties: [ new OA\Property(property: 'code', type: 'integer', example: 0), new OA\Property(property: 'message', type: 'string', example: '获取成功'), new OA\Property(property: 'data', ref: '#/components/schemas/SkuOrigin'), ]) ), new OA\Response(response: 404, description: '数据不存在', content: new OA\JsonContent(ref: '#/components/schemas/ErrorResponse')), ] )] #[RequestMapping(path: "{id}", methods: "GET")] public function show(int $id): ResponseInterface|array { $query = SkuOrigin::query(); $this->applyDataScope($query); $record = $query->where('id', $id)->first(); if (!$record) { return $this->response->json([ 'code' => 404, 'message' => '数据不存在', ])->withStatus(404); } return [ 'code' => 0, 'message' => '获取成功', 'data' => $record, ]; } /** * 创建 SKU */ #[OA\Post( path: '/sku-origins', summary: '创建客户内部 SKU', security: [['bearerAuth' => []]], tags: ['SkuOrigins'], requestBody: new OA\RequestBody( required: true, content: new OA\JsonContent( required: ['company_id', 'sku', 'barcode', 'name'], properties: [ new OA\Property(property: 'company_id', type: 'integer', example: 3), new OA\Property(property: 'sku', type: 'string', example: '0032'), new OA\Property(property: 'barcode', type: 'string', example: '6901234567890'), new OA\Property(property: 'name', type: 'string', example: 'Running Shoes Model A'), new OA\Property(property: 'label', type: 'string', nullable: true, example: '跑步鞋 A 款'), new OA\Property(property: 'hs', type: 'string', nullable: true, example: '6403990090'), new OA\Property(property: 'ledger', type: 'string', nullable: true), new OA\Property(property: 'ext', type: 'object', nullable: true), ] ) ), responses: [ new OA\Response( response: 201, description: '创建成功', content: new OA\JsonContent(properties: [ new OA\Property(property: 'code', type: 'integer', example: 0), new OA\Property(property: 'message', type: 'string', example: '创建成功'), new OA\Property(property: 'data', ref: '#/components/schemas/SkuOrigin'), ]) ), new OA\Response(response: 422, description: '参数校验失败', content: new OA\JsonContent(ref: '#/components/schemas/ErrorResponse')), ] )] #[RequestMapping(path: "", methods: "POST")] public function store(): ResponseInterface|array { $data = $this->request->all(); // 参数校验 $required_fields = ['company_id', 'sku', 'barcode', 'name']; foreach ($required_fields as $field) { if (!isset($data[$field]) || $data[$field] === '') { return $this->response->json([ 'code' => 422, 'message' => "缺少必填字段: {$field}", ])->withStatus(422); } } // 唯一性校验 (company_id + sku) $exists = SkuOrigin::query() ->where('company_id', (int) $data['company_id']) ->where('sku', $data['sku']) ->exists(); if ($exists) { return $this->response->json([ 'code' => 422, 'message' => "该公司下 SKU '{$data['sku']}' 已存在", ])->withStatus(422); } $record = SkuOrigin::query()->create([ 'company_id' => (int) $data['company_id'], 'sku' => $data['sku'], 'hs' => $data['hs'] ?? null, 'barcode' => $data['barcode'], 'name' => $data['name'], 'label' => $data['label'] ?? null, 'ledger' => $data['ledger'] ?? null, 'ext' => $data['ext'] ?? null, ]); // 记录操作日志 $user_id = OperationLogService::getCurrentUserId(); if ($user_id) { OperationLogService::log( $user_id, 'create', 'sku_origin', $record->id, "创建内部 SKU: {$record->sku}", ip: $this->request->getHeaderLine('x-real-ip') ?: null, ); } return $this->response->json([ 'code' => 0, 'message' => '创建成功', 'data' => $record, ])->withStatus(201); } /** * 更新 SKU */ #[OA\Put( path: '/sku-origins/{id}', summary: '更新客户内部 SKU', security: [['bearerAuth' => []]], tags: ['SkuOrigins'], parameters: [ new OA\Parameter(name: 'id', in: 'path', required: true, schema: new OA\Schema(type: 'integer')), ], requestBody: new OA\RequestBody( required: true, content: new OA\JsonContent(properties: [ new OA\Property(property: 'sku', type: 'string'), new OA\Property(property: 'barcode', type: 'string'), new OA\Property(property: 'name', type: 'string'), new OA\Property(property: 'label', type: 'string', nullable: true), new OA\Property(property: 'hs', type: 'string', nullable: true), new OA\Property(property: 'ledger', type: 'string', nullable: true), new OA\Property(property: 'ext', type: 'object', nullable: true), ]) ), responses: [ new OA\Response( response: 200, description: '更新成功', content: new OA\JsonContent(properties: [ new OA\Property(property: 'code', type: 'integer', example: 0), new OA\Property(property: 'message', type: 'string', example: '更新成功'), new OA\Property(property: 'data', ref: '#/components/schemas/SkuOrigin'), ]) ), new OA\Response(response: 404, description: '数据不存在', content: new OA\JsonContent(ref: '#/components/schemas/ErrorResponse')), new OA\Response(response: 422, description: '参数校验失败', content: new OA\JsonContent(ref: '#/components/schemas/ErrorResponse')), ] )] #[RequestMapping(path: "{id}", methods: "PUT")] public function update(int $id): ResponseInterface|array { $query = SkuOrigin::query(); $this->applyDataScope($query); $record = $query->where('id', $id)->first(); if (!$record) { return $this->response->json([ 'code' => 404, 'message' => '数据不存在', ])->withStatus(404); } $data = $this->request->all(); $allowed_fields = ['sku', 'barcode', 'name', 'label', 'hs', 'ledger', 'ext']; $update_data = array_intersect_key($data, array_flip($allowed_fields)); // 如果修改了 sku,检查唯一性 if (isset($update_data['sku']) && $update_data['sku'] !== $record->sku) { $exists = SkuOrigin::query() ->where('company_id', $record->company_id) ->where('sku', $update_data['sku']) ->where('id', '!=', $id) ->exists(); if ($exists) { return $this->response->json([ 'code' => 422, 'message' => "该公司下 SKU '{$update_data['sku']}' 已存在", ])->withStatus(422); } } $record->update($update_data); $user_id = OperationLogService::getCurrentUserId(); if ($user_id) { OperationLogService::log( $user_id, 'update', 'sku_origin', $record->id, "更新内部 SKU: {$record->sku}", detail: ['updated_fields' => array_keys($update_data)], ip: $this->request->getHeaderLine('x-real-ip') ?: null, ); } return [ 'code' => 0, 'message' => '更新成功', 'data' => $record->fresh(), ]; } /** * 删除 SKU */ #[OA\Delete( path: '/sku-origins/{id}', summary: '删除客户内部 SKU', description: '删除前检查是否有映射引用,有引用时禁止删除', security: [['bearerAuth' => []]], tags: ['SkuOrigins'], parameters: [ new OA\Parameter(name: 'id', in: 'path', required: true, schema: new OA\Schema(type: 'integer')), ], responses: [ new OA\Response( response: 200, description: '删除成功', content: new OA\JsonContent(properties: [ new OA\Property(property: 'code', type: 'integer', example: 0), new OA\Property(property: 'message', type: 'string', example: '删除成功'), ]) ), new OA\Response(response: 404, description: '数据不存在', content: new OA\JsonContent(ref: '#/components/schemas/ErrorResponse')), new OA\Response(response: 409, description: '存在映射引用', content: new OA\JsonContent(ref: '#/components/schemas/ErrorResponse')), ] )] #[RequestMapping(path: "{id}", methods: "DELETE")] public function destroy(int $id): ResponseInterface|array { $query = SkuOrigin::query(); $this->applyDataScope($query); $record = $query->where('id', $id)->first(); if (!$record) { return $this->response->json([ 'code' => 404, 'message' => '数据不存在', ])->withStatus(404); } // 检查映射引用 if ($this->skuService->hasReferences($id)) { return $this->response->json([ 'code' => 409, 'message' => '该 SKU 存在映射引用,请先删除相关映射记录', ])->withStatus(409); } $sku_value = $record->sku; $record->delete(); $user_id = OperationLogService::getCurrentUserId(); if ($user_id) { OperationLogService::log( $user_id, 'delete', 'sku_origin', $id, "删除内部 SKU: {$sku_value}", ip: $this->request->getHeaderLine('x-real-ip') ?: null, ); } return [ 'code' => 0, 'message' => '删除成功', ]; } /** * DataScope 过滤(基于 company_id) */ private function applyDataScope(\Hyperf\Database\Model\Builder $query): void { $scope_type = $this->request->getAttribute('scope_type'); $scope_ids = $this->request->getAttribute('scope_ids', []); if ($scope_type === 'store') { $company_ids = \App\Model\Store::query() ->whereIn('id', $scope_ids) ->distinct() ->pluck('company_id') ->toArray(); $query->whereIn('company_id', $company_ids); } elseif ($scope_type === 'platform') { $company_ids = \App\Model\Store::query() ->whereIn('platform_id', $scope_ids) ->distinct() ->pluck('company_id') ->toArray(); $query->whereIn('company_id', $company_ids); } } }