diff --git a/Cargo.lock b/Cargo.lock index 84ebfe1..f9a78ff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2169,6 +2169,7 @@ dependencies = [ "axum", "axum-extra", "base64 0.22.1", + "bytes", "chrono", "dotenvy", "hex", diff --git a/Cargo.toml b/Cargo.toml index 389394b..61b7e41 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,7 @@ time = "0.3" serde = { version = "1", features = ["derive"] } serde_json = "1" thiserror = "1" +bytes = "1" tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter"] } diff --git a/docs/api.md b/docs/api.md index 0f4d670..a1d7bf9 100644 --- a/docs/api.md +++ b/docs/api.md @@ -731,6 +731,8 @@ Authorization: Bearer 凭据加密保存且不通过 API 回传。测试接口执行 Bucket 检查、内部临时对象读写删和公网预签名下载;激活接口会再次测试并原子切换活动端点。活动端点不能直接编辑或删除。 +列表响应中的 `local_object_count` 与 `local_stored_bytes` 统计当前实际位于应用服务器的成品。存在活动 S3 时,新对象仍优先写入 S3;若本次 S3 写入失败,则自动回退本地并按实际后端完成下载和到期清理。 + ### 11.7 兑换码管理 ```http diff --git a/docs/s3-storage-plan.md b/docs/s3-storage-plan.md index a67acad..0377b69 100644 --- a/docs/s3-storage-plan.md +++ b/docs/s3-storage-plan.md @@ -39,6 +39,7 @@ flowchart LR 4. 批处理原图只在 118 的共享 `uploads/orig` 临时保存,Worker 完成或失败后删除,不上传 S3。 5. 批量 ZIP 在 118 临时生成,64 MiB 以上自动使用 S3 分片上传,上传后删除临时目录。 6. 每个成品记录写入时的端点 ID。以后切换端点不会使旧文件失联;旧端点凭据会保留到关联对象清空。 +7. 活动 S3 仍是首选后端;连接、凭据或上传失败时,本次成品自动写入 118 本地卷并记录 `storage_backend=local`。S3 恢复后,后续新对象会再次优先写入 S3。 `/api/v1/compress/direct` 保留原有“响应体直接返回图片”的 API 语义,避免破坏现有调用方;网站下载、历史记录下载、普通压缩结果和批量 ZIP 均走 S3。 @@ -126,6 +127,7 @@ aws --endpoint-url http://127.0.0.1:3900 \ - 未授权用户无法取得签名 URL;任务过期后应用下载接口返回 404。 - 单文件与批任务数据库均记录正确的 `storage_endpoint_id` 和对象键。 - 切换到第二端点后,新对象进入第二端点,第一端点历史对象仍可下载。 -- S3 停止时同步请求返回 503,批任务保留临时原图并重试,不静默写回本地。 +- S3 停止时同步请求和批任务均完成本地兜底,数据库记录 `storage_backend=local`,下载接口直接从应用服务器返回文件。 +- S3 恢复后下一次新对象重新记录为 `storage_backend=s3`,下载接口恢复 `307` 到签名 URL。 - 删除 S3 对象失败时,过期任务数据库记录保留并在下一轮重试。 - 119 磁盘 70%/85% 告警、容器重启、NTP 时间同步和证书续期均验证通过。 diff --git a/frontend/src/app/layouts/PublicLayout.vue b/frontend/src/app/layouts/PublicLayout.vue index b3eba7c..bd2ea05 100644 --- a/frontend/src/app/layouts/PublicLayout.vue +++ b/frontend/src/app/layouts/PublicLayout.vue @@ -8,6 +8,8 @@ const auth = useAuthStore() const router = useRouter() const isLoggedIn = computed(() => auth.isLoggedIn) +const consoleRoute = computed(() => (auth.user?.role === 'admin' ? '/admin' : '/dashboard')) +const consoleLabel = computed(() => (auth.user?.role === 'admin' ? '管理后台' : '控制台')) function logout() { auth.logout() @@ -35,10 +37,10 @@ function logout() {