model = AiApiKeyModel::class; $this->selectField = ['id', 'platform_id', 'name', 'remark', 'is_default', 'status', 'sort', 'created_at', 'updated_at']; $this->queryField = [ 'platform_id' => '=', 'name' => 'like', 'status' => '=', ]; $this->orderBy = [ 'name' => 'sort', 'sort' => 'desc', ]; } /** * 获取 AI 管理页选项(平台卡片 + 当前激活组合) */ public function getRuntimeOptions(): array { return AiRuntimeConfigService::getInstance()->optionsForConfig(); } /** * 保存默认平台/模型/密钥 */ public function saveRuntime(array $params): array { $provider = (string) ($params['provider'] ?? ''); $model = (string) ($params['model'] ?? ''); $apiKeyId = (int) ($params['api_key_id'] ?? 0); return AiRuntimeConfigService::getInstance()->saveActiveConfig($provider, $model, $apiKeyId); } /** * 密钥列表(卡片展示用,不返回明文密钥) * 直接查表,避免单例 where 被 update 污染导致列表为空 */ public function listKeys(): array { $items = AiApiKeyModel::where('deleted_at', 0) ->orderByDesc('sort') ->orderByDesc('id') ->get(['id', 'platform_id', 'name', 'remark', 'is_default', 'status', 'sort', 'api_key', 'created_at', 'updated_at']) ->toArray(); $platforms = AiPlatformModel::where('deleted_at', 0) ->get(['id', 'code', 'name', 'logo']) ->keyBy('id') ->toArray(); foreach ($items as &$item) { $pid = (int) ($item['platform_id'] ?? 0); $item['platform'] = $platforms[$pid] ?? null; $item['has_key'] = trim((string) ($item['api_key'] ?? '')) !== ''; unset($item['api_key']); } unset($item); return [ 'page' => 1, 'size' => count($items), 'page_count' => 1, 'total' => count($items), 'items' => $items, ]; } /** * 平台下拉(密钥表单用) */ public function platformOptions(): array { return AiPlatformModel::where('deleted_at', 0) ->where('status', 1) ->orderByDesc('sort') ->orderBy('id') ->get(['id', 'code', 'name', 'logo']) ->toArray(); } /** * 新增密钥(明文入库前加密) */ public function createKey(array $params): mixed { $platformId = (int) ($params['platform_id'] ?? 0); $name = trim((string) ($params['name'] ?? '')); $apiKey = trim((string) ($params['api_key'] ?? '')); if ($platformId <= 0) { $this->utils->errorThrow('请选择所属平台'); } if ($name === '') { $this->utils->errorThrow('请填写密钥别名'); } if ($apiKey === '') { $this->utils->errorThrow('请填写 API Key'); } $platform = AiPlatformModel::where('id', $platformId) ->where('deleted_at', 0) ->first(); if (!$platform) { $this->utils->errorThrow('平台不存在'); } $isDefault = (int) ($params['is_default'] ?? 0); if ($isDefault === 1) { // 同平台只保留一个默认密钥 AiApiKeyModel::where('platform_id', $platformId) ->where('deleted_at', 0) ->update(['is_default' => 0, 'updated_at' => time()]); } return $this->insert([ 'platform_id' => $platformId, 'name' => $name, 'api_key' => FieldEncryptService::getInstance()->encryptForStorage($apiKey), 'remark' => trim((string) ($params['remark'] ?? '')), 'is_default' => $isDefault, 'status' => (int) ($params['status'] ?? 1), 'sort' => (int) ($params['sort'] ?? 0), 'created_at' => time(), 'updated_at' => 0, 'deleted_at' => 0, ]); } /** * 更新密钥;api_key 为空表示不改密钥本身 */ public function updateKey(int $id, array $params): mixed { $info = AiApiKeyModel::where('id', $id)->where('deleted_at', 0)->first(); if (!$info) { $this->utils->notFound('密钥不存在'); } $data = []; if (array_key_exists('name', $params)) { $name = trim((string) $params['name']); if ($name === '') { $this->utils->errorThrow('密钥别名不能为空'); } $data['name'] = $name; } if (array_key_exists('remark', $params)) { $data['remark'] = trim((string) $params['remark']); } if (array_key_exists('status', $params)) { $data['status'] = (int) $params['status']; } if (array_key_exists('sort', $params)) { $data['sort'] = (int) $params['sort']; } if (array_key_exists('platform_id', $params)) { $platformId = (int) $params['platform_id']; if ($platformId <= 0) { $this->utils->errorThrow('请选择所属平台'); } $data['platform_id'] = $platformId; } $platformId = (int) ($data['platform_id'] ?? $info->platform_id); if (array_key_exists('is_default', $params)) { $isDefault = (int) $params['is_default']; $data['is_default'] = $isDefault; if ($isDefault === 1) { AiApiKeyModel::where('platform_id', $platformId) ->where('deleted_at', 0) ->where('id', '<>', $id) ->update(['is_default' => 0, 'updated_at' => time()]); } } $apiKey = trim((string) ($params['api_key'] ?? '')); if ($apiKey !== '') { $data['api_key'] = FieldEncryptService::getInstance()->encryptForStorage($apiKey); } if (empty($data)) { return true; } $data['updated_at'] = time(); // 直接 update,避免 BaseService::save 污染单例 where 导致后续列表为空 return AiApiKeyModel::where('id', $id)->where('deleted_at', 0)->update($data); } /** * 软删除密钥 */ public function deleteKeys(array $ids): mixed { $ids = array_values(array_filter(array_map('intval', $ids))); if (empty($ids)) { $this->utils->errorThrow('参数错误'); } return AiApiKeyModel::whereIn('id', $ids)->where('deleted_at', 0)->update([ 'deleted_at' => time(), 'updated_at' => time(), ]); } /** * AI 生成历史列表 */ public function generationList(): array { return AiGenerationLogService::getInstance()->getPageListForAdmin(); } /** * AI 生成历史详情 */ public function generationDetail(int $id): array { return AiGenerationLogService::getInstance()->getDetailForAdmin($id); } }