getConnection()->getSchemaBuilder(); $row = $schema->hasTable('sa_water_promotion_setting') ? WaterPromotionSetting::query()->with('sku')->find(1) : null; return [ 'initialized' => $row !== null, 'enabled' => (bool) ($row?->enabled ?? false), 'sku_id' => $row?->sku_id === null ? null : (int) $row->sku_id, 'sku_name' => $row?->sku?->name, 'quantity' => (int) ($row?->quantity ?? 0), 'min_amount_cents' => (int) ($row?->min_amount_cents ?? 0), 'revision' => (int) ($row?->revision ?? 0), 'rules' => self::RULES, ]; } public static function save(array $input, int $actor): array { if (!is_bool($input['enabled'] ?? null)) { throw new ApiException('活动开关必须为布尔值'); } $revision = WaterBusiness::positive($input['revision'] ?? null, '规则版本'); $quantity = WaterBusiness::positive($input['quantity'] ?? null, '奖励桶数', true); $minimum = WaterBusiness::positive($input['min_amount_cents'] ?? null, '首购门槛', true); $sku = WaterBusiness::positive($input['sku_id'] ?? 0, '赠水规格', true); if ($quantity > 10000 || $minimum > 100000000) { throw new ApiException('奖励最多10000桶,首购门槛最多1000000元'); } if ($input['enabled'] && (!$quantity || !$sku)) { throw new ApiException('启用前请选择赠水规格并配置奖励桶数'); } if ($sku && !WaterSku::query()->where('id', $sku)->where('status', 1)->exists()) { throw new ApiException('赠水规格不存在或已停用'); } return WaterModel::transaction(function () use ($input, $actor, $revision, $quantity, $minimum, $sku) { $row = WaterPromotionSetting::query()->lockForUpdate()->find(1); if (!$row || (int) $row->revision !== $revision) { throw new ApiException('规则未初始化或已更新,请刷新后再试'); } $row->fill([ 'enabled' => $input['enabled'], 'sku_id' => $sku ?: null, 'quantity' => $quantity, 'min_amount_cents' => $minimum, 'revision' => $revision + 1, 'updated_by' => $actor, 'updated_at' => date('Y-m-d H:i:s'), ])->save(); WaterLedger::query()->create([ 'kind' => 'promotion_policy', 'created_by' => $actor, 'sku_id' => $sku, 'enterprise_id' => 0, 'quantity' => 0, 'reference' => 'promotion:policy:' . ($revision + 1), 'note' => json_encode($row->toArray(), JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR), 'created_at' => date('Y-m-d H:i:s'), ]); return self::current(); }); } }