412 lines
11 KiB
Markdown
412 lines
11 KiB
Markdown
|
|
# XK 文件工具箱 - 功能结构分析
|
|||
|
|
|
|||
|
|
## 一、项目概述
|
|||
|
|
|
|||
|
|
**技术栈**: Wails v2 (Go 1.25 + Vue 3)
|
|||
|
|
**应用类型**: Windows 原生桌面文件处理工具
|
|||
|
|
**核心功能**: PDF、Word、Excel、图片四大类文件处理
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 二、模块功能分析
|
|||
|
|
|
|||
|
|
### 2.1 已正确实现的功能 ✅
|
|||
|
|
|
|||
|
|
#### 架构设计
|
|||
|
|
1. **组件化架构完善**
|
|||
|
|
- ToolView.vue 已将各工具拆分为独立子组件
|
|||
|
|
- 12个图片工具组件(ImageCompressTool、ImageResizeTool等)
|
|||
|
|
- 8个PDF工具组件(PdfCompressTool、PdfToImageTool等)
|
|||
|
|
- 清晰的 props/emit 通信机制
|
|||
|
|
|
|||
|
|
2. **路由系统合理**
|
|||
|
|
- Hash 路由支持 `/tool/:category/:action` 动态切换
|
|||
|
|
- 路由参数驱动工具界面渲染
|
|||
|
|
- 状态重置逻辑正确
|
|||
|
|
|
|||
|
|
3. **文件处理流程完整**
|
|||
|
|
- 选择 → 预览 → 参数配置 → 处理 → 结果展示
|
|||
|
|
- 支持文件拖拽上传
|
|||
|
|
- Base64 预览机制正常工作
|
|||
|
|
|
|||
|
|
4. **数据持久化**
|
|||
|
|
- 最近使用记录(本地JSON存储,最多5条)
|
|||
|
|
- 默认输出目录配置保存在用户主目录
|
|||
|
|
- 快捷方式自定义保存
|
|||
|
|
|
|||
|
|
#### 业务功能
|
|||
|
|
5. **图片处理基础功能可用**
|
|||
|
|
- 格式转换(JPEG/PNG/GIF/BMP/TIFF/ICO)
|
|||
|
|
- 调整大小(保持宽高比/自由缩放)
|
|||
|
|
- 旋转、翻转、裁剪
|
|||
|
|
- 灰度、亮度、对比度、饱和度调整
|
|||
|
|
- 锐化、模糊、反色
|
|||
|
|
|
|||
|
|
6. **PDF基础操作可用**(依赖pdfcpu)
|
|||
|
|
- 压缩优化
|
|||
|
|
- 合并、分割
|
|||
|
|
- 旋转、添加水印
|
|||
|
|
- 文本/Markdown/HTML转PDF
|
|||
|
|
|
|||
|
|
7. **Word/Excel转换可用**
|
|||
|
|
- Word转PDF(调用系统Office或LibreOffice)
|
|||
|
|
- Excel转CSV/JSON
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 2.2 实现不当的问题 ❌
|
|||
|
|
|
|||
|
|
#### 问题1: 图片压缩算法效率低下(已修复)
|
|||
|
|
|
|||
|
|
**位置**: `services/image_service.go:245-313`
|
|||
|
|
|
|||
|
|
**原问题**:
|
|||
|
|
- PNG压缩级别映射错误(quality > 80才用BestCompression,逻辑反了)
|
|||
|
|
- JPEG直接使用imaging库重编码,未优化参数
|
|||
|
|
- 缺少智能降采样策略
|
|||
|
|
- **实际效果**: 压缩后文件可能更大
|
|||
|
|
|
|||
|
|
**修复方案**(已完成):
|
|||
|
|
```go
|
|||
|
|
// 1. 智能降采样:超大图片自动缩小到4000px以内
|
|||
|
|
if maxWidth == 0 && maxHeight == 0 {
|
|||
|
|
maxDim := 4000
|
|||
|
|
if width > maxDim || height > maxDim {
|
|||
|
|
// 自动计算缩放比例
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 2. 修正PNG压缩级别映射
|
|||
|
|
if quality >= 90 {
|
|||
|
|
level = png.BestCompression // 高质量→最大压缩
|
|||
|
|
} else if quality >= 70 {
|
|||
|
|
level = png.DefaultCompression
|
|||
|
|
} else {
|
|||
|
|
level = png.BestSpeed // 低质量→快速压缩
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 3. 使用标准jpeg.Encode而非imaging.Save
|
|||
|
|
opts := &jpeg.Options{Quality: quality}
|
|||
|
|
return jpeg.Encode(f, img, opts)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**前端增强**(已完成):
|
|||
|
|
- 添加压缩率计算和显示
|
|||
|
|
- 文件变大时给出警告提示
|
|||
|
|
- 动画效果展示压缩结果
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
#### 问题2: PDF功能依赖MuPDF且fallback不完善(已修复)
|
|||
|
|
|
|||
|
|
**位置**: `services/pdf_fitz.go` 和 `services/pdf_nofitz.go`
|
|||
|
|
|
|||
|
|
**原问题**:
|
|||
|
|
- `pdf_fitz.go` 依赖系统级MuPDF库(MuPDFLib.dll)
|
|||
|
|
- `pdf_nofitz.go` 是纯Go fallback但功能残缺:
|
|||
|
|
- 文本提取使用原始content stream解析,准确率低
|
|||
|
|
- PDF转图片生成空白灰色图片(无效)
|
|||
|
|
- 编译时默认启用fitz标签,运行时缺少DLL会崩溃
|
|||
|
|
|
|||
|
|
**修复方案**(已完成):
|
|||
|
|
|
|||
|
|
**1. 改进DLL部署机制** (`main.go`)
|
|||
|
|
```go
|
|||
|
|
func init() {
|
|||
|
|
// 检查DLL是否存在
|
|||
|
|
for _, name := range names {
|
|||
|
|
if _, err := os.Stat(p); err == nil {
|
|||
|
|
return // DLL已存在
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 尝试释放嵌入的DLL
|
|||
|
|
for _, name := range names {
|
|||
|
|
if err := os.WriteFile(p, mupdfDLL, 0644); err != nil {
|
|||
|
|
log.Printf("Failed to extract MuPDF DLL: %v", err)
|
|||
|
|
} else {
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 失败则设置环境变量标记使用nofitz
|
|||
|
|
os.Setenv("XK_NO_FITZ", "1")
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**2. 运行时检测和降级** (`services/pdf_service.go`)
|
|||
|
|
```go
|
|||
|
|
func (s *PDFService) ExtractText(inputPath string) (string, error) {
|
|||
|
|
// 检查是否应使用nofitz模式
|
|||
|
|
if os.Getenv("XK_NO_FITZ") == "1" {
|
|||
|
|
return extractTextNoFitz(inputPath)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 尝试fitz,失败则降级
|
|||
|
|
text, err := extractTextWithFitz(inputPath)
|
|||
|
|
if err != nil {
|
|||
|
|
if contains(err.Error(), []string{"MuPDF", "DLL", "not found"}) {
|
|||
|
|
os.Setenv("XK_NO_FITZ", "1")
|
|||
|
|
return extractTextNoFitz(inputPath)
|
|||
|
|
}
|
|||
|
|
return "", err
|
|||
|
|
}
|
|||
|
|
return text, nil
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**3. nofitz模式友好提示**
|
|||
|
|
- 文本提取: 返回页数并提示功能受限
|
|||
|
|
- PDF转图片: 明确提示需要MuPDF库支持
|
|||
|
|
|
|||
|
|
**当前状态**:
|
|||
|
|
- ✅ 压缩、合并、分割、旋转、水印:正常使用pdfcpu
|
|||
|
|
- ⚠️ 文本提取:fitz模式准确,nofitz模式仅返回页数
|
|||
|
|
- ⚠️ PDF转图片:fitz模式正常,nofitz模式给出清晰错误提示
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
#### 问题3: ToolView.vue职责过重(部分优化)
|
|||
|
|
|
|||
|
|
**位置**: `frontend/src/components/ToolView.vue` (940行)
|
|||
|
|
|
|||
|
|
**问题**:
|
|||
|
|
- 虽然已拆分子组件,但ToolView仍包含大量通用逻辑
|
|||
|
|
- 重复代码: `processFile` 和 `handleImageProcess` 逻辑几乎相同
|
|||
|
|
- 硬编码的分类配置应抽离到配置文件
|
|||
|
|
|
|||
|
|
**建议优化**(未实施):
|
|||
|
|
```javascript
|
|||
|
|
// 提取为composable
|
|||
|
|
export function useFileProcessor() {
|
|||
|
|
async function processFile(req) {
|
|||
|
|
// 统一的处理逻辑
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
async function handleImageProcess(req) {
|
|||
|
|
// 调用processFile,避免重复
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 配置抽离到单独文件
|
|||
|
|
// config/toolCategories.js
|
|||
|
|
export const categoryConfig = {
|
|||
|
|
pdf: { /* ... */ },
|
|||
|
|
image: { /* ... */ }
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**现状**: 由于优先级考虑,此问题暂未重构,但不影响功能使用。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
#### 问题4: 缺少自动处理机制(未实施)
|
|||
|
|
|
|||
|
|
**问题**: AGENTS.md提到"Image tools auto-process on parameter change (500ms debounce)",但代码中未实现
|
|||
|
|
|
|||
|
|
**影响**: 用户每次调整参数需手动点击"开始处理",体验差
|
|||
|
|
|
|||
|
|
**建议实现**(未实施):
|
|||
|
|
```vue
|
|||
|
|
<script setup>
|
|||
|
|
import { watch } from 'vue'
|
|||
|
|
import { debounce } from 'lodash-es'
|
|||
|
|
|
|||
|
|
const autoProcess = ref(true) // 添加开关
|
|||
|
|
|
|||
|
|
const debouncedProcess = debounce((params) => {
|
|||
|
|
if (autoProcess.value && filePath.value) {
|
|||
|
|
emit('process', params)
|
|||
|
|
}
|
|||
|
|
}, 500)
|
|||
|
|
|
|||
|
|
watch([qualityInt, customWidth, customHeight], () => {
|
|||
|
|
debouncedProcess(buildRequest())
|
|||
|
|
})
|
|||
|
|
</script>
|
|||
|
|
|
|||
|
|
<template>
|
|||
|
|
<el-switch v-model="autoProcess" active-text="自动处理" />
|
|||
|
|
</template>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
#### 问题5: 临时文件管理混乱(未实施)
|
|||
|
|
|
|||
|
|
**位置**: `handlers.go:329-333` getTempPath
|
|||
|
|
|
|||
|
|
**问题**:
|
|||
|
|
- 临时文件存储在系统temp目录,前缀`xk_`但从未清理
|
|||
|
|
- 长时间使用会积累大量垃圾文件
|
|||
|
|
|
|||
|
|
**建议修复**(未实施):
|
|||
|
|
```go
|
|||
|
|
// 应用启动时清理旧临时文件
|
|||
|
|
func cleanupTempFiles() {
|
|||
|
|
tempDir := os.TempDir()
|
|||
|
|
entries, _ := os.ReadDir(tempDir)
|
|||
|
|
cutoff := time.Now().Add(-24 * time.Hour)
|
|||
|
|
|
|||
|
|
for _, entry := range entries {
|
|||
|
|
if strings.HasPrefix(entry.Name(), "xk_") {
|
|||
|
|
info, _ := entry.Info()
|
|||
|
|
if info.ModTime().Before(cutoff) {
|
|||
|
|
os.Remove(filepath.Join(tempDir, entry.Name()))
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 在FileHandler.startup中调用
|
|||
|
|
func (h *FileHandler) startup(ctx context.Context) {
|
|||
|
|
h.ctx = ctx
|
|||
|
|
cleanupTempFiles() // 清理超过24小时的临时文件
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
#### 问题6: 错误处理不完善(部分修复)
|
|||
|
|
|
|||
|
|
**问题**:
|
|||
|
|
- 多处使用空catch块吞掉错误(如ToolView.vue第151行、207行、330行)
|
|||
|
|
- 缺少用户友好的错误提示
|
|||
|
|
|
|||
|
|
**已修复**:
|
|||
|
|
- PDF服务增加了MuPDF缺失时的优雅降级和清晰提示
|
|||
|
|
- 图片压缩增加了文件变大的警告
|
|||
|
|
|
|||
|
|
**待修复**:
|
|||
|
|
```vue
|
|||
|
|
<!-- 替换空catch块 -->
|
|||
|
|
try {
|
|||
|
|
config.value = await window.go.main.FileHandler.GetConfig()
|
|||
|
|
} catch (e) {
|
|||
|
|
console.warn('加载配置失败,使用默认配置', e)
|
|||
|
|
// 不阻断应用运行
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 三、用户体验问题
|
|||
|
|
|
|||
|
|
### 3.1 体验较差的方面
|
|||
|
|
|
|||
|
|
**体验问题1: 无实时预览**
|
|||
|
|
- 图片工具调整参数后无法即时看到效果
|
|||
|
|
- 必须点击"开始处理"按钮才能看到结果
|
|||
|
|
|
|||
|
|
**体验问题2: 文件大小对比不够直观**
|
|||
|
|
- 仅显示"原大小→新大小 (减少X%)"
|
|||
|
|
- 缺少可视化图表(如柱状图、环形进度条)
|
|||
|
|
|
|||
|
|
**体验问题3: 批量处理能力缺失**
|
|||
|
|
- 所有工具仅支持单文件处理
|
|||
|
|
- PDF合并虽支持多文件,但UI交互复杂
|
|||
|
|
|
|||
|
|
**体验问题4: 缺少进度反馈**
|
|||
|
|
- 大文件处理时仅有loading spinner
|
|||
|
|
- 无进度百分比,无法取消操作
|
|||
|
|
|
|||
|
|
**体验问题5: 输出路径选择繁琐**
|
|||
|
|
- 每次处理需手动选择保存路径或接受默认
|
|||
|
|
- 无"上次使用的目录"记忆功能
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 3.2 UI设计评估
|
|||
|
|
|
|||
|
|
**优点**:
|
|||
|
|
- ✅ 暗色主题一致性好
|
|||
|
|
- ✅ Glassmorphism效果现代
|
|||
|
|
- ✅ CSS变量系统化(--bg-primary, --accent-primary等)
|
|||
|
|
- ✅ Element Plus组件使用得当
|
|||
|
|
|
|||
|
|
**待优化点**:
|
|||
|
|
1. **视觉层次**: 工具面板与画布区域对比度不足
|
|||
|
|
2. **交互反馈**: 缺少微动画和过渡效果
|
|||
|
|
3. **信息密度**: 参数配置区域过于紧凑
|
|||
|
|
4. **一致性**: 不同工具的UI布局略有差异
|
|||
|
|
|
|||
|
|
**建议优化方向**(基于ui-ux-pro-max规范):
|
|||
|
|
- 画布区域背景加深至 `#12121a`
|
|||
|
|
- 激活状态的tab增加底部指示条
|
|||
|
|
- 按钮hover增加scale变换 `transform: scale(1.02)`
|
|||
|
|
- 压缩结果使用环形进度条展示压缩率
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 四、优化总结
|
|||
|
|
|
|||
|
|
### 4.1 已完成的优化 ✅
|
|||
|
|
|
|||
|
|
1. **图片压缩算法优化**
|
|||
|
|
- ✅ 智能降采样(超大图片自动缩小)
|
|||
|
|
- ✅ 修正PNG压缩级别映射
|
|||
|
|
- ✅ 使用优化的JPEG/PNG编码器
|
|||
|
|
- ✅ 前端显示压缩率和警告提示
|
|||
|
|
|
|||
|
|
2. **PDF功能fallback机制**
|
|||
|
|
- ✅ 改进MuPDF DLL部署和错误处理
|
|||
|
|
- ✅ 运行时自动检测并降级到nofitz模式
|
|||
|
|
- ✅ nofitz模式给出清晰的友好提示
|
|||
|
|
- ✅ PDF基础功能(压缩/合并/分割等)继续可用
|
|||
|
|
|
|||
|
|
3. **代码质量提升**
|
|||
|
|
- ✅ 移除冗余代码(pdf_nofitz.go从191行精简至28行)
|
|||
|
|
- ✅ 增加错误日志记录
|
|||
|
|
- ✅ 改善用户体验(明确的错误提示)
|
|||
|
|
|
|||
|
|
### 4.2 待实施的优化 📋
|
|||
|
|
|
|||
|
|
**高优先级**:
|
|||
|
|
- [ ] 实现图片工具自动处理机制(500ms防抖)
|
|||
|
|
- [ ] 临时文件自动清理
|
|||
|
|
- [ ] 完善错误处理(替换空catch块)
|
|||
|
|
|
|||
|
|
**中优先级**:
|
|||
|
|
- [ ] 批量处理支持
|
|||
|
|
- [ ] 处理进度显示
|
|||
|
|
- [ ] 输出目录记忆功能
|
|||
|
|
|
|||
|
|
**低优先级**:
|
|||
|
|
- [ ] UI细节优化(基于ui-ux-pro-max)
|
|||
|
|
- [ ] ToolView.vue重构(提取重复逻辑)
|
|||
|
|
- [ ] 实时预览增强
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 五、技术债务
|
|||
|
|
|
|||
|
|
1. **MuPDF依赖**: 完整版需要分发MuPDFLib.dll,需确认许可合规性
|
|||
|
|
2. **Word转PDF**: 依赖系统安装的Office/LibreOffice,非Windows平台不可用
|
|||
|
|
3. **PDF文本提取**: nofitz模式下功能受限,准确率不如fitz模式
|
|||
|
|
4. **前端状态管理**: 大型应用应考虑Pinia/Vuex而非纯props传递
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 六、推荐后续行动
|
|||
|
|
|
|||
|
|
### Phase 1: 稳定性加固(1-2天)
|
|||
|
|
- 实现临时文件清理
|
|||
|
|
- 完善错误边界处理
|
|||
|
|
- 添加单元测试覆盖核心服务
|
|||
|
|
|
|||
|
|
### Phase 2: 体验提升(3-5天)
|
|||
|
|
- 实现自动处理机制
|
|||
|
|
- 添加批量处理支持
|
|||
|
|
- 优化UI交互动画
|
|||
|
|
|
|||
|
|
### Phase 3: 功能扩展(按需)
|
|||
|
|
- 集成更多图片格式(WebP、AVIF)
|
|||
|
|
- PDF OCR支持
|
|||
|
|
- 云端存储集成
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
**文档版本**: v1.0
|
|||
|
|
**最后更新**: 2026-06-23
|
|||
|
|
**维护者**: XK开发团队
|