From 968f764af7bc349541fbc7f1f153aa79b984752c Mon Sep 17 00:00:00 2001 From: oiov Date: Tue, 15 Jul 2025 15:30:01 +0800 Subject: [PATCH 1/6] docs: add cloud storage docs --- content/docs/developer/cloud-storag-zh.mdx | 259 ++++++++++++++++++++ content/docs/developer/cloud-storage.mdx | 262 +++++++++++++++++++++ content/docs/developer/s3.mdx | 10 - lib/dto/files.ts | 3 +- public/_static/docs/cos-cors.png | Bin 0 -> 97912 bytes public/sw.js.map | 2 +- 6 files changed, 523 insertions(+), 13 deletions(-) create mode 100644 content/docs/developer/cloud-storag-zh.mdx create mode 100644 content/docs/developer/cloud-storage.mdx delete mode 100644 content/docs/developer/s3.mdx create mode 100644 public/_static/docs/cos-cors.png diff --git a/content/docs/developer/cloud-storag-zh.mdx b/content/docs/developer/cloud-storag-zh.mdx new file mode 100644 index 0000000..625bbe1 --- /dev/null +++ b/content/docs/developer/cloud-storag-zh.mdx @@ -0,0 +1,259 @@ +--- +title: 云存储配置 +description: 如何配置多平台云存储 +--- + + + +## 概览 + +管理员可以在 `/admin/system` 管理 S3 配置,包括添加、删除和修改云存储的 S3 配置。 + +WR.DO 目前支持多种云存储提供商: + +- Cloudflare R2 +- AWS S3 +- 腾讯云 COS +- 阿里云 OSS +- 自定义提供商 (兼容 S3 API) + +> 一个提供商可以添加多个存储桶 + +## Cloudflare R2 + +### 1. 创建 R2 存储桶 + +1. 登录您的 [Cloudflare 仪表板](https://dash.cloudflare.com/) +2. 从左侧边栏导航到 **R2 对象存储** +3. 点击 **创建存储桶** +4. 输入您的存储桶名称(例如:`wrdo`) +5. 选择位置(建议选择自动) +6. 点击 **创建存储桶** + +### 2. 获取 API 凭证 + +1. 在您的 Cloudflare 仪表板中,前往 **我的个人资料** > **API 令牌** +2. 点击 **创建令牌** +3. 使用 **R2 令牌** 模板或创建自定义令牌,包含: + - **权限**: `R2:Edit` + - **账户资源**: 包含您的账户 + - **区域资源**: 包含所有区域(如果需要) +4. 点击 **继续摘要**,然后 **创建令牌** +5. 复制并保存令牌(这是您的 **访问密钥 ID** 和 **秘密访问密钥**) + +### 3. 获取账户 ID + +1. 在您的 Cloudflare 仪表板中,前往右侧边栏 +2. 复制您的 **账户 ID** + +### 4. 获取公共 URL + +1. 在您的 Cloudflare 仪表板中,前往 **R2 对象存储** > **存储桶详情** > **公共开发 URL** + +如果您已配置自定义域名,请使用该域名。 + +### 5. 配置 CORS + +1. 在您的 Cloudflare 仪表板中,前往 **R2 对象存储** > **存储桶设置** -> **CORS 策略** + +填入以下内容: + +```json +[ + { + "AllowedOrigins": [ + "http://localhost:3000", + "https://wr.do" // 替换为您的域名 + ], + "AllowedMethods": [ + "GET", + "PUT", + "POST", + "DELETE", + "HEAD" + ], + "AllowedHeaders": [ + "*" + ], + "ExposeHeaders": [ + "ETag" + ], + "MaxAgeSeconds": 3600 + } +] +``` + +### 6. 在 WR.DO 中配置 + +访问 `localhost:3000/admin/system`,填写配置表单: + +- **提供渠道**: cloudflare (r2) +- **渠道名称**: Cloudflare R2(或任何自定义名称) +- **S3 端点**: `https://<账户ID>.r2.cloudflarestorage.com`(替换为您的账户端点) +- **访问密钥 ID**: 第 2 步中的 API 令牌 +- **机密访问密钥**: 第 2 步中的 API 令牌 +- **启用**: 开启 +- **存储桶名称**: 您的存储桶名称 +- **公开域名或自定义域名**: 参考第 4 步 +- **存储桶区域**: auto +- **前缀**: 可选 +- **公开**: 如果您想要公共访问,请启用 + +## 腾讯云 COS + +### 1. 创建 COS 存储桶 + +1. 登录 [腾讯云控制台](https://console.cloud.tencent.com/cos) +2. 点击 **存储桶列表** > **创建存储桶** +3. 输入存储桶名称(例如:`wrdo-1303456836`) +4. 选择地域(例如:`ap-chengdu`) +5. 配置访问权限 +6. 点击 **创建** + +### 2. 获取 API 密钥 + +1. 前往 [CAM 控制台](https://console.cloud.tencent.com/cam/capi) +2. 点击 **新建密钥** 或使用现有密钥 +3. 保存您的 **SecretId** 和 **SecretKey** + +### 3. CORS 设置 + +1. 前往 [COS 控制台](https://console.cloud.tencent.com/cos) +2. 点击 **存储桶列表** > **选择存储桶** -> 安全管理 -> 跨域访问 CORS 设置 +3. 填入下列规则: + +![](/_static/docs/cos-cors.png) + +### 4. 在 WR.DO 中配置 + +填写配置表单: + +- **提供渠道**: tencent (cos) +- **渠道名称**: 腾讯云 COS(或任何自定义名称) +- **S3 端点**: `https://cos.ap-chengdu.myqcloud.com`(替换为您的地域) +- **访问密钥 ID**: 您的 SecretId +- **机密访问密钥**: 您的 SecretKey +- **启用**: 开启 +- **存储桶名称**: 您的存储桶名称(例如:`wrdo-1303456836`) +- **公开域名或自定义域名**: `https://wrdo-1303456836.cos.ap-chengdu.myqcloud.com`(您的存储桶公共 URL) +- **存储桶区域**: 您的 COS 地域(例如:`ap-chengdu`) +- **前缀**: 可选日期前缀 +- **公开**: 如果您想要公共访问,请启用 + +## 阿里云 OSS + +### 1. 创建 OSS 存储桶 + +1. 登录 [阿里云控制台](https://oss.console.aliyun.com/) +2. 点击 **创建 Bucket** +3. 输入存储桶名称 +4. 选择地域(例如:`oss-cn-hangzhou`) +5. 配置 ACL 和其他设置 +6. 点击 **确定** + +### 2. 获取 AccessKey + +1. 前往 [RAM 控制台](https://ram.console.aliyun.com/manage/ak) +2. 点击 **创建 AccessKey** 或使用现有密钥 +3. 保存您的 **AccessKeyId** 和 **AccessKeySecret** + +### 3. 在 WR.DO 中配置 + +填写配置表单: + +- **提供渠道**: ali (oss) +- **渠道名称**: 阿里云 OSS(或任何自定义名称) +- **S3 端点**: `https://oss-cn-hangzhou.aliyuncs.com`(替换为您的地域) +- **访问密钥 ID**: 您的 AccessKeyId +- **机密访问密钥**: 您的 AccessKeySecret +- **启用**: 开启 +- **存储桶名称**: 您的存储桶名称 +- **公开域名或自定义域名**: `https://your-bucket.oss-cn-hangzhou.aliyuncs.com`(您的存储桶公共 URL) +- **存储桶区域**: 您的 OSS 地域(例如:`oss-cn-hangzhou`) +- **前缀**: 可选日期前缀 +- **公开**: 如果您想要公共访问,请启用 + +## AWS S3 + +### 1. 创建 S3 存储桶 + +1. 登录 [AWS 控制台](https://console.aws.amazon.com/s3/) +2. 点击 **创建存储桶** +3. 输入存储桶名称(全球唯一) +4. 选择 AWS 区域 +5. 根据需要配置存储桶设置 +6. 点击 **创建存储桶** + +### 2. 创建 IAM 用户 + +1. 前往 [IAM 控制台](https://console.aws.amazon.com/iam/) +2. 点击 **用户** > **添加用户** +3. 输入用户名并选择 **编程访问** +4. 附加现有策略或创建具有 S3 权限的自定义策略: + ```json + { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "s3:GetObject", + "s3:PutObject", + "s3:DeleteObject", + "s3:ListBucket" + ], + "Resource": [ + "arn:aws:s3:::your-bucket-name", + "arn:aws:s3:::your-bucket-name/*" + ] + } + ] + } + ``` +5. 完成用户创建并保存 **访问密钥 ID** 和 **秘密访问密钥** + +### 3. 在 WR.DO 中配置 + +填写配置表单: + +- **提供渠道**: aws (s3) +- **渠道名称**: AWS S3(或任何自定义名称) +- **S3 端点**: `https://s3.amazonaws.com`(或特定区域端点) +- **访问密钥 ID**: 您的 IAM 用户访问密钥 ID +- **机密访问密钥**: 您的 IAM 用户秘密访问密钥 +- **启用**: 开启 +- **存储桶名称**: 您的 S3 存储桶名称 +- **公开域名或自定义域名**: 您的存储桶公共 URL 或 CloudFront 分发 +- **存储桶区域**: 您的 S3 区域(例如:`us-east-1`) +- **前缀**: 可选日期前缀 +- **公开**: 如果您想要公共访问,请启用 + +## 通用配置选项 + +### 前缀设置 +- 使用基于日期的前缀(例如:`2025/08/08`)按日期组织文件 +- 如果您喜欢扁平文件结构,请留空 + +### 公共访问 +- 如果您希望文件可以通过直接 URL 访问,请启用 **公开** +- 对于私有文件存储,请禁用 + +### 自定义域名 +- 配置自定义域名以获得更好的品牌体验 +- 确保为您的域名进行正确的 DNS 配置 + +## 故障排除 + +### 常见问题 + +1. **访问被拒绝**: 检查您的 API 凭证和权限 +2. **存储桶未找到**: 验证存储桶名称和区域设置 +3. **CORS 问题**: 如果需要,在您的存储桶中配置 CORS 设置 +4. **端点错误**: 确保您的提供商端点格式正确 + +### 测试配置 + +保存配置后,您可以通过以下方式测试: +1. 通过管理界面上传测试文件 +2. 检查文件是否出现在您的云存储桶中 +3. 验证公共访问(如果启用)是否可以通过文件 URL 访问 \ No newline at end of file diff --git a/content/docs/developer/cloud-storage.mdx b/content/docs/developer/cloud-storage.mdx new file mode 100644 index 0000000..0f579b9 --- /dev/null +++ b/content/docs/developer/cloud-storage.mdx @@ -0,0 +1,262 @@ +--- +title: Cloud Storage +description: How to config the cloud storage api +--- + + + +## Overview + +Administrators can manage s3 configurations at `/admin/system`, +including adding, deleting, and modifying s3 configurations for cloud storage. + +WR.DO now supports multiple cloud storage providers: + +- Cloudflare R2 +- AWS S3 +- Tencent COS +- Ali OSS +- Custom Provider (Support any S3 compatible provider) + +> One provider can configure multiple buckets. + +## Cloudflare R2 + +### 1. Create R2 Bucket + +1. Log in to your [Cloudflare dashboard](https://dash.cloudflare.com/) +2. Navigate to **R2 Object Storage** from the left sidebar +3. Click **Create bucket** +4. Enter your bucket name (e.g., `wrdo`) +5. Select the location (auto is recommended) +6. Click **Create bucket** + +### 2. Get API Credentials + +1. In your Cloudflare dashboard, go to **My Profile** > **API Tokens** +2. Click **Create Token** +3. Use the **R2 Token** template or create a custom token with: + - **Permissions**: `R2:Edit` + - **Account Resources**: Include your account + - **Zone Resources**: Include all zones (if needed) +4. Click **Continue to summary** and then **Create Token** +5. Copy and save the token (this is your **Access Key ID** and **Secret Access Key**) + +### 3. Get Account ID + +1. In your Cloudflare dashboard, go to the right sidebar +2. Copy your **Account ID** + +### 4. Get Public URL + +1. In your Cloudflare dashboard, go to **R2 Object Storage** > **Bucket Details** > **Public Development URL** + +if you have configured a custom domain, use that instead. + +### 5. Config CORS + +1. In your Cloudflare dashboard, go to **R2 Object Storage** > **Bucket Settings** -> **CORS Policy** + +Fill in the following: + +```json +[ + { + "AllowedOrigins": [ + "http://localhost:3000", + "https://wr.do" // Replace with your domain + ], + "AllowedMethods": [ + "GET", + "PUT", + "POST", + "DELETE", + "HEAD" + ], + "AllowedHeaders": [ + "*" + ], + "ExposeHeaders": [ + "ETag" + ], + "MaxAgeSeconds": 3600 + } +] +``` + +### 6. Configuration in WR.DO + +Follow `localhost:3000/admin/system`, fill in the configuration form with: + +- **Provider**: cloudflare (r2) +- **Channel Name**: Cloudflare R2 (or any custom name) +- **S3 Endpoint**: `https://.r2.cloudflarestorage.com` (replace with your account's endpoint) +- **Access Key ID**: Your API token from step 2 +- **Secret Access Key**: Your API token from step 2 +- **Enable**: Toggle ON +- **Bucket Name**: Your bucket name +- **Public Domain**: follow step 4 +- **Storage Region**: auto +- **Prefix**: Optional +- **Public**: Enable if you want public access + + +## Tencent COS + +### 1. Create COS Bucket + +1. Log in to [Tencent Cloud Console](https://console.cloud.tencent.com/cos) +2. Click **Bucket List** > **Create Bucket** +3. Enter bucket name (e.g., `wrdo-1303456836`) +4. Select region (e.g., `ap-chengdu`) +5. Configure access permissions +6. Click **Create** + +### 2. Get API Keys + +1. Go to [CAM Console](https://console.cloud.tencent.com/cam/capi) +2. Click **Create Key** or use existing keys +3. Save your **SecretId** and **SecretKey** + +### 3. CORS 设置 + +1. Follow [COS Console](https://console.cloud.tencent.com/cos) +2. Click **Bucket List** > **Select a Bucket** -> 安全管理 -> 跨域访问 CORS 设置 +3. Fill in the following rules: + +![](/_static/docs/cos-cors.png) + +### 4. Configuration in WR.DO + +Fill in the configuration form with: + +- **Provider**: tencent (cos) +- **Channel Name**: 腾讯云 COS (or any custom name) +- **S3 Endpoint**: `https://cos.ap-chengdu.myqcloud.com` (replace with your region) +- **Access Key ID**: Your SecretId +- **Secret Access Key**: Your SecretKey +- **Enable**: Toggle ON +- **Bucket Name**: Your bucket name (e.g., `wrdo-1303456836`) +- **Public Domain**: `https://wrdo-1303456836.cos.ap-chengdu.myqcloud.com` (your bucket's public URL) +- **Storage Region**: Your COS region (e.g., `ap-chengdu`) +- **Prefix**: Optional date prefix +- **Public**: Enable if you want public access + +## Ali OSS + +### 1. Create OSS Bucket + +1. Log in to [Alibaba Cloud Console](https://oss.console.aliyun.com/) +2. Click **Create Bucket** +3. Enter bucket name +4. Select region (e.g., `oss-cn-hangzhou`) +5. Configure ACL and other settings +6. Click **OK** + +### 2. Get AccessKey + +1. Go to [RAM Console](https://ram.console.aliyun.com/manage/ak) +2. Click **Create AccessKey** or use existing keys +3. Save your **AccessKeyId** and **AccessKeySecret** + +### 3. Configuration in WR.DO + +Fill in the configuration form with: + +- **Provider**: ali (oss) +- **Channel Name**: 阿里云 OSS (or any custom name) +- **S3 Endpoint**: `https://oss-cn-hangzhou.aliyuncs.com` (replace with your region) +- **Access Key ID**: Your AccessKeyId +- **Secret Access Key**: Your AccessKeySecret +- **Enable**: Toggle ON +- **Bucket Name**: Your bucket name +- **Public Domain**: `https://your-bucket.oss-cn-hangzhou.aliyuncs.com` (your bucket's public URL) +- **Storage Region**: Your OSS region (e.g., `oss-cn-hangzhou`) +- **Prefix**: Optional date prefix +- **Public**: Enable if you want public access + +## AWS S3 + +### 1. Create S3 Bucket + +1. Log in to [AWS Console](https://console.aws.amazon.com/s3/) +2. Click **Create bucket** +3. Enter bucket name (globally unique) +4. Select AWS region +5. Configure bucket settings as needed +6. Click **Create bucket** + +### 2. Create IAM User + +1. Go to [IAM Console](https://console.aws.amazon.com/iam/) +2. Click **Users** > **Add user** +3. Enter username and select **Programmatic access** +4. Attach existing policies or create custom policy with S3 permissions: + ```json + { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "s3:GetObject", + "s3:PutObject", + "s3:DeleteObject", + "s3:ListBucket" + ], + "Resource": [ + "arn:aws:s3:::your-bucket-name", + "arn:aws:s3:::your-bucket-name/*" + ] + } + ] + } + ``` +5. Complete user creation and save **Access Key ID** and **Secret Access Key** + +### 3. Configuration in WR.DO + +Fill in the configuration form with: + +- **Provider**: aws (s3) +- **Channel Name**: AWS S3 (or any custom name) +- **S3 Endpoint**: `https://s3.amazonaws.com` (or region-specific endpoint) +- **Access Key ID**: Your IAM user's Access Key ID +- **Secret Access Key**: Your IAM user's Secret Access Key +- **Enable**: Toggle ON +- **Bucket Name**: Your S3 bucket name +- **Public Domain**: Your bucket's public URL or CloudFront distribution +- **Storage Region**: Your S3 region (e.g., `us-east-1`) +- **Prefix**: Optional date prefix +- **Public**: Enable if you want public access + + +## Common Configuration Options + +### Prefix Settings +- Use date-based prefixes (e.g., `2025/08/08`) to organize files by date +- Leave empty if you prefer flat file structure + +### Public Access +- Enable **Public** if you want files to be accessible via direct URLs +- Disable for private file storage + +### Custom Domains +- Configure custom domains for better branding +- Ensure proper DNS configuration for your domain + +## Troubleshooting + +### Common Issues + +1. **Access Denied**: Check your API credentials and permissions +2. **Bucket Not Found**: Verify bucket name and region settings +3. **CORS Issues**: Configure CORS settings in your bucket if needed +4. **Endpoint Errors**: Ensure correct endpoint format for your provider + +### Testing Configuration + +After saving your configuration, you can test it by: +1. Uploading a test file through the admin interface +2. Checking if the file appears in your cloud storage bucket +3. Verifying public access (if enabled) by accessing the file URL diff --git a/content/docs/developer/s3.mdx b/content/docs/developer/s3.mdx deleted file mode 100644 index 3b08cc4..0000000 --- a/content/docs/developer/s3.mdx +++ /dev/null @@ -1,10 +0,0 @@ ---- -title: S3 Configs -description: How to config the s3 api. ---- - -## Overview - -Administrators can manage s3 configurations at `/admin/system`, including adding, deleting, and modifying s3 configurations. - -## Cloudflare R2 \ No newline at end of file diff --git a/lib/dto/files.ts b/lib/dto/files.ts index cc20470..a093ad7 100644 --- a/lib/dto/files.ts +++ b/lib/dto/files.ts @@ -158,9 +158,8 @@ export async function getUserFiles(options: QueryUserFileOptions = {}) { }), prisma.userFile.count({ where }), prisma.userFile.aggregate({ - // All provider's file size where: { - userId, + ...(userId && { userId }), status: 1, }, _sum: { size: true }, diff --git a/public/_static/docs/cos-cors.png b/public/_static/docs/cos-cors.png new file mode 100644 index 0000000000000000000000000000000000000000..2daf81949241ba0f9117a52f94c47f37b6b63d9f GIT binary patch literal 97912 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 literal 0 HcmV?d00001 diff --git a/public/sw.js.map b/public/sw.js.map index 6110b66..54c1284 100644 --- a/public/sw.js.map +++ b/public/sw.js.map @@ -1 +1 @@ -{"version":3,"file":"sw.js","sources":["../../../../../../private/var/folders/9b/3qmyp8zd2xvdspdrp149fyg00000gn/T/bf4c8ec428159b5c3ebe0be7863842cb/sw.js"],"sourcesContent":["import {registerRoute as workbox_routing_registerRoute} from '/Users/songjunxi/Desktop/repos/wrdo-app/wr.do/node_modules/.pnpm/workbox-routing@6.6.0/node_modules/workbox-routing/registerRoute.mjs';\nimport {NetworkFirst as workbox_strategies_NetworkFirst} from '/Users/songjunxi/Desktop/repos/wrdo-app/wr.do/node_modules/.pnpm/workbox-strategies@6.6.0/node_modules/workbox-strategies/NetworkFirst.mjs';\nimport {NetworkOnly as workbox_strategies_NetworkOnly} from '/Users/songjunxi/Desktop/repos/wrdo-app/wr.do/node_modules/.pnpm/workbox-strategies@6.6.0/node_modules/workbox-strategies/NetworkOnly.mjs';\nimport {clientsClaim as workbox_core_clientsClaim} from '/Users/songjunxi/Desktop/repos/wrdo-app/wr.do/node_modules/.pnpm/workbox-core@6.6.0/node_modules/workbox-core/clientsClaim.mjs';/**\n * Welcome to your Workbox-powered service worker!\n *\n * You'll need to register this file in your web app.\n * See https://goo.gl/nhQhGp\n *\n * The rest of the code is auto-generated. Please don't update this file\n * directly; instead, make changes to your Workbox build configuration\n * and re-run your build process.\n * See https://goo.gl/2aRDsh\n */\n\n\nimportScripts(\n \n);\n\n\n\n\n\n\n\nself.skipWaiting();\n\nworkbox_core_clientsClaim();\n\n\n\nworkbox_routing_registerRoute(\"/\", new workbox_strategies_NetworkFirst({ \"cacheName\":\"start-url\", plugins: [{ cacheWillUpdate: async ({ request, response, event, state }) => { if (response && response.type === 'opaqueredirect') { return new Response(response.body, { status: 200, statusText: 'OK', headers: response.headers }) } return response } }] }), 'GET');\nworkbox_routing_registerRoute(/.*/i, new workbox_strategies_NetworkOnly({ \"cacheName\":\"dev\", plugins: [] }), 'GET');\n\n\n\n\n"],"names":["importScripts","self","skipWaiting","workbox_core_clientsClaim","workbox_routing_registerRoute","workbox_strategies_NetworkFirst","plugins","cacheWillUpdate","request","response","event","state","type","Response","body","status","statusText","headers","workbox_strategies_NetworkOnly"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgBAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAa,EAEZ,CAAA;EAQDC,CAAI,CAAA,CAAA,CAAA,CAACC,CAAW,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAAA;AAElBC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAyB,EAAE,CAAA;AAI3BC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAA6B,CAAC,CAAA,CAAA,CAAG,CAAE,CAAA,CAAA,CAAA,CAAA,CAAIC,oBAA+B,CAAC,CAAA;EAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAW,EAAC,CAAW,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;EAAEC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAO,EAAE,CAAC,CAAA;GAAEC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAe,EAAE,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;QAAEC,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;QAAEC,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;QAAEC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA;AAAEC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA;AAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA;EAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAIF,QAAQ,CAAIA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAQ,CAACG,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,gBAAgB,CAAE,CAAA,CAAA;AAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,OAAO,CAAIC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAQ,CAACJ,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAACK,IAAI,CAAE,CAAA,CAAA;EAAEC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAM,EAAE,CAAG,CAAA,CAAA,CAAA;EAAEC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAU,EAAE,CAAI,CAAA,CAAA,CAAA,CAAA;YAAEC,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAER,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAACQ,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA;AAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAC,CAAA;EAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;EAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAOR,QAAQ,CAAA;EAAC,CAAA,CAAA,CAAA,CAAA,CAAA;KAAG,CAAA;AAAE,CAAA,CAAA,CAAC,CAAC,CAAA,CAAE,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,CAAA;AACxWL,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAA6B,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,CAAE,CAAA,CAAA,CAAA,CAAA,CAAIc,mBAA8B,CAAC,CAAA;EAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAW,EAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA;EAAEZ,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAO,EAAE,CAAA,CAAA;EAAG,CAAC,CAAC,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAA;;"} \ No newline at end of file +{"version":3,"file":"sw.js","sources":["../../../../../../private/var/folders/9b/3qmyp8zd2xvdspdrp149fyg00000gn/T/d668bd1078ac655e5218181d0eff41b9/sw.js"],"sourcesContent":["import {registerRoute as workbox_routing_registerRoute} from '/Users/songjunxi/Desktop/repos/wrdo-app/wr.do/node_modules/.pnpm/workbox-routing@6.6.0/node_modules/workbox-routing/registerRoute.mjs';\nimport {NetworkFirst as workbox_strategies_NetworkFirst} from '/Users/songjunxi/Desktop/repos/wrdo-app/wr.do/node_modules/.pnpm/workbox-strategies@6.6.0/node_modules/workbox-strategies/NetworkFirst.mjs';\nimport {NetworkOnly as workbox_strategies_NetworkOnly} from '/Users/songjunxi/Desktop/repos/wrdo-app/wr.do/node_modules/.pnpm/workbox-strategies@6.6.0/node_modules/workbox-strategies/NetworkOnly.mjs';\nimport {clientsClaim as workbox_core_clientsClaim} from '/Users/songjunxi/Desktop/repos/wrdo-app/wr.do/node_modules/.pnpm/workbox-core@6.6.0/node_modules/workbox-core/clientsClaim.mjs';/**\n * Welcome to your Workbox-powered service worker!\n *\n * You'll need to register this file in your web app.\n * See https://goo.gl/nhQhGp\n *\n * The rest of the code is auto-generated. Please don't update this file\n * directly; instead, make changes to your Workbox build configuration\n * and re-run your build process.\n * See https://goo.gl/2aRDsh\n */\n\n\nimportScripts(\n \n);\n\n\n\n\n\n\n\nself.skipWaiting();\n\nworkbox_core_clientsClaim();\n\n\n\nworkbox_routing_registerRoute(\"/\", new workbox_strategies_NetworkFirst({ \"cacheName\":\"start-url\", plugins: [{ cacheWillUpdate: async ({ request, response, event, state }) => { if (response && response.type === 'opaqueredirect') { return new Response(response.body, { status: 200, statusText: 'OK', headers: response.headers }) } return response } }] }), 'GET');\nworkbox_routing_registerRoute(/.*/i, new workbox_strategies_NetworkOnly({ \"cacheName\":\"dev\", plugins: [] }), 'GET');\n\n\n\n\n"],"names":["importScripts","self","skipWaiting","workbox_core_clientsClaim","workbox_routing_registerRoute","workbox_strategies_NetworkFirst","plugins","cacheWillUpdate","request","response","event","state","type","Response","body","status","statusText","headers","workbox_strategies_NetworkOnly"],"mappings":"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"} \ No newline at end of file From 8aa0609c95818f9c19a357f6313debd6d45bcb92 Mon Sep 17 00:00:00 2001 From: oiov Date: Tue, 15 Jul 2025 16:18:19 +0800 Subject: [PATCH 2/6] upd file links --- components/file/file-list.tsx | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/components/file/file-list.tsx b/components/file/file-list.tsx index 643ca1d..80148af 100644 --- a/components/file/file-list.tsx +++ b/components/file/file-list.tsx @@ -240,26 +240,28 @@ export default function UserFileList({ -
- -

- {`${file.name}${getFileUrl(file.path)}`} -

- ${getFileUrl(file.path)}`} - /> -

- {`![${file.name}](${getFileUrl(file.path)})`} + {`[${file.name}](${getFileUrl(file.path)})`}

+ {file.mimeType.startsWith("image/") && ( +
+ +

+ {`${file.name}${getFileUrl(file.path)}`} +

+ ${getFileUrl(file.path)}`} + /> +
+ )} ); From 0a128254d3c1bed62602a8a8d412cc91ccfc4508 Mon Sep 17 00:00:00 2001 From: oiov Date: Thu, 17 Jul 2025 10:15:23 +0800 Subject: [PATCH 3/6] chore empty bucket tip --- .../storage/admin/s3/files/configs/route.ts | 6 ---- components/file/file-list.tsx | 4 +-- components/file/index.tsx | 35 ++++++++++--------- public/sw.js.map | 2 +- 4 files changed, 22 insertions(+), 25 deletions(-) diff --git a/app/api/storage/admin/s3/files/configs/route.ts b/app/api/storage/admin/s3/files/configs/route.ts index 84e1353..5ac2bed 100644 --- a/app/api/storage/admin/s3/files/configs/route.ts +++ b/app/api/storage/admin/s3/files/configs/route.ts @@ -33,12 +33,6 @@ export async function GET(req: NextRequest) { })) .filter((c) => c.buckets.length > 0); - if (processedList.length === 0) { - return NextResponse.json("No buckets found", { - status: 404, - }); - } - return NextResponse.json(processedList); } catch (error) { console.error("[Error]", error); diff --git a/components/file/file-list.tsx b/components/file/file-list.tsx index 80148af..d537a72 100644 --- a/components/file/file-list.tsx +++ b/components/file/file-list.tsx @@ -357,10 +357,10 @@ export default function UserFileList({ +

{file.user.name}

{file.user.email}

- +
} > {file.user.name ?? file.user.email} diff --git a/components/file/index.tsx b/components/file/index.tsx index d5e0521..01d1457 100644 --- a/components/file/index.tsx +++ b/components/file/index.tsx @@ -288,7 +288,7 @@ export default function UserFileManager({ user, action }: FileListProps) { - {s3Configs.map((provider) => ( + {s3Configs.map((provider, index) => ( {provider.provider_name} {provider.buckets?.map((item) => ( @@ -299,7 +299,7 @@ export default function UserFileManager({ user, action }: FileListProps) { {item.bucket} ))} - + {index !== s3Configs.length - 1 && } ))} @@ -415,25 +415,28 @@ export default function UserFileManager({ user, action }: FileListProps) { )} - {!isLoading && !error && !s3Configs && !currentBucketInfo && ( - - - - {t("No buckets found")} - - - {t( - "The administrator has not configured the storage bucket, no file can be uploaded", - )} - - - )} + {!isLoading && + !error && + !s3Configs?.length && + !currentBucketInfo.bucket && ( + + + + {t("No buckets found")} + + + {t( + "The administrator has not configured the storage bucket, no file can be uploaded", + )} + + + )} {!isLoading && !error && s3Configs && s3Configs.length > 0 && - currentBucketInfo && ( + currentBucketInfo.bucket && ( { if (response && response.type === 'opaqueredirect') { return new Response(response.body, { status: 200, statusText: 'OK', headers: response.headers }) } return response } }] }), 'GET');\nworkbox_routing_registerRoute(/.*/i, new workbox_strategies_NetworkOnly({ \"cacheName\":\"dev\", plugins: [] }), 'GET');\n\n\n\n\n"],"names":["importScripts","self","skipWaiting","workbox_core_clientsClaim","workbox_routing_registerRoute","workbox_strategies_NetworkFirst","plugins","cacheWillUpdate","request","response","event","state","type","Response","body","status","statusText","headers","workbox_strategies_NetworkOnly"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"sw.js","sources":["../../../../../../private/var/folders/9b/3qmyp8zd2xvdspdrp149fyg00000gn/T/da3081931a4b4b8e0299a7aed11c8d3e/sw.js"],"sourcesContent":["import {registerRoute as workbox_routing_registerRoute} from '/Users/songjunxi/Desktop/repos/wrdo-app/wr.do/node_modules/.pnpm/workbox-routing@6.6.0/node_modules/workbox-routing/registerRoute.mjs';\nimport {NetworkFirst as workbox_strategies_NetworkFirst} from '/Users/songjunxi/Desktop/repos/wrdo-app/wr.do/node_modules/.pnpm/workbox-strategies@6.6.0/node_modules/workbox-strategies/NetworkFirst.mjs';\nimport {NetworkOnly as workbox_strategies_NetworkOnly} from '/Users/songjunxi/Desktop/repos/wrdo-app/wr.do/node_modules/.pnpm/workbox-strategies@6.6.0/node_modules/workbox-strategies/NetworkOnly.mjs';\nimport {clientsClaim as workbox_core_clientsClaim} from '/Users/songjunxi/Desktop/repos/wrdo-app/wr.do/node_modules/.pnpm/workbox-core@6.6.0/node_modules/workbox-core/clientsClaim.mjs';/**\n * Welcome to your Workbox-powered service worker!\n *\n * You'll need to register this file in your web app.\n * See https://goo.gl/nhQhGp\n *\n * The rest of the code is auto-generated. Please don't update this file\n * directly; instead, make changes to your Workbox build configuration\n * and re-run your build process.\n * See https://goo.gl/2aRDsh\n */\n\n\nimportScripts(\n \n);\n\n\n\n\n\n\n\nself.skipWaiting();\n\nworkbox_core_clientsClaim();\n\n\n\nworkbox_routing_registerRoute(\"/\", new workbox_strategies_NetworkFirst({ \"cacheName\":\"start-url\", plugins: [{ cacheWillUpdate: async ({ request, response, event, state }) => { if (response && response.type === 'opaqueredirect') { return new Response(response.body, { status: 200, statusText: 'OK', headers: response.headers }) } return response } }] }), 'GET');\nworkbox_routing_registerRoute(/.*/i, new workbox_strategies_NetworkOnly({ \"cacheName\":\"dev\", plugins: [] }), 'GET');\n\n\n\n\n"],"names":["importScripts","self","skipWaiting","workbox_core_clientsClaim","workbox_routing_registerRoute","workbox_strategies_NetworkFirst","plugins","cacheWillUpdate","request","response","event","state","type","Response","body","status","statusText","headers","workbox_strategies_NetworkOnly"],"mappings":"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"} \ No newline at end of file From 877e826d23caf4fdccc9556b9f8aa00440340e8f Mon Sep 17 00:00:00 2001 From: oiov Date: Sun, 20 Jul 2025 19:53:38 +0800 Subject: [PATCH 4/6] feat(s3): add custom provider section --- app/(protected)/admin/storage/loading.tsx | 4 ++-- app/(protected)/admin/system/s3-list.tsx | 8 ++++++-- app/(protected)/dashboard/storage/loading.tsx | 4 ++-- app/api/storage/s3/files/route.ts | 1 + 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/app/(protected)/admin/storage/loading.tsx b/app/(protected)/admin/storage/loading.tsx index 1eab0dd..835c8cf 100644 --- a/app/(protected)/admin/storage/loading.tsx +++ b/app/(protected)/admin/storage/loading.tsx @@ -5,8 +5,8 @@ export default function DashboardRecordsLoading() { return ( <> diff --git a/app/(protected)/admin/system/s3-list.tsx b/app/(protected)/admin/system/s3-list.tsx index f78f408..2e9dee0 100644 --- a/app/(protected)/admin/system/s3-list.tsx +++ b/app/(protected)/admin/system/s3-list.tsx @@ -3,7 +3,6 @@ import { useEffect, useMemo, useState, useTransition } from "react"; import Link from "next/link"; import { motion } from "framer-motion"; -import { CloudCog } from "lucide-react"; import { useTranslations } from "next-intl"; import { toast } from "sonner"; import useSWR from "swr"; @@ -63,7 +62,12 @@ export default function S3Configs({}: {}) { channel: "cos", }, { label: "Ali OSS", value: "Ali OSS", platform: "ali", channel: "oss" }, - { label: "Minio", value: "Minio", platform: "minio", channel: "s3" }, + { + label: "Custom Provider", + value: "Custom Provider", + platform: "custom", + channel: "cp", + }, ]; useEffect(() => { diff --git a/app/(protected)/dashboard/storage/loading.tsx b/app/(protected)/dashboard/storage/loading.tsx index 1eab0dd..835c8cf 100644 --- a/app/(protected)/dashboard/storage/loading.tsx +++ b/app/(protected)/dashboard/storage/loading.tsx @@ -5,8 +5,8 @@ export default function DashboardRecordsLoading() { return ( <> diff --git a/app/api/storage/s3/files/route.ts b/app/api/storage/s3/files/route.ts index 6408b67..0c4022d 100644 --- a/app/api/storage/s3/files/route.ts +++ b/app/api/storage/s3/files/route.ts @@ -162,6 +162,7 @@ export async function DELETE(request: NextRequest) { await softDeleteUserFiles(ids); return NextResponse.json({ message: "File deleted successfully" }); } catch (error) { + console.error("Error deleting file:", error); return NextResponse.json("Error deleting file", { status: 500 }); } } From d25de8d0f7d6d36453c6d7ae9dcb11a737317279 Mon Sep 17 00:00:00 2001 From: weiruchenai1 <1627333583@qq.com> Date: Mon, 21 Jul 2025 00:24:44 +0800 Subject: [PATCH 5/6] feat: improve file upload error handling and add Chinese localization --- app/(protected)/admin/system/s3-list.tsx | 22 +++++++++++ app/api/storage/s3/upload/route.ts | 21 +++++++++++ components/file/upload.tsx | 47 ++++++++++++++---------- hooks/use-file-upload.ts | 25 +++++++++++-- lib/dto/files.ts | 38 ++++++++++++++++++- lib/r2.ts | 1 + locales/en.json | 2 + locales/zh.json | 2 + 8 files changed, 134 insertions(+), 24 deletions(-) diff --git a/app/(protected)/admin/system/s3-list.tsx b/app/(protected)/admin/system/s3-list.tsx index 2e9dee0..49fdd4c 100644 --- a/app/(protected)/admin/system/s3-list.tsx +++ b/app/(protected)/admin/system/s3-list.tsx @@ -446,6 +446,7 @@ export default function S3Configs({}: {}) { region: "auto", custom_domain: "", file_size: "26214400", + max_storage: "", public: true, }); setS3Configs( @@ -538,6 +539,26 @@ export default function S3Configs({}: {}) { /> +
+ +
+ + updateBucket(index2, { max_storage: e.target.value }) + } + /> + {bucket.max_storage && ( + + ≈{(Number(bucket.max_storage) / (1024 * 1024 * 1024)).toFixed(1)}GB + + )} +
+
+
@@ -592,6 +613,7 @@ export default function S3Configs({}: {}) { region: "auto", custom_domain: "", file_size: "26214400", + max_storage: "", public: true, }, ], diff --git a/app/api/storage/s3/upload/route.ts b/app/api/storage/s3/upload/route.ts index 7846743..fb86fb2 100644 --- a/app/api/storage/s3/upload/route.ts +++ b/app/api/storage/s3/upload/route.ts @@ -2,6 +2,7 @@ import { NextRequest, NextResponse } from "next/server"; import { GetObjectCommand, PutObjectCommand } from "@aws-sdk/client-s3"; import { getSignedUrl } from "@aws-sdk/s3-request-presigner"; +import { getBucketStorageUsage } from "@/lib/dto/files"; import { getPlanQuota } from "@/lib/dto/plan"; import { getMultipleConfigs } from "@/lib/dto/system-config"; import { checkUserStatus } from "@/lib/dto/user"; @@ -60,6 +61,26 @@ export async function POST(request: NextRequest) { }); if (limit) return Response.json(limit.statusText, { status: limit.status }); + // 检查存储桶容量限制 + const bucketConfig = buckets.find((b) => b.bucket === bucket); + if (bucketConfig?.max_storage) { + const bucketUsage = await getBucketStorageUsage(bucket, provider); + if (bucketUsage.success && bucketUsage.data) { + const currentUsage = bucketUsage.data.totalSize; + const maxStorage = Number(bucketConfig.max_storage); + const totalUploadSize = files.reduce((sum, file) => sum + Number(file.size), 0); + + if (currentUsage + totalUploadSize > maxStorage) { + const remainingSpace = Math.max(0, maxStorage - currentUsage); + const remainingSpaceGB = (remainingSpace / (1024 * 1024 * 1024)).toFixed(2); + return Response.json( + `上传容量超限,剩余空间:${remainingSpaceGB}GB,请更换存储桶或联系管理员`, + { status: 403 } + ); + } + } + } + const R2 = createS3Client( providerChannel.endpoint, providerChannel.access_key_id, diff --git a/components/file/upload.tsx b/components/file/upload.tsx index ac977a6..6c0bf65 100644 --- a/components/file/upload.tsx +++ b/components/file/upload.tsx @@ -257,27 +257,34 @@ export const FileUploader = ({ ) : ( (file.status === "error" || file.status === "cancelled") && ( -
-
-
- {t("Aborted")} +
+
+
+
+ {file.status === "cancelled" ? t("Aborted") : t("Failed")} +
+ +
- - + {file.status === "error" && file.error && ( +
+ {file.error} +
+ )}
) )} diff --git a/hooks/use-file-upload.ts b/hooks/use-file-upload.ts index c0302fd..f938484 100644 --- a/hooks/use-file-upload.ts +++ b/hooks/use-file-upload.ts @@ -146,7 +146,25 @@ export function useFileUpload({ bucketInfo, userId, api }: Props) { }); if (!response.ok) { - throw new Error("获取预签名 URL 失败"); + // 尝试获取后端返回的具体错误信息 + let errorMessage = "获取预签名 URL 失败"; + try { + const errorText = await response.text(); + if (errorText) { + // 如果返回的是JSON格式的错误信息,尝试解析 + try { + const errorData = JSON.parse(errorText); + errorMessage = errorData.message || errorData.error || errorText; + } catch { + // 如果不是JSON,直接使用文本内容 + errorMessage = errorText; + } + } + } catch { + // 如果无法读取响应内容,使用默认错误信息 + errorMessage = `上传失败 (${response.status})`; + } + throw new Error(errorMessage); } const data = await response.json(); @@ -331,14 +349,15 @@ export function useFileUpload({ bucketInfo, userId, api }: Props) { await Promise.allSettled(uploadPromises); } catch (error) { console.error("上传失败:", error); - // 将所有 pending 状态的文件设置为错误状态 + // 将所有 pending 状态的文件设置为错误状态,并显示具体错误信息 + const errorMessage = error instanceof Error ? error.message : "上传失败"; setFiles((prev) => prev.map((file) => file.status === "pending" ? { ...file, status: "error", - error: "上传失败", + error: errorMessage, } : file, ), diff --git a/lib/dto/files.ts b/lib/dto/files.ts index a093ad7..0941ac7 100644 --- a/lib/dto/files.ts +++ b/lib/dto/files.ts @@ -274,7 +274,7 @@ export async function getUserFileStats(userId: string) { success: true, data: { totalFiles, - totalSize: totalSize._sum.size || 0, + totalSize: storageValueToBytes(totalSize._sum.size || 0), filesByProvider, }, }; @@ -357,3 +357,39 @@ export async function cleanupExpiredFiles(days: number = 30) { return { success: false, error: "Failed to clean up expired files" }; } } + +// 获取特定存储桶的使用量统计 +export async function getBucketStorageUsage( + bucket: string, + providerName: string, +): Promise< + | { success: true; data: { totalSize: number; totalFiles: number } } + | { success: false; error: string } +> { + try { + const result = await prisma.userFile.aggregate({ + where: { + bucket, + providerName, + status: 1, + }, + _sum: { + size: true, + }, + _count: { + id: true, + }, + }); + + return { + success: true, + data: { + totalSize: storageValueToBytes(result._sum.size || 0), + totalFiles: result._count.id || 0, + }, + }; + } catch (error) { + console.error("Failed to get bucket storage usage:", error); + return { success: false, error: "Failed to get bucket storage usage" }; + } +} diff --git a/lib/r2.ts b/lib/r2.ts index 3aa3b98..dbf54ce 100644 --- a/lib/r2.ts +++ b/lib/r2.ts @@ -34,6 +34,7 @@ export interface BucketItem { prefix?: string; file_types?: string; file_size?: string; + max_storage?: string; // 存储桶最大存储容量(字节) region?: string; public: boolean; } diff --git a/locales/en.json b/locales/en.json index 73ec486..efea390 100644 --- a/locales/en.json +++ b/locales/en.json @@ -360,6 +360,7 @@ "Uploading": "Uploading", "Completed": "Completed", "Aborted": "Aborted", + "Failed": "Failed", "Drop files to upload them to": "Drop files to upload them to", "Drag and drop file(s) here": "Drag and drop file(s) here", "or": "or", @@ -623,6 +624,7 @@ "Region": "Region", "Prefix": "Prefix", "Optional": "Optional", + "Max Storage": "Max Storage", "Allowed File Types": "Allowed File Types", "Public": "Public", "Publicize this storage bucket, all registered users can upload files to this storage bucket; If not public, only administrators can upload files to this storage bucket": "Publicize this storage bucket, all registered users can upload files to this storage bucket; If not public, only administrators can upload files to this storage bucket", diff --git a/locales/zh.json b/locales/zh.json index 237aa1e..0a79d0a 100644 --- a/locales/zh.json +++ b/locales/zh.json @@ -360,6 +360,7 @@ "Uploading": "上传中", "Completed": "已完成", "Aborted": "已中止", + "Failed": "失败", "Drop files to upload them to": "将文件上传到", "Drag and drop file(s) here": "将文件拖到此处上传", "or": "或", @@ -623,6 +624,7 @@ "Region": "存储桶区域", "Prefix": "前缀", "Optional": "可选", + "Max Storage": "最大存储容量", "Allowed File Types": "允许的文件类型", "Public": "公开", "Publicize this storage bucket, all registered users can upload files to this storage bucket; If not public, only administrators can upload files to this storage bucket": "公开此存储桶,所有注册用户都可以上传文件到此存储桶; 若不公开,只有管理员可以上传文件到此存储桶", From 509ad15652e6489bf2504a709069495b26229f6c Mon Sep 17 00:00:00 2001 From: weiruchenai1 <1627333583@qq.com> Date: Tue, 22 Jul 2025 12:47:23 +0800 Subject: [PATCH 6/6] =?UTF-8?q?feat:=20=E5=AE=9E=E7=8E=B0=E5=88=86?= =?UTF-8?q?=E5=B1=82=E5=AD=98=E5=82=A8=E9=85=8D=E9=A2=9D=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E5=92=8CUI=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🆕 新增功能: - 添加存储桶容量限制配置功能,支持按存储桶设置最大容量 - 新增存储桶使用情况API端点 (/api/storage/bucket-usage) - 实现Plan配额和存储桶配额的分层显示 🎨 界面优化: - 存储使用情况面板支持双层配额显示 - 上传错误提示改为右对齐显示 - Toast通知位置改为右下角 - 为存储桶配置添加帮助提示 🔧 功能改进: - 优化上传前容量检查逻辑 - 改进错误信息显示,使用中文提示 - 智能显示更严格的配额限制 - 完善国际化支持 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- app/(protected)/admin/system/s3-list.tsx | 18 +++- app/api/storage/bucket-usage/route.ts | 72 +++++++++++++++ app/api/storage/s3/upload/route.ts | 7 +- app/layout.tsx | 2 +- components/file/index.tsx | 26 +++++- components/file/storage-size.tsx | 109 +++++++++++++++++++---- components/file/upload.tsx | 4 +- locales/en.json | 6 ++ locales/zh.json | 6 ++ 9 files changed, 224 insertions(+), 26 deletions(-) create mode 100644 app/api/storage/bucket-usage/route.ts diff --git a/app/(protected)/admin/system/s3-list.tsx b/app/(protected)/admin/system/s3-list.tsx index 49fdd4c..3d14090 100644 --- a/app/(protected)/admin/system/s3-list.tsx +++ b/app/(protected)/admin/system/s3-list.tsx @@ -540,9 +540,21 @@ export default function S3Configs({}: {}) {
- +
+ + + + + + + + {t("maxStorageTooltip")} + + + +
c.provider_name === provider, + ); + if (!providerConfig) { + return NextResponse.json("Provider does not exist", { + status: 400, + }); + } + + const bucketConfig = providerConfig.buckets?.find( + (b) => b.bucket === bucket, + ); + if (!bucketConfig) { + return NextResponse.json("Bucket does not exist", { + status: 400, + }); + } + + // 获取存储桶使用情况 + const bucketUsage = await getBucketStorageUsage(bucket, provider); + if (!bucketUsage.success) { + return NextResponse.json("Failed to get bucket usage", { + status: 500, + }); + } + + return NextResponse.json({ + bucket: bucket, + provider: provider, + usage: { + totalSize: bucketUsage.data.totalSize, + totalFiles: bucketUsage.data.totalFiles, + }, + limits: { + maxStorage: bucketConfig.max_storage ? Number(bucketConfig.max_storage) : null, + }, + }); + } catch (error) { + console.error("Error getting bucket usage:", error); + return NextResponse.json({ error: "Server Error" }, { status: 500 }); + } +} \ No newline at end of file diff --git a/app/api/storage/s3/upload/route.ts b/app/api/storage/s3/upload/route.ts index fb86fb2..6525479 100644 --- a/app/api/storage/s3/upload/route.ts +++ b/app/api/storage/s3/upload/route.ts @@ -63,18 +63,19 @@ export async function POST(request: NextRequest) { // 检查存储桶容量限制 const bucketConfig = buckets.find((b) => b.bucket === bucket); + const totalUploadSize = files.reduce((sum, file) => sum + Number(file.size), 0); + if (bucketConfig?.max_storage) { const bucketUsage = await getBucketStorageUsage(bucket, provider); if (bucketUsage.success && bucketUsage.data) { const currentUsage = bucketUsage.data.totalSize; const maxStorage = Number(bucketConfig.max_storage); - const totalUploadSize = files.reduce((sum, file) => sum + Number(file.size), 0); if (currentUsage + totalUploadSize > maxStorage) { - const remainingSpace = Math.max(0, maxStorage - currentUsage); + const remainingSpace = maxStorage - currentUsage; const remainingSpaceGB = (remainingSpace / (1024 * 1024 * 1024)).toFixed(2); return Response.json( - `上传容量超限,剩余空间:${remainingSpaceGB}GB,请更换存储桶或联系管理员`, + `存储桶容量不足!剩余 ${remainingSpaceGB}GB,请更换存储桶`, { status: 403 } ); } diff --git a/app/layout.tsx b/app/layout.tsx index 5e3e093..d2a2fcc 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -43,7 +43,7 @@ export default async function RootLayout({ children }: RootLayoutProps) { disableTransitionOnChange > {children} - + diff --git a/components/file/index.tsx b/components/file/index.tsx index 01d1457..8702f39 100644 --- a/components/file/index.tsx +++ b/components/file/index.tsx @@ -124,6 +124,17 @@ export default function UserFileManager({ user, action }: FileListProps) { fetcher, ); + const { data: bucketUsage } = useSWR( + currentBucketInfo.bucket && currentBucketInfo.provider_name + ? `/api/storage/bucket-usage?bucket=${currentBucketInfo.bucket}&provider=${currentBucketInfo.provider_name}` + : null, + fetcher, + { + revalidateOnFocus: false, + refreshInterval: 30000, // 每30秒更新一次 + }, + ); + useEffect(() => { if (s3Configs && s3Configs.length > 0) { setCurrentProvider(s3Configs[0]); @@ -261,11 +272,22 @@ export default function UserFileManager({ user, action }: FileListProps) { - +
} > - + )} {/* Bucket Select */} diff --git a/components/file/storage-size.tsx b/components/file/storage-size.tsx index 53b5d08..e3e2306 100644 --- a/components/file/storage-size.tsx +++ b/components/file/storage-size.tsx @@ -1,14 +1,21 @@ import React from "react"; -import { AlertTriangle, CheckCircle, HardDrive } from "lucide-react"; +import { AlertTriangle, CheckCircle, HardDrive, Folder } from "lucide-react"; import { formatFileSize } from "@/lib/utils"; -export function FileSizeDisplay({ files, plan, t }) { +export function FileSizeDisplay({ files, plan, bucketInfo, bucketUsage, t }) { const totalSize = files?.totalSize || 0; const maxSize = Number(plan?.stMaxTotalSize || 0); const usagePercentage = maxSize > 0 ? Math.min((totalSize / maxSize) * 100, 100) : 0; + // 存储桶级别的配额信息 + const bucketTotalSize = bucketUsage?.usage?.totalSize || 0; + const bucketMaxSize = bucketUsage?.limits?.maxStorage || 0; + const bucketUsagePercentage = + bucketMaxSize > 0 ? Math.min((bucketTotalSize / bucketMaxSize) * 100, 100) : 0; + const hasBucketLimit = bucketMaxSize > 0; + const getStatusColor = (percentage) => { if (percentage >= 90) return "text-red-600"; if (percentage >= 70) return "text-yellow-600"; @@ -55,8 +62,11 @@ export function FileSizeDisplay({ files, plan, t }) {
- {/* 详细信息 */} + {/* Plan级别详细信息 */}
+
+ {t("planQuota")} +
{t("usedSpace")}: @@ -83,34 +93,103 @@ export function FileSizeDisplay({ files, plan, t }) {
+ {/* 存储桶级别信息 */} + {hasBucketLimit && ( + <> +
+
+ + + {t("bucketQuota")} - {bucketInfo?.bucket} + +
+
+ + {t("used")} + + + {bucketUsagePercentage.toFixed(1)}% + +
+
+
+
+
+
+ + {t("usedSpace")}: + + + {formatFileSize(bucketTotalSize, { precision: 2 })} + +
+
+ + {t("bucketCapacity")}: + + + {formatFileSize(bucketMaxSize, { precision: 2 })} + +
+
+ + {t("availableSpace")}: + + + {formatFileSize(bucketMaxSize - bucketTotalSize, { precision: 2 })} + +
+
+
+ + )} + {/* 状态提示 */}
usagePercentage ? bucketUsagePercentage : usagePercentage)}`} > - {getStatusIcon(usagePercentage)} + {getStatusIcon(hasBucketLimit && bucketUsagePercentage > usagePercentage ? bucketUsagePercentage : usagePercentage)} - {usagePercentage >= 90 - ? t("storageFull") - : usagePercentage >= 70 - ? t("storageHigh") - : t("storageGood")} + {(() => { + const criticalPercentage = hasBucketLimit && bucketUsagePercentage > usagePercentage ? bucketUsagePercentage : usagePercentage; + if (criticalPercentage >= 90) { + return hasBucketLimit && bucketUsagePercentage >= 90 ? t("bucketStorageFull") : t("storageFull"); + } else if (criticalPercentage >= 70) { + return hasBucketLimit && bucketUsagePercentage >= 70 ? t("bucketStorageHigh") : t("storageHigh"); + } else { + return t("storageGood"); + } + })()}
); } -export function CircularStorageIndicator({ files, plan, size = 32 }) { +export function CircularStorageIndicator({ files, plan, bucketUsage, size = 32 }) { const totalSize = files?.totalSize || 0; const maxSize = Number(plan?.stMaxTotalSize || 0); const usagePercentage = maxSize > 0 ? Math.min((totalSize / maxSize) * 100, 100) : 0; + // 存储桶级别的配额信息 + const bucketTotalSize = bucketUsage?.usage?.totalSize || 0; + const bucketMaxSize = bucketUsage?.limits?.maxStorage || 0; + const bucketUsagePercentage = + bucketMaxSize > 0 ? Math.min((bucketTotalSize / bucketMaxSize) * 100, 100) : 0; + const hasBucketLimit = bucketMaxSize > 0; + + // 使用更严格的限制来显示 + const displayPercentage = hasBucketLimit && bucketUsagePercentage > usagePercentage ? bucketUsagePercentage : usagePercentage; + // 圆形参数 const radius = (size - 6) / 2; const circumference = 2 * Math.PI * radius; const strokeDashoffset = - circumference - (usagePercentage / 100) * circumference; + circumference - (displayPercentage / 100) * circumference; // 根据使用率确定颜色 const getColor = (percentage) => { @@ -139,7 +218,7 @@ export function CircularStorageIndicator({ files, plan, size = 32 }) { cx={size / 2} cy={size / 2} r={radius} - stroke={getColor(usagePercentage)} + stroke={getColor(displayPercentage)} strokeWidth="3" fill="none" strokeLinecap="round" @@ -150,9 +229,9 @@ export function CircularStorageIndicator({ files, plan, size = 32 }) {
- {Math.round(usagePercentage)}% + {Math.round(displayPercentage)}%
); diff --git a/components/file/upload.tsx b/components/file/upload.tsx index 6c0bf65..77f355f 100644 --- a/components/file/upload.tsx +++ b/components/file/upload.tsx @@ -258,7 +258,7 @@ export const FileUploader = ({ (file.status === "error" || file.status === "cancelled") && (
-
+
{file.status === "cancelled" ? t("Aborted") : t("Failed")} @@ -281,7 +281,7 @@ export const FileUploader = ({
{file.status === "error" && file.error && ( -
+
{file.error}
)} diff --git a/locales/en.json b/locales/en.json index efea390..4bbf049 100644 --- a/locales/en.json +++ b/locales/en.json @@ -214,6 +214,11 @@ "storageFull": "Storage space is almost full", "storageHigh": "Storage space usage is high", "storageGood": "Storage space is sufficient", + "planQuota": "Plan Quota", + "bucketQuota": "Bucket Quota", + "bucketCapacity": "Bucket Capacity", + "bucketStorageFull": "Bucket storage is almost full", + "bucketStorageHigh": "Bucket storage usage is high", "items": "items", "Total": "Total", "Configuration Error": "Configuration Error" @@ -625,6 +630,7 @@ "Prefix": "Prefix", "Optional": "Optional", "Max Storage": "Max Storage", + "maxStorageTooltip": "Set maximum storage capacity for this bucket (in bytes). If not set, uses plan quota global limit.", "Allowed File Types": "Allowed File Types", "Public": "Public", "Publicize this storage bucket, all registered users can upload files to this storage bucket; If not public, only administrators can upload files to this storage bucket": "Publicize this storage bucket, all registered users can upload files to this storage bucket; If not public, only administrators can upload files to this storage bucket", diff --git a/locales/zh.json b/locales/zh.json index 0a79d0a..5c87543 100644 --- a/locales/zh.json +++ b/locales/zh.json @@ -214,6 +214,11 @@ "storageFull": "存储空间即将用完", "storageHigh": "存储空间使用较多", "storageGood": "存储空间充足", + "planQuota": "计划配额", + "bucketQuota": "存储桶配额", + "bucketCapacity": "存储桶容量", + "bucketStorageFull": "存储桶空间即将用完", + "bucketStorageHigh": "存储桶空间使用较多", "items": "条", "Total": "共", "Configuration Error": "配置错误" @@ -625,6 +630,7 @@ "Prefix": "前缀", "Optional": "可选", "Max Storage": "最大存储容量", + "maxStorageTooltip": "设置此存储桶的最大存储容量(字节)。如果不设置,默认使用 Plan 配额的全局限制。", "Allowed File Types": "允许的文件类型", "Public": "公开", "Publicize this storage bucket, all registered users can upload files to this storage bucket; If not public, only administrators can upload files to this storage bucket": "公开此存储桶,所有注册用户都可以上传文件到此存储桶; 若不公开,只有管理员可以上传文件到此存储桶",