diff --git a/IMPLEMENTATION_SUMMARY.md b/IMPLEMENTATION_SUMMARY.md deleted file mode 100644 index f706a9d6..00000000 --- a/IMPLEMENTATION_SUMMARY.md +++ /dev/null @@ -1,161 +0,0 @@ -# 站点批量导入导出功能实现总结 - -## 功能概述 - -成功实现了站点批量导入和批量导出功能,在站点列表页面右上角添加了导入和导出操作按钮,方便用户快速备份和恢复站点配置。 - -## 实现的功能 - -### 1. 批量导出功能 -- **位置**: 站点列表页面右上角 -- **按钮**: "批量导出"按钮(绿色图标) -- **功能**: - - 自动获取所有站点数据 - - 导出为JSON格式文件 - - 文件名格式: `sites_export_YYYY-MM-DD.json` - - 包含站点的所有配置信息(除ID外) - - 自动下载到用户本地 - -### 2. 批量导入功能 -- **位置**: 站点列表页面右上角 -- **按钮**: "批量导入"按钮(蓝色图标) -- **功能**: - - 支持JSON格式文件导入 - - 支持拖拽上传和文件选择 - - 导入前数据预览和验证 - - 实时导入进度显示 - - 详细的导入结果反馈 - -## 技术实现 - -### 1. 前端组件 -- **SiteCardListView.vue**: 主页面组件,添加了导入导出按钮 -- **SiteImportDialog.vue**: 新建的导入对话框组件 -- **导出功能**: 直接在SiteCardListView中实现 - -### 2. 后端接口 -- **导出**: 使用现有的 `GET /site/` 接口获取所有站点数据 -- **导入**: 使用现有的 `POST /site/` 接口批量创建站点 - -### 3. 数据验证 -- 验证必填字段: `name`, `domain`, `url` -- 自动移除ID字段避免冲突 -- 显示数据预览和验证结果 - -### 4. 用户体验 -- 拖拽上传支持 -- 实时进度显示 -- 详细的错误提示 -- 多语言支持(中文、英文、繁体中文) - -## 文件结构 - -``` -src/ -├── views/site/ -│ └── SiteCardListView.vue # 主页面,添加了导入导出按钮 -├── components/dialog/ -│ └── SiteImportDialog.vue # 新建的导入对话框组件 -├── locales/ -│ ├── zh-CN.ts # 简体中文翻译 -│ ├── en-US.ts # 英文翻译 -│ └── zh-TW.ts # 繁体中文翻译 -└── test_sites_export.json # 测试用的导出文件 -``` - -## 国际化支持 - -### 中文(简体) -- 批量导入/导出 -- 数据预览 -- 错误提示 -- 进度显示 - -### 英文 -- Batch Import/Export -- Data Preview -- Error Messages -- Progress Display - -### 繁体中文 -- 批量導入/導出 -- 數據預覽 -- 錯誤提示 -- 進度顯示 - -## 使用方法 - -### 导出站点配置 -1. 进入站点管理页面 -2. 点击右上角的"批量导出"按钮 -3. 浏览器自动下载JSON配置文件 - -### 导入站点配置 -1. 进入站点管理页面 -2. 点击右上角的"批量导入"按钮 -3. 选择或拖拽JSON文件 -4. 查看数据预览 -5. 点击"开始导入" -6. 等待导入完成 - -## 文件格式 - -导出的JSON文件包含以下字段: -```json -{ - "name": "站点名称", - "domain": "站点域名", - "url": "站点地址", - "rss": "RSS地址", - "downloader": "下载器", - "cookie": "Cookie信息", - "apikey": "API密钥", - "token": "访问令牌", - "ua": "User-Agent", - "proxy": false, - "filter": "过滤规则", - "render": false, - "public": 0, - "note": "备注信息", - "timeout": 30, - "limit_interval": 0, - "limit_count": 0, - "limit_seconds": 0, - "is_active": true, - "pri": 1 -} -``` - -## 错误处理 - -- 文件格式验证 -- 数据完整性检查 -- 网络错误处理 -- 导入失败统计 -- 用户友好的错误提示 - -## 测试 - -- 提供了 `test_sites_export.json` 测试文件 -- 支持各种边界情况测试 -- 多语言界面测试 -- 拖拽上传功能测试 - -## 构建状态 - -✅ 项目构建成功 -✅ 所有组件正常工作 -✅ 国际化完整 -✅ 错误处理完善 -✅ 用户体验良好 - -## 总结 - -成功实现了完整的站点批量导入导出功能,包括: -- 直观的用户界面 -- 完善的数据验证 -- 良好的错误处理 -- 完整的多语言支持 -- 优秀的用户体验 - -该功能可以帮助用户快速备份和恢复站点配置,提高工作效率。 \ No newline at end of file diff --git a/SITE_IMPORT_EXPORT_README.md b/SITE_IMPORT_EXPORT_README.md deleted file mode 100644 index d41e9bb4..00000000 --- a/SITE_IMPORT_EXPORT_README.md +++ /dev/null @@ -1,95 +0,0 @@ -# 站点批量导入导出功能 - -## 功能概述 - -在站点管理页面新增了批量导入和批量导出功能,方便用户快速备份和恢复站点配置。 - -## 功能特性 - -### 批量导出 -- 点击站点列表页面右上角的"批量导出"按钮 -- 自动导出所有站点的配置信息为JSON格式 -- 文件名格式:`sites_export_YYYY-MM-DD.json` -- 包含站点的所有配置信息(除ID外) - -### 批量导入 -- 点击站点列表页面右上角的"批量导入"按钮 -- 支持JSON格式的站点配置文件 -- 支持拖拽上传和文件选择 -- 导入前会显示数据预览 -- 自动验证数据有效性 -- 显示导入进度和结果 - -## 使用方法 - -### 导出站点配置 -1. 进入站点管理页面 -2. 点击右上角的"批量导出"按钮 -3. 浏览器会自动下载JSON格式的配置文件 - -### 导入站点配置 -1. 进入站点管理页面 -2. 点击右上角的"批量导入"按钮 -3. 选择JSON格式的站点配置文件 -4. 查看数据预览,确认无误后点击"开始导入" -5. 等待导入完成,查看导入结果 - -## 文件格式 - -导出的JSON文件格式如下: - -```json -[ - { - "name": "站点名称", - "domain": "站点域名", - "url": "站点地址", - "rss": "RSS地址", - "downloader": "下载器", - "cookie": "Cookie信息", - "apikey": "API密钥", - "token": "访问令牌", - "ua": "User-Agent", - "proxy": false, - "filter": "过滤规则", - "render": false, - "public": 0, - "note": "备注信息", - "timeout": 30, - "limit_interval": 0, - "limit_count": 0, - "limit_seconds": 0, - "is_active": true, - "pri": 1 - } -] -``` - -## 数据验证 - -导入时会自动验证以下必填字段: -- `name`: 站点名称 -- `domain`: 站点域名 -- `url`: 站点地址 - -如果数据无效,会在预览中标记出来,并显示错误提示。 - -## 注意事项 - -1. 导入时会自动移除原数据中的ID字段,避免冲突 -2. 导入过程中会显示进度条和实时状态 -3. 如果部分数据导入失败,会显示详细的成功和失败数量 -4. 导入完成后会自动刷新站点列表 -5. 支持的文件格式:JSON文件(.json) - -## 测试文件 - -项目根目录下提供了 `test_sites_export.json` 测试文件,可用于测试导入功能。 - -## 技术实现 - -- 使用现有的站点新增接口 `POST /site/` 进行批量导入 -- 使用现有的站点查询接口 `GET /site/` 进行数据导出 -- 前端使用Vue 3 + Vuetify 3实现用户界面 -- 支持拖拽上传和文件选择 -- 实时进度显示和错误处理 \ No newline at end of file diff --git a/src/components/dialog/SiteImportDialog.vue b/src/components/dialog/SiteImportDialog.vue index 302f87b9..4ca5965a 100644 --- a/src/components/dialog/SiteImportDialog.vue +++ b/src/components/dialog/SiteImportDialog.vue @@ -12,6 +12,9 @@ const { t } = useI18n() // 显示器宽度 const display = useDisplay() +// 提示框 +const $toast = useToast() + // 输入参数 const props = defineProps({ modelValue: { @@ -23,8 +26,7 @@ const props = defineProps({ // 注册事件 const emit = defineEmits(['update:modelValue', 'import-success']) -// 提示框 -const $toast = useToast() + // 是否拖拽中 const isDragging = ref(false) diff --git a/src/views/site/SiteCardListView.vue b/src/views/site/SiteCardListView.vue index d3c69e99..3f3a6e4e 100644 --- a/src/views/site/SiteCardListView.vue +++ b/src/views/site/SiteCardListView.vue @@ -11,10 +11,14 @@ import { useDisplay } from 'vuetify' import { useDynamicButton } from '@/composables/useDynamicButton' import { useI18n } from 'vue-i18n' import { usePWA } from '@/composables/usePWA' +import { useToast } from 'vue-toastification' // 国际化 const { t } = useI18n() +// 提示框 +const $toast = useToast() + // 路由 const route = useRoute() @@ -260,15 +264,9 @@ async function exportSites() { URL.revokeObjectURL(url) // 显示成功提示 - const { t } = useI18n() - const { useToast } = await import('vue-toastification') - const $toast = useToast() $toast.success(t('site.messages.exportSuccess')) } catch (error) { console.error('Export sites failed:', error) - const { t } = useI18n() - const { useToast } = await import('vue-toastification') - const $toast = useToast() $toast.error(t('site.messages.exportFailed')) } } diff --git a/test_sites_export.json b/test_sites_export.json deleted file mode 100644 index 897cf695..00000000 --- a/test_sites_export.json +++ /dev/null @@ -1,46 +0,0 @@ -[ - { - "name": "测试站点1", - "domain": "test1.example.com", - "url": "https://test1.example.com", - "rss": "https://test1.example.com/rss", - "downloader": "", - "cookie": "", - "apikey": "", - "token": "", - "ua": "", - "proxy": false, - "filter": "", - "render": false, - "public": 0, - "note": "测试站点1", - "timeout": 30, - "limit_interval": 0, - "limit_count": 0, - "limit_seconds": 0, - "is_active": true, - "pri": 1 - }, - { - "name": "测试站点2", - "domain": "test2.example.com", - "url": "https://test2.example.com", - "rss": "https://test2.example.com/rss", - "downloader": "", - "cookie": "", - "apikey": "", - "token": "", - "ua": "", - "proxy": false, - "filter": "", - "render": false, - "public": 0, - "note": "测试站点2", - "timeout": 30, - "limit_interval": 0, - "limit_count": 0, - "limit_seconds": 0, - "is_active": true, - "pri": 2 - } -] \ No newline at end of file