model = OssConfigModel::class; $this->selectField = [ 'id', 'driver', 'name', 'endpoint', 'region', 'bucket', 'domain', 'path_prefix', 'is_active', 'status', 'remark', 'sort', 'created_at', 'updated_at', ]; $this->queryField = [ 'driver' => '=', 'name' => 'like', 'status' => '=', 'is_active' => '=', ]; $this->orderBy = [ 'name' => 'sort', 'sort' => 'desc', ]; } /** * 驱动枚举选项(前端表单 / 卡片文案) */ public function driverOptions(): array { return OssDriverEnum::options(); } /** * 运行时页数据:配置卡片 + 当前启用 ID(不回显密钥明文) */ public function getRuntimeOptions(): array { $items = $this->formatConfigRows( OssConfigModel::where('deleted_at', 0) ->orderByDesc('sort') ->orderByDesc('id') ->get() ->toArray() ); $activeId = 0; foreach ($items as $item) { if ((int) ($item['is_active'] ?? 0) === 1) { $activeId = (int) $item['id']; break; } } if ($activeId <= 0) { $activeId = (int) SystemConfigService::getInstance()->getValue('oss_active_config_id', 0); } return [ 'drivers' => OssDriverEnum::options(), 'items' => $items, 'active_id' => $activeId, ]; } /** * 切换当前启用的 OSS 配置 * 为什么双写 is_active + system_config:上传链路优先读 kv,列表页靠 is_active 展示徽章 */ public function saveRuntime(array $params): array { $id = (int) ($params['id'] ?? 0); if ($id <= 0) { $this->utils->errorThrow('请选择要启用的配置'); } $info = OssConfigModel::where('id', $id)->where('deleted_at', 0)->first(); if (!$info) { $this->utils->notFound('配置不存在'); } if ((int) $info->status !== 1) { $this->utils->errorThrow('该配置已禁用,无法启用'); } $now = time(); OssConfigModel::where('deleted_at', 0)->update(['is_active' => 0, 'updated_at' => $now]); OssConfigModel::where('id', $id)->update(['is_active' => 1, 'updated_at' => $now]); SystemConfigService::getInstance()->setValue('oss_active_config_id', (string) $id, '当前启用的 OSS 配置 ID'); return ['id' => $id]; } /** * 配置列表(卡片,无密钥明文) */ public function listConfigs(): array { $items = $this->formatConfigRows( OssConfigModel::where('deleted_at', 0) ->orderByDesc('sort') ->orderByDesc('id') ->get() ->toArray() ); return [ 'page' => 1, 'size' => count($items), 'page_count' => 1, 'total' => count($items), 'items' => $items, ]; } /** * 新增 OSS 配置;云驱动要求填写密钥 */ public function createConfig(array $params): mixed { $driver = trim((string) ($params['driver'] ?? '')); $name = trim((string) ($params['name'] ?? '')); if (!OssDriverEnum::isValid($driver)) { $this->utils->errorThrow('不支持的存储驱动'); } if ($name === '') { $this->utils->errorThrow('请填写配置别名'); } $enum = OssDriverEnum::from($driver); $accessKey = trim((string) ($params['access_key'] ?? '')); $secretKey = trim((string) ($params['secret_key'] ?? '')); if ($enum->needsSecret() && ($accessKey === '' || $secretKey === '')) { $this->utils->errorThrow('该驱动需要填写 AccessKey 与 SecretKey'); } $encrypt = FieldEncryptService::getInstance(); $isActive = (int) ($params['is_active'] ?? 0); $now = time(); if ($isActive === 1) { OssConfigModel::where('deleted_at', 0)->update(['is_active' => 0, 'updated_at' => $now]); } $id = OssConfigModel::insertGetId([ 'driver' => $driver, 'name' => $name, 'access_key' => $accessKey !== '' ? $encrypt->encryptForStorage($accessKey) : '', 'secret_key' => $secretKey !== '' ? $encrypt->encryptForStorage($secretKey) : '', 'endpoint' => trim((string) ($params['endpoint'] ?? '')), 'region' => trim((string) ($params['region'] ?? '')), 'bucket' => trim((string) ($params['bucket'] ?? '')), 'domain' => trim((string) ($params['domain'] ?? '')), 'path_prefix' => trim((string) ($params['path_prefix'] ?? '')), 'extra_json' => null, 'is_active' => $isActive, 'status' => (int) ($params['status'] ?? 1), 'remark' => trim((string) ($params['remark'] ?? '')), 'sort' => (int) ($params['sort'] ?? 0), 'created_at' => $now, 'updated_at' => 0, 'deleted_at' => 0, ]); if ($isActive === 1) { SystemConfigService::getInstance()->setValue('oss_active_config_id', (string) $id, '当前启用的 OSS 配置 ID'); } return ['id' => $id]; } /** * 更新配置;access_key/secret_key 空串表示不改密钥 */ public function updateConfig(int $id, array $params): mixed { $info = OssConfigModel::where('id', $id)->where('deleted_at', 0)->first(); if (!$info) { $this->utils->notFound('配置不存在'); } $data = []; if (array_key_exists('driver', $params)) { $driver = trim((string) $params['driver']); if (!OssDriverEnum::isValid($driver)) { $this->utils->errorThrow('不支持的存储驱动'); } $data['driver'] = $driver; } if (array_key_exists('name', $params)) { $name = trim((string) $params['name']); if ($name === '') { $this->utils->errorThrow('配置别名不能为空'); } $data['name'] = $name; } foreach (['endpoint', 'region', 'bucket', 'domain', 'path_prefix', 'remark'] as $field) { if (array_key_exists($field, $params)) { $data[$field] = trim((string) $params[$field]); } } if (array_key_exists('status', $params)) { $data['status'] = (int) $params['status']; } if (array_key_exists('sort', $params)) { $data['sort'] = (int) $params['sort']; } $encrypt = FieldEncryptService::getInstance(); $accessKey = trim((string) ($params['access_key'] ?? '')); if ($accessKey !== '') { $data['access_key'] = $encrypt->encryptForStorage($accessKey); } $secretKey = trim((string) ($params['secret_key'] ?? '')); if ($secretKey !== '') { $data['secret_key'] = $encrypt->encryptForStorage($secretKey); } $now = time(); if (array_key_exists('is_active', $params) && (int) $params['is_active'] === 1) { OssConfigModel::where('deleted_at', 0)->where('id', '<>', $id)->update(['is_active' => 0, 'updated_at' => $now]); $data['is_active'] = 1; SystemConfigService::getInstance()->setValue('oss_active_config_id', (string) $id, '当前启用的 OSS 配置 ID'); } elseif (array_key_exists('is_active', $params)) { $data['is_active'] = (int) $params['is_active']; } if (empty($data)) { return true; } $data['updated_at'] = $now; return OssConfigModel::where('id', $id)->where('deleted_at', 0)->update($data); } /** * 软删除;若删的是当前启用项则回落到本地配置,避免上传无可用驱动 */ public function deleteConfigs(array $ids): mixed { $ids = array_values(array_filter(array_map('intval', $ids))); if (empty($ids)) { $this->utils->errorThrow('参数错误'); } $activeId = (int) SystemConfigService::getInstance()->getValue('oss_active_config_id', 0); $deletingActive = ($activeId > 0 && in_array($activeId, $ids, true)) || OssConfigModel::whereIn('id', $ids)->where('is_active', 1)->where('deleted_at', 0)->exists(); $fallbackId = 0; if ($deletingActive) { $local = OssConfigModel::where('driver', 'local') ->where('deleted_at', 0) ->where('status', 1) ->whereNotIn('id', $ids) ->orderBy('id') ->first(); if (!$local) { $this->utils->errorThrow('不能删除当前启用的配置:请先切换,或保留至少一条本地存储'); } $fallbackId = (int) $local->id; } $ok = OssConfigModel::whereIn('id', $ids)->where('deleted_at', 0)->update([ 'deleted_at' => time(), 'updated_at' => time(), 'is_active' => 0, ]); if ($fallbackId > 0) { $this->saveRuntime(['id' => $fallbackId]); } return $ok; } /** * 行格式化:补驱动名、密钥是否已配置标记 */ private function formatConfigRows(array $rows): array { foreach ($rows as &$row) { $driver = (string) ($row['driver'] ?? ''); $enum = OssDriverEnum::tryFrom($driver); $row['driver_name'] = $enum?->label() ?? $driver; $row['driver_desc'] = $enum?->description() ?? ''; $row['has_access_key'] = trim((string) ($row['access_key'] ?? '')) !== ''; $row['has_secret_key'] = trim((string) ($row['secret_key'] ?? '')) !== ''; unset($row['access_key'], $row['secret_key']); } unset($row); return $rows; } }