false, 'message' => '注入数量必须大于0']; } if (bccomp($price, '0', 5) <= 0) { return ['success' => false, 'message' => '注入价格必须大于0']; } $totalAmount = bcmul($price, $quantity, 5); try { return DB::transaction(function () use ($adminUserId, $itemId, $quantity, $price, $totalAmount, $remark) { // 获取操作前的仓库数量 $warehouse = MexWarehouse::firstOrCreate( ['item_id' => $itemId], [ 'quantity' => 0, 'total_buy_amount' => '0.00000', 'total_sell_amount' => '0.00000', 'total_buy_quantity' => 0, 'total_sell_quantity' => 0, ] ); $beforeQuantity = $warehouse->quantity; // 1. 给仓库账户添加真实物品(确保用户可以买到) $addItemResult = ItemService::addItem(self::WAREHOUSE_USER_ID, $itemId, $quantity, [ 'reason' => 'mex_admin_inject', 'source_type' => REWARD_SOURCE_TYPE::ADMIN_GRANT->value, 'source_id' => $adminUserId, 'remark' => "管理员注入物品到农贸市场,管理员ID:{$adminUserId}" ]); if (!$addItemResult['success']) { throw new \Exception('给仓库账户添加物品失败:' . ($addItemResult['message'] ?? '未知错误')); } // 2. 更新仓库库存统计(注入操作相当于系统买入) $warehouse->quantity += $quantity; $warehouse->total_buy_quantity += $quantity; $warehouse->total_buy_amount = bcadd($warehouse->total_buy_amount, $totalAmount, 5); $warehouse->last_transaction_at = now(); $warehouse->save(); $afterQuantity = $warehouse->quantity; // 创建成交记录 $transaction = MexTransaction::create([ 'buy_order_id' => null, 'sell_order_id' => null, 'buyer_id' => self::WAREHOUSE_USER_ID, // 仓库账户作为买方 'seller_id' => self::CONTROL_USER_ID, // 调控账户作为卖方 'item_id' => $itemId, 'quantity' => $quantity, 'price' => $price, 'total_amount' => $totalAmount, 'transaction_type' => TransactionType::ADMIN_INJECT, 'is_admin_operation' => true, 'admin_user_id' => $adminUserId, ]); // 创建管理员操作记录 $operation = MexAdminOperation::create([ 'admin_user_id' => $adminUserId, 'operation_type' => AdminOperationType::INJECT, 'item_id' => $itemId, 'quantity' => $quantity, 'price' => $price, 'total_amount' => $totalAmount, 'before_warehouse_quantity' => $beforeQuantity, 'after_warehouse_quantity' => $afterQuantity, 'transaction_id' => $transaction->id, 'remark' => $remark, ]); return [ 'success' => true, 'message' => '物品注入成功', 'operation_id' => $operation->id, 'transaction_id' => $transaction->id, 'before_quantity' => $beforeQuantity, 'after_quantity' => $afterQuantity, 'injected_quantity' => $quantity, ]; }); } catch (\Exception $e) { return ['success' => false, 'message' => '物品注入失败:' . $e->getMessage()]; } } /** * 物品回收(减少市场库存) * * @param int $adminUserId 管理员用户ID * @param int $itemId 商品ID * @param int $quantity 数量 * @param string $price 价格 * @param string|null $remark 备注 * @return array 操作结果 */ public static function recycleItem(int $adminUserId, int $itemId, int $quantity, string $price, ?string $remark = null): array { if ($quantity <= 0) { return ['success' => false, 'message' => '回收数量必须大于0']; } if (bccomp($price, '0', 5) <= 0) { return ['success' => false, 'message' => '回收价格必须大于0']; } $totalAmount = bcmul($price, $quantity, 5); try { return DB::transaction(function () use ($adminUserId, $itemId, $quantity, $price, $totalAmount, $remark) { // 检查仓库库存 $warehouse = MexWarehouse::where('item_id', $itemId)->first(); if (!$warehouse || $warehouse->quantity < $quantity) { throw new \Exception('仓库库存不足,无法回收'); } $beforeQuantity = $warehouse->quantity; // 1. 从仓库账户扣除真实物品 $consumeItemResult = ItemService::consumeItem(self::WAREHOUSE_USER_ID, $itemId, null, $quantity, [ 'reason' => 'mex_admin_recycle', 'source_id' => $adminUserId, 'remark' => "管理员从农贸市场回收物品,管理员ID:{$adminUserId}" ]); if (!$consumeItemResult['success']) { throw new \Exception('从仓库账户扣除物品失败:' . ($consumeItemResult['message'] ?? '未知错误')); } // 2. 更新仓库库存统计(回收操作相当于系统卖出) $warehouse->quantity -= $quantity; $warehouse->total_sell_quantity += $quantity; $warehouse->total_sell_amount = bcadd($warehouse->total_sell_amount, $totalAmount, 5); $warehouse->last_transaction_at = now(); $warehouse->save(); $afterQuantity = $warehouse->quantity; // 创建成交记录 $transaction = MexTransaction::create([ 'buy_order_id' => null, 'sell_order_id' => null, 'buyer_id' => self::CONTROL_USER_ID, // 调控账户作为买方 'seller_id' => self::WAREHOUSE_USER_ID, // 仓库账户作为卖方 'item_id' => $itemId, 'quantity' => $quantity, 'price' => $price, 'total_amount' => $totalAmount, 'transaction_type' => TransactionType::ADMIN_RECYCLE, 'is_admin_operation' => true, 'admin_user_id' => $adminUserId, ]); // 创建管理员操作记录 $operation = MexAdminOperation::create([ 'admin_user_id' => $adminUserId, 'operation_type' => AdminOperationType::RECYCLE, 'item_id' => $itemId, 'quantity' => $quantity, 'price' => $price, 'total_amount' => $totalAmount, 'before_warehouse_quantity' => $beforeQuantity, 'after_warehouse_quantity' => $afterQuantity, 'transaction_id' => $transaction->id, 'remark' => $remark, ]); return [ 'success' => true, 'message' => '物品回收成功', 'operation_id' => $operation->id, 'transaction_id' => $transaction->id, 'before_quantity' => $beforeQuantity, 'after_quantity' => $afterQuantity, 'recycled_quantity' => $quantity, ]; }); } catch (\Exception $e) { return ['success' => false, 'message' => '物品回收失败:' . $e->getMessage()]; } } /** * 获取管理员操作记录 * * @param int $page 页码 * @param int $pageSize 每页数量 * @param int|null $adminUserId 管理员用户ID筛选 * @param AdminOperationType|null $operationType 操作类型筛选 * @return array 操作记录列表 */ public static function getAdminOperations(int $page = 1, int $pageSize = 20, ?int $adminUserId = null, ?AdminOperationType $operationType = null): array { $query = MexAdminOperation::query()->orderBy('created_at', 'desc'); if ($adminUserId) { $query->where('admin_user_id', $adminUserId); } if ($operationType) { $query->where('operation_type', $operationType); } $operations = $query->paginate($pageSize, ['*'], 'page', $page); $result = []; foreach ($operations->items() as $operation) { $result[] = [ 'id' => $operation->id, 'admin_user_id' => $operation->admin_user_id, 'operation_type' => $operation->operation_type->value, 'operation_type_desc' => $operation->operation_type->getDescription(), 'item_id' => $operation->item_id, 'quantity' => $operation->quantity, 'price' => $operation->price, 'total_amount' => $operation->total_amount, 'before_warehouse_quantity' => $operation->before_warehouse_quantity, 'after_warehouse_quantity' => $operation->after_warehouse_quantity, 'quantity_change' => $operation->after_warehouse_quantity - $operation->before_warehouse_quantity, 'transaction_id' => $operation->transaction_id, 'remark' => $operation->remark, 'created_at' => $operation->created_at, ]; } return [ 'operations' => $result, 'total' => $operations->total(), 'page' => $page, 'page_size' => $pageSize, ]; } /** * 获取管理员操作统计 * * @param int $days 统计天数 * @return array 统计信息 */ public static function getAdminOperationStats(int $days = 7): array { $startDate = now()->subDays($days)->startOfDay(); $stats = MexAdminOperation::where('created_at', '>=', $startDate) ->selectRaw(' COUNT(*) as total_operations, COUNT(CASE WHEN operation_type = ? THEN 1 END) as inject_count, COUNT(CASE WHEN operation_type = ? THEN 1 END) as recycle_count, SUM(CASE WHEN operation_type = ? THEN quantity ELSE 0 END) as inject_quantity, SUM(CASE WHEN operation_type = ? THEN quantity ELSE 0 END) as recycle_quantity, SUM(CASE WHEN operation_type = ? THEN total_amount ELSE 0 END) as inject_amount, SUM(CASE WHEN operation_type = ? THEN total_amount ELSE 0 END) as recycle_amount, COUNT(DISTINCT admin_user_id) as active_admins, COUNT(DISTINCT item_id) as affected_items ', [ AdminOperationType::INJECT->value, AdminOperationType::RECYCLE->value, AdminOperationType::INJECT->value, AdminOperationType::RECYCLE->value, AdminOperationType::INJECT->value, AdminOperationType::RECYCLE->value, ]) ->first(); return [ 'days' => $days, 'total_operations' => $stats->total_operations ?? 0, 'inject_count' => $stats->inject_count ?? 0, 'recycle_count' => $stats->recycle_count ?? 0, 'inject_quantity' => $stats->inject_quantity ?? 0, 'recycle_quantity' => $stats->recycle_quantity ?? 0, 'inject_amount' => $stats->inject_amount ?? '0.00000', 'recycle_amount' => $stats->recycle_amount ?? '0.00000', 'net_quantity' => ($stats->inject_quantity ?? 0) - ($stats->recycle_quantity ?? 0), 'net_amount' => bcsub($stats->inject_amount ?? '0', $stats->recycle_amount ?? '0', 5), 'active_admins' => $stats->active_admins ?? 0, 'affected_items' => $stats->affected_items ?? 0, 'start_date' => $startDate, 'end_date' => now(), ]; } /** * 初始化库存 * 为所有已启用定价的商品创建库存记录(库存为0) * * @param int $adminUserId 管理员用户ID * @return array 初始化结果 */ public static function initializeWarehouse(int $adminUserId): array { try { return DB::transaction(function () use ($adminUserId) { // 1. 检查是否已有库存记录 $existingWarehouseCount = MexWarehouse::count(); if ($existingWarehouseCount > 0) { return [ 'success' => false, 'message' => '库存表不为空,无法初始化。当前已有 ' . $existingWarehouseCount . ' 条库存记录。' ]; } // 2. 获取所有已启用的定价配置 $priceConfigs = MexPriceConfig::where('is_enabled', true)->get(); if ($priceConfigs->isEmpty()) { return [ 'success' => false, 'message' => '没有找到已启用的定价配置,无法初始化库存。' ]; } $initializedItems = []; $now = now(); // 3. 为每个已定价的商品创建库存记录 foreach ($priceConfigs as $priceConfig) { $warehouse = MexWarehouse::create([ 'item_id' => $priceConfig->item_id, 'quantity' => 0, 'total_buy_amount' => '0.00000', 'total_sell_amount' => '0.00000', 'total_buy_quantity' => 0, 'total_sell_quantity' => 0, 'last_transaction_at' => $now, ]); $initializedItems[] = [ 'item_id' => $priceConfig->item_id, 'min_price' => $priceConfig->min_price, 'max_price' => $priceConfig->max_price, 'warehouse_id' => $warehouse->id, ]; } // 4. 创建管理员操作记录 $operation = MexAdminOperation::create([ 'admin_user_id' => $adminUserId, 'operation_type' => AdminOperationType::INJECT, // 使用注入类型记录初始化操作 'item_id' => 0, // 特殊标记:0表示批量初始化 'quantity' => count($initializedItems), 'price' => '0.00000', 'total_amount' => '0.00000', 'before_warehouse_quantity' => 0, 'after_warehouse_quantity' => 0, 'transaction_id' => null, 'remark' => "初始化农贸市场库存,为 " . count($initializedItems) . " 个商品创建库存记录", ]); return [ 'success' => true, 'message' => '库存初始化成功', 'operation_id' => $operation->id, 'initialized_count' => count($initializedItems), 'initialized_items' => $initializedItems, ]; }); } catch (\Exception $e) { return ['success' => false, 'message' => '库存初始化失败:' . $e->getMessage()]; } } }