build(deps): 添加 compressorjs 和 cropperjs 依赖并更新文档
添加 compressorjs 用于图片压缩功能,调整 cropperjs 依赖位置 新增 compressorjs 使用指南文档和项目开发说明文档
This commit is contained in:
parent
864ef9a1fa
commit
8819f17aa0
|
|
@ -0,0 +1,252 @@
|
||||||
|
# CLAUDE.md
|
||||||
|
|
||||||
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||||
|
|
||||||
|
## Development Commands
|
||||||
|
|
||||||
|
### Environment Requirements
|
||||||
|
- **Node.js**: 16.0+ (recommended: Node.js 16 + pnpm 7.30.5)
|
||||||
|
- **pnpm**: 6.0+
|
||||||
|
|
||||||
|
### Common Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Install dependencies
|
||||||
|
pnpm install
|
||||||
|
|
||||||
|
# Start development server
|
||||||
|
pnpm dev
|
||||||
|
|
||||||
|
# Build for production
|
||||||
|
pnpm build
|
||||||
|
|
||||||
|
# Build for staging
|
||||||
|
pnpm build:staging
|
||||||
|
|
||||||
|
# Preview production build
|
||||||
|
pnpm preview
|
||||||
|
|
||||||
|
# Run type checking
|
||||||
|
pnpm typecheck
|
||||||
|
|
||||||
|
# Run all linters
|
||||||
|
pnpm lint
|
||||||
|
|
||||||
|
# Run individual linters
|
||||||
|
pnpm lint:eslint # ESLint with auto-fix
|
||||||
|
pnpm lint:prettier # Prettier formatting
|
||||||
|
pnpm lint:stylelint # Stylelint with auto-fix
|
||||||
|
|
||||||
|
# Clean install (removes node_modules and reinstalls)
|
||||||
|
pnpm clean:cache
|
||||||
|
|
||||||
|
# Generate SVG icons
|
||||||
|
pnpm svgo
|
||||||
|
```
|
||||||
|
|
||||||
|
### API Proxy Configuration
|
||||||
|
The dev server is configured with a proxy to backend API at `http://localhost:8080`:
|
||||||
|
- API calls starting with `/dev-api/` are proxied to the backend
|
||||||
|
- See `vite.config.ts:46-52` for proxy configuration
|
||||||
|
|
||||||
|
## Project Architecture
|
||||||
|
|
||||||
|
### Technology Stack
|
||||||
|
- **Frontend Framework**: Vue 3.3.4 with Composition API
|
||||||
|
- **Language**: TypeScript 5.0.4
|
||||||
|
- **UI Library**: Element Plus 2.3.6
|
||||||
|
- **Build Tool**: Vite 4.3.9
|
||||||
|
- **State Management**: Pinia 2.1.4
|
||||||
|
- **Router**: Vue Router 4.2.2
|
||||||
|
|
||||||
|
### High-Level Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
src/
|
||||||
|
├── api/ # API layer - organized by business module
|
||||||
|
│ ├── ab98/ # Member management APIs
|
||||||
|
│ ├── cabinet/ # Smart cabinet management APIs
|
||||||
|
│ ├── common/ # Shared/common APIs
|
||||||
|
│ ├── qy/ # Enterprise user APIs
|
||||||
|
│ ├── shop/ # Shop management APIs
|
||||||
|
│ └── system/ # System administration APIs
|
||||||
|
├── components/ # Reusable Vue components
|
||||||
|
├── layout/ # App layout components
|
||||||
|
├── router/ # Vue Router configuration
|
||||||
|
│ └── modules/ # Route modules (global, home, error, etc.)
|
||||||
|
├── store/ # Pinia state management
|
||||||
|
│ └── modules/ # Store modules
|
||||||
|
├── utils/ # Utility functions
|
||||||
|
│ └── request.ts # Axios HTTP client with interceptors
|
||||||
|
├── views/ # Page components organized by feature
|
||||||
|
│ ├── cabinet/ # Smart cabinet management pages
|
||||||
|
│ ├── shop/ # Shop management pages
|
||||||
|
│ ├── qy/ # Enterprise management pages
|
||||||
|
│ ├── system/ # System administration pages
|
||||||
|
│ └── user/ # User management pages
|
||||||
|
├── directives/ # Custom Vue directives
|
||||||
|
├── plugins/ # Vue plugins configuration
|
||||||
|
└── style/ # Global styles
|
||||||
|
```
|
||||||
|
|
||||||
|
### Key Configuration Files
|
||||||
|
- `vite.config.ts`: Vite build configuration with path aliases (@ -> src, @build -> build)
|
||||||
|
- `tsconfig.json`: TypeScript configuration
|
||||||
|
- `tailwind.config.js`: Tailwind CSS configuration
|
||||||
|
- `.eslintrc.js`: ESLint rules
|
||||||
|
- `.stylelintrc.js`: Stylelint rules
|
||||||
|
|
||||||
|
## Core Business Modules
|
||||||
|
|
||||||
|
### 1. Smart Cabinet Management (cabinet)
|
||||||
|
- **柜体管理**: Smart cabinet device management
|
||||||
|
- **格口管理**: Cabinet cell/compartment management
|
||||||
|
- **设备操作**: Remote device control
|
||||||
|
- **MQTT 服务器**: MQTT server management for device communication
|
||||||
|
|
||||||
|
Key files:
|
||||||
|
- `src/api/cabinet/smart-cabinet.ts`
|
||||||
|
- `src/api/cabinet/cabinet-cell.ts`
|
||||||
|
- `src/api/cabinet/mqttServer.ts`
|
||||||
|
|
||||||
|
### 2. Shop Management (shop)
|
||||||
|
- **商品管理**: Product management and inventory
|
||||||
|
- **分类管理**: Product categories
|
||||||
|
- **订单管理**: Order processing
|
||||||
|
- **审批中心**: Business approval workflows
|
||||||
|
- **数据统计**: Analytics dashboard
|
||||||
|
|
||||||
|
Key files:
|
||||||
|
- `src/api/shop/shop.ts`
|
||||||
|
- `src/api/shop/goods.ts`
|
||||||
|
- `src/api/shop/order.ts`
|
||||||
|
- `src/api/shop/stats.ts`
|
||||||
|
|
||||||
|
### 3. Enterprise Management (qy)
|
||||||
|
- **企业用户管理**: Enterprise user management
|
||||||
|
- **余额管理**: User balance and transaction records
|
||||||
|
|
||||||
|
Key files:
|
||||||
|
- `src/api/qy/qyUser.ts`
|
||||||
|
|
||||||
|
### 4. System Administration (system)
|
||||||
|
- **用户管理**: System user management
|
||||||
|
- **权限管理**: Role and permission configuration
|
||||||
|
- **个人中心**: User profile management
|
||||||
|
|
||||||
|
Key files:
|
||||||
|
- `src/api/system/`
|
||||||
|
|
||||||
|
### 5. Member Management (ab98)
|
||||||
|
- **会员信息**: Member profile management
|
||||||
|
- **会员详情**: Detailed member information
|
||||||
|
|
||||||
|
Key files:
|
||||||
|
- `src/api/ab98/`
|
||||||
|
|
||||||
|
## Architecture Patterns
|
||||||
|
|
||||||
|
### Request Handling
|
||||||
|
- Centralized HTTP client: `src/utils/request.ts`
|
||||||
|
- Request interceptor adds authentication token
|
||||||
|
- Response interceptor handles errors globally
|
||||||
|
- API methods return typed responses
|
||||||
|
|
||||||
|
### State Management
|
||||||
|
- Pinia stores organized by feature in `src/store/modules/`
|
||||||
|
- Includes permission, button权限, system config, and WeChat integration
|
||||||
|
- Stores can be persisted to localStorage
|
||||||
|
|
||||||
|
### Routing
|
||||||
|
- Dynamic routing based on user permissions
|
||||||
|
- Static routes in `src/router/modules/`
|
||||||
|
- Route guards handle authentication and authorization
|
||||||
|
- Lazy-loaded route components for code splitting
|
||||||
|
|
||||||
|
### Component Development
|
||||||
|
- Composition API with `<script setup>` syntax
|
||||||
|
- TypeScript interfaces for props and emits
|
||||||
|
- Reusable components in `src/components/`
|
||||||
|
- Custom components follow naming conventions (PascalCase)
|
||||||
|
|
||||||
|
## Development Best Practices
|
||||||
|
|
||||||
|
### Code Style
|
||||||
|
- **Components**: PascalCase (e.g., `UserProfile.vue`)
|
||||||
|
- **Files**: kebab-case (e.g., `user-profile.ts`)
|
||||||
|
- **Variables**: camelCase (e.g., `userName`)
|
||||||
|
- **Constants**: UPPER_SNAKE_CASE (e.g., `MAX_COUNT`)
|
||||||
|
|
||||||
|
### TypeScript Guidelines
|
||||||
|
- Strict mode is disabled in tsconfig.json for flexibility
|
||||||
|
- Define interfaces for all API responses
|
||||||
|
- Use TypeScript generics for typed API calls
|
||||||
|
- Use `withDefaults` for prop definitions
|
||||||
|
|
||||||
|
### Git Workflow
|
||||||
|
- Husky pre-commit hooks for code quality
|
||||||
|
- Commit messages follow Conventional Commits format:
|
||||||
|
```
|
||||||
|
<type>(<scope>): <subject>
|
||||||
|
```
|
||||||
|
Types: `feat`, `fix`, `docs`, `style`, `refactor`, `test`, `chore`
|
||||||
|
|
||||||
|
## Environment Configuration
|
||||||
|
|
||||||
|
### Environment Files
|
||||||
|
- `.env.development`: Development environment variables
|
||||||
|
- `.env.staging`: Staging environment variables
|
||||||
|
- `.env.production`: Production environment variables
|
||||||
|
|
||||||
|
### Key Environment Variables
|
||||||
|
- `VITE_ROUTER_HISTORY`: Router history mode
|
||||||
|
- `VITE_PORT`: Dev server port
|
||||||
|
- `VITE_PUBLIC_PATH`: Base path for production builds
|
||||||
|
- `VITE_API_BASE_URL`: Backend API base URL (in request.ts)
|
||||||
|
|
||||||
|
## Build & Deployment
|
||||||
|
|
||||||
|
### Build Process
|
||||||
|
- Vite for bundling and optimization
|
||||||
|
- Static assets organized by type (js/css/images)
|
||||||
|
- Source maps disabled in production
|
||||||
|
- Code splitting and chunk optimization
|
||||||
|
|
||||||
|
### Deployment
|
||||||
|
- Output directory: `dist/`
|
||||||
|
- Configure server for SPA routing
|
||||||
|
- Production builds include `serverConfig.json` for server addresses
|
||||||
|
- See `doc/部署和维护指南.md` for detailed deployment instructions
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
Based on package.json, the project appears to have testing infrastructure in place but specific test commands are not defined. The codebase follows Vue 3 + Vite patterns compatible with:
|
||||||
|
- Vitest for unit testing
|
||||||
|
- Vue Test Utils for component testing
|
||||||
|
|
||||||
|
## Code Quality Tools
|
||||||
|
|
||||||
|
### Linting Stack
|
||||||
|
- **ESLint**: Code quality with @typescript-eslint
|
||||||
|
- **Prettier**: Code formatting
|
||||||
|
- **Stylelint**: CSS/SCSS linting with stylelint-config-standard
|
||||||
|
- All three are enforced via Husky pre-commit hooks
|
||||||
|
|
||||||
|
### Performance Optimization
|
||||||
|
- Lazy loading for routes and heavy components
|
||||||
|
- Asset optimization via Vite plugins
|
||||||
|
- CDN support for third-party libraries
|
||||||
|
- Tree-shaking for dead code elimination
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
See the `doc/` directory for detailed documentation:
|
||||||
|
- `项目说明文档.md`: Project overview and architecture
|
||||||
|
- `开发指南.md`: Development guide and best practices
|
||||||
|
- `API接口文档.md`: Complete API documentation
|
||||||
|
- `部署和维护指南.md`: Deployment and maintenance guide
|
||||||
|
|
||||||
|
## Key References
|
||||||
|
- This project is based on [Pure-Admin](https://github.com/pure-admin/vue-pure-admin)
|
||||||
|
- Vue 3 Documentation: https://v3.cn.vuejs.org
|
||||||
|
- Vite Documentation: https://cn.vitejs.dev
|
||||||
|
- Element Plus Documentation: https://element-plus.org/zh-CN
|
||||||
|
- Pinia Documentation: https://pinia.vuejs.org
|
||||||
|
|
@ -0,0 +1,318 @@
|
||||||
|
# CompressorJS 实战使用文档
|
||||||
|
|
||||||
|
基于项目中的 `src/pages/approval/submit.vue` 实例编写。
|
||||||
|
|
||||||
|
## 1. 简介
|
||||||
|
|
||||||
|
CompressorJS 是一个轻量级的 JavaScript 图像压缩库,基于 Canvas API,依赖少且易用。适用于文件上传前压缩,可显著减少文件大小和上传时间。
|
||||||
|
|
||||||
|
## 2. 安装
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pnpm add compressorjs
|
||||||
|
# 或
|
||||||
|
npm install compressorjs
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. 基础使用(基于项目实例)
|
||||||
|
|
||||||
|
### 3.1 基本语法
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import Compressor from 'compressorjs'
|
||||||
|
|
||||||
|
new Compressor(file, {
|
||||||
|
quality: 0.8,
|
||||||
|
maxWidth: 1280,
|
||||||
|
maxHeight: 1280,
|
||||||
|
success(result) {
|
||||||
|
// 压缩成功后的处理
|
||||||
|
},
|
||||||
|
error(err) {
|
||||||
|
// 压缩失败处理
|
||||||
|
}
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.2 实际项目代码解析
|
||||||
|
|
||||||
|
在 `submit.vue:54-115`,`handleFileUpload` 函数中:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const handleFileUpload = async (items: UploaderFileListItem | UploaderFileListItem[]) => {
|
||||||
|
const files = Array.isArray(items) ? items : [items]
|
||||||
|
|
||||||
|
const uploadPromises = files.map(async (item) => {
|
||||||
|
const file = item.file as File
|
||||||
|
|
||||||
|
// 压缩文件
|
||||||
|
let compressedFile = file
|
||||||
|
try {
|
||||||
|
compressedFile = await new Promise<File>((resolve, reject) => {
|
||||||
|
new Compressor(file, {
|
||||||
|
quality: 0.8, // 压缩质量 0-1 之间
|
||||||
|
maxWidth: 1280, // 最大宽度
|
||||||
|
maxHeight: 1280, // 最大高度
|
||||||
|
success(result) {
|
||||||
|
// 转换为 File 对象,保持原始文件名
|
||||||
|
resolve(new File([result], file.name, {
|
||||||
|
type: 'image/jpeg', // 统一输出为 jpeg
|
||||||
|
lastModified: Date.now()
|
||||||
|
}))
|
||||||
|
},
|
||||||
|
error(err) {
|
||||||
|
reject(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
console.error('压缩失败:', error)
|
||||||
|
// 压缩失败时使用原文件
|
||||||
|
}
|
||||||
|
|
||||||
|
// 继续上传...
|
||||||
|
})
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**关键点:**
|
||||||
|
- 使用 Promise 包装 Compressor 的回调式 API
|
||||||
|
- 压缩失败时降级使用原文件
|
||||||
|
- 转换结果为标准 File 对象,便于后续处理
|
||||||
|
|
||||||
|
## 4. 配置参数详解
|
||||||
|
|
||||||
|
| 参数 | 类型 | 默认值 | 说明 |
|
||||||
|
|------|------|--------|------|
|
||||||
|
| `quality` | number | 0.8 | 压缩质量,0-1 之间,值越小文件越小但质量越差 |
|
||||||
|
| `maxWidth` | number | Infinity | 最大宽度(像素) |
|
||||||
|
| `maxHeight` | number | Infinity | 最大高度(像素) |
|
||||||
|
| `minWidth` | number | 0 | 最小宽度 |
|
||||||
|
| `minHeight` | number | 0 | 最小高度 |
|
||||||
|
| `width` | number | - | 固定宽度(优先级高于 maxWidth) |
|
||||||
|
| `height` | number | - | 固定高度(优先级高于 maxHeight) |
|
||||||
|
| `resize` | string | 'cover' | 调整大小模式:'none'\|'contain'\|'cover'\|'crop' |
|
||||||
|
| `crop` | boolean | false | 是否裁剪(需配合 width/height) |
|
||||||
|
| `rotate` | number | 0 | 旋转角度(度) |
|
||||||
|
| `blur` | number | 0 | 模糊半径 |
|
||||||
|
| `grayscale` | boolean | false | 转为灰度图 |
|
||||||
|
| `input` | string | 'file' | 输入类型 |
|
||||||
|
| `output` | string | 'blob' | 输出类型:'blob'\|'base64'\|'datauristring' |
|
||||||
|
|
||||||
|
## 5. 常见使用场景
|
||||||
|
|
||||||
|
### 5.1 批量图片压缩
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const compressFiles = async (files) => {
|
||||||
|
const promises = files.map(file => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
new Compressor(file, {
|
||||||
|
quality: 0.8,
|
||||||
|
maxWidth: 1280,
|
||||||
|
maxHeight: 1280,
|
||||||
|
success: resolve,
|
||||||
|
error: reject
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
return await Promise.all(promises)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5.2 限制文件大小
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const compressWithSizeLimit = (file, maxSizeMB = 2) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const maxSizeBytes = maxSizeMB * 1024 * 1024
|
||||||
|
|
||||||
|
new Compressor(file, {
|
||||||
|
quality: 0.6, // 降低质量确保文件更小
|
||||||
|
maxWidth: 1024,
|
||||||
|
maxHeight: 1024,
|
||||||
|
success: (result) => {
|
||||||
|
if (result.size > maxSizeBytes) {
|
||||||
|
// 仍超出限制,进一步压缩
|
||||||
|
new Compressor(file, {
|
||||||
|
quality: 0.4,
|
||||||
|
maxWidth: 800,
|
||||||
|
maxHeight: 800,
|
||||||
|
success: resolve,
|
||||||
|
error: reject
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
resolve(result)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: reject
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5.3 自定义输出格式
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 输出为 base64
|
||||||
|
new Compressor(file, {
|
||||||
|
quality: 0.8,
|
||||||
|
maxWidth: 1280,
|
||||||
|
maxHeight: 1280,
|
||||||
|
output: 'datauristring',
|
||||||
|
success: (result) => {
|
||||||
|
const base64String = result // 已经是 base64 字符串
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 转换为 PNG
|
||||||
|
new Compressor(file, {
|
||||||
|
quality: 0.9,
|
||||||
|
maxWidth: 1280,
|
||||||
|
maxHeight: 1280,
|
||||||
|
success: (result) => {
|
||||||
|
new File([result], 'image.png', { type: 'image/png' })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
## 6. 最佳实践
|
||||||
|
|
||||||
|
### 6.1 错误处理
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
let compressedFile = originalFile
|
||||||
|
try {
|
||||||
|
compressedFile = await new Promise((resolve, reject) => {
|
||||||
|
new Compressor(file, options)
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
console.error('压缩失败:', error)
|
||||||
|
// 压缩失败时使用原文件,避免阻塞上传流程
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6.2 文件类型检查
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const isImage = (file) => {
|
||||||
|
return /^image\//.test(file.type)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isImage(file)) {
|
||||||
|
throw new Error('仅支持图片文件')
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6.3 压缩级别建议
|
||||||
|
|
||||||
|
- **高质量**(适合产品图、头像):
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
quality: 0.9,
|
||||||
|
maxWidth: 1920,
|
||||||
|
maxHeight: 1920
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- **中等质量**(适合一般场景):
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
quality: 0.8,
|
||||||
|
maxWidth: 1280,
|
||||||
|
maxHeight: 1280
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- **高质量压缩**(适合缩略图、证明材料):
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
quality: 0.6,
|
||||||
|
maxWidth: 800,
|
||||||
|
maxHeight: 800
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6.4 进度提示(适用于 Vue/Vant)
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
item.status = 'uploading'
|
||||||
|
item.message = '压缩中...'
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 压缩
|
||||||
|
item.message = '上传中...'
|
||||||
|
|
||||||
|
// 上传
|
||||||
|
item.status = 'done'
|
||||||
|
item.message = '上传成功'
|
||||||
|
} catch (error) {
|
||||||
|
item.status = 'failed'
|
||||||
|
item.message = '上传失败'
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 7. 性能优化
|
||||||
|
|
||||||
|
1. **避免重复压缩**:上传前检查文件是否已压缩
|
||||||
|
2. **合理设置尺寸**:根据业务需求设置最大宽高
|
||||||
|
3. **并发控制**:避免同时压缩过多文件
|
||||||
|
4. **使用 Web Workers**:大量文件时考虑使用 Web Worker
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 并发控制示例
|
||||||
|
const processFilesWithLimit = async (files, limit = 3) => {
|
||||||
|
const results = []
|
||||||
|
const executing = []
|
||||||
|
|
||||||
|
for (const file of files) {
|
||||||
|
const promise = Promise.resolve().then(() => compressFile(file))
|
||||||
|
results.push(promise)
|
||||||
|
|
||||||
|
if (limit <= files.length) {
|
||||||
|
const executing_promise = promise.then(() =>
|
||||||
|
executing.splice(executing.indexOf(executing_promise), 1)
|
||||||
|
)
|
||||||
|
executing.push(executing_promise)
|
||||||
|
|
||||||
|
if (executing.length >= limit) {
|
||||||
|
await Promise.race(executing)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.all(results)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 8. 注意事项
|
||||||
|
|
||||||
|
1. **只支持图片格式**:CompressorJS 仅处理图片文件(jpeg, png, gif 等)
|
||||||
|
2. **Canvas 依赖**:依赖浏览器 Canvas API,部分旧浏览器可能不支持
|
||||||
|
3. **内存使用**:大文件压缩会消耗较多内存,建议控制文件大小
|
||||||
|
4. **EXIF 方向**:压缩可能会丢失图片 EXIF 方向信息
|
||||||
|
5. **文件类型转换**:默认输出 blob,转换为 File 时需显式指定类型
|
||||||
|
|
||||||
|
## 9. 完整示例
|
||||||
|
|
||||||
|
参考项目中的完整实现:
|
||||||
|
- 文件:`src/pages/approval/submit.vue:54-115`
|
||||||
|
- 结合 Vant Uploader 组件的批量图片上传和压缩
|
||||||
|
- 集成错误处理和状态管理
|
||||||
|
- 支持压缩失败时的降级策略
|
||||||
|
|
||||||
|
## 10. 常见问题
|
||||||
|
|
||||||
|
**Q: 压缩后文件变大?**
|
||||||
|
A: 原文件已非常小,或开启了失真优化。尝试降低 quality 或设置更小的 maxWidth/maxHeight。
|
||||||
|
|
||||||
|
**Q: 支持 GIF 动态图?**
|
||||||
|
A: 不支持,CompressorJS 仅处理静态图像。
|
||||||
|
|
||||||
|
**Q: 如何保持文件类型?**
|
||||||
|
A: 压缩时输出为 blob,然后在 File 构造函数中指定目标类型:
|
||||||
|
```javascript
|
||||||
|
const type = file.type.includes('png') ? 'image/png' : 'image/jpeg'
|
||||||
|
new File([result], file.name, { type })
|
||||||
|
```
|
||||||
|
|
@ -36,6 +36,8 @@
|
||||||
"@vueuse/motion": "^2.0.0",
|
"@vueuse/motion": "^2.0.0",
|
||||||
"animate.css": "^4.1.1",
|
"animate.css": "^4.1.1",
|
||||||
"axios": "^1.4.0",
|
"axios": "^1.4.0",
|
||||||
|
"compressorjs": "^1.2.1",
|
||||||
|
"cropperjs": "^1.5.13",
|
||||||
"crypto-js": "^4.1.1",
|
"crypto-js": "^4.1.1",
|
||||||
"dayjs": "^1.11.8",
|
"dayjs": "^1.11.8",
|
||||||
"echarts": "^5.4.2",
|
"echarts": "^5.4.2",
|
||||||
|
|
@ -48,8 +50,6 @@
|
||||||
"path": "^0.12.7",
|
"path": "^0.12.7",
|
||||||
"pinia": "^2.1.4",
|
"pinia": "^2.1.4",
|
||||||
"pinyin-pro": "^3.15.2",
|
"pinyin-pro": "^3.15.2",
|
||||||
"cropperjs": "^1.5.13",
|
|
||||||
"vue-tippy": "^6.2.0",
|
|
||||||
"qrcode": "^1.5.3",
|
"qrcode": "^1.5.3",
|
||||||
"qs": "^6.11.2",
|
"qs": "^6.11.2",
|
||||||
"responsive-storage": "^2.2.0",
|
"responsive-storage": "^2.2.0",
|
||||||
|
|
@ -57,6 +57,7 @@
|
||||||
"typeit": "^8.7.1",
|
"typeit": "^8.7.1",
|
||||||
"vue": "^3.3.4",
|
"vue": "^3.3.4",
|
||||||
"vue-router": "^4.2.2",
|
"vue-router": "^4.2.2",
|
||||||
|
"vue-tippy": "^6.2.0",
|
||||||
"vue-types": "^5.1.0",
|
"vue-types": "^5.1.0",
|
||||||
"xlsx": "^0.18.5"
|
"xlsx": "^0.18.5"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,9 @@ importers:
|
||||||
axios:
|
axios:
|
||||||
specifier: ^1.4.0
|
specifier: ^1.4.0
|
||||||
version: 1.8.1
|
version: 1.8.1
|
||||||
|
compressorjs:
|
||||||
|
specifier: ^1.2.1
|
||||||
|
version: 1.2.1
|
||||||
cropperjs:
|
cropperjs:
|
||||||
specifier: ^1.5.13
|
specifier: ^1.5.13
|
||||||
version: 1.6.2
|
version: 1.6.2
|
||||||
|
|
@ -771,36 +774,42 @@ packages:
|
||||||
engines: {node: '>= 10.0.0'}
|
engines: {node: '>= 10.0.0'}
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@parcel/watcher-linux-arm-musl@2.5.1':
|
'@parcel/watcher-linux-arm-musl@2.5.1':
|
||||||
resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==}
|
resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==}
|
||||||
engines: {node: '>= 10.0.0'}
|
engines: {node: '>= 10.0.0'}
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
'@parcel/watcher-linux-arm64-glibc@2.5.1':
|
'@parcel/watcher-linux-arm64-glibc@2.5.1':
|
||||||
resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==}
|
resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==}
|
||||||
engines: {node: '>= 10.0.0'}
|
engines: {node: '>= 10.0.0'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@parcel/watcher-linux-arm64-musl@2.5.1':
|
'@parcel/watcher-linux-arm64-musl@2.5.1':
|
||||||
resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==}
|
resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==}
|
||||||
engines: {node: '>= 10.0.0'}
|
engines: {node: '>= 10.0.0'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
'@parcel/watcher-linux-x64-glibc@2.5.1':
|
'@parcel/watcher-linux-x64-glibc@2.5.1':
|
||||||
resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==}
|
resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==}
|
||||||
engines: {node: '>= 10.0.0'}
|
engines: {node: '>= 10.0.0'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@parcel/watcher-linux-x64-musl@2.5.1':
|
'@parcel/watcher-linux-x64-musl@2.5.1':
|
||||||
resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==}
|
resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==}
|
||||||
engines: {node: '>= 10.0.0'}
|
engines: {node: '>= 10.0.0'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
'@parcel/watcher-win32-arm64@2.5.1':
|
'@parcel/watcher-win32-arm64@2.5.1':
|
||||||
resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==}
|
resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==}
|
||||||
|
|
@ -1325,6 +1334,9 @@ packages:
|
||||||
resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
|
resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
|
blueimp-canvas-to-blob@3.29.0:
|
||||||
|
resolution: {integrity: sha512-0pcSSGxC0QxT+yVkivxIqW0Y4VlO2XSDPofBAqoJ1qJxgH9eiUDLv50Rixij2cDuEfx4M6DpD9UGZpRhT5Q8qg==}
|
||||||
|
|
||||||
boolbase@1.0.0:
|
boolbase@1.0.0:
|
||||||
resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==}
|
resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==}
|
||||||
|
|
||||||
|
|
@ -1500,6 +1512,9 @@ packages:
|
||||||
compare-func@2.0.0:
|
compare-func@2.0.0:
|
||||||
resolution: {integrity: sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==}
|
resolution: {integrity: sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==}
|
||||||
|
|
||||||
|
compressorjs@1.2.1:
|
||||||
|
resolution: {integrity: sha512-+geIjeRnPhQ+LLvvA7wxBQE5ddeLU7pJ3FsKFWirDw6veY3s9iLxAQEw7lXGHnhCJvBujEQWuNnGzZcvCvdkLQ==}
|
||||||
|
|
||||||
computeds@0.0.1:
|
computeds@0.0.1:
|
||||||
resolution: {integrity: sha512-7CEBgcMjVmitjYo5q8JTJVra6X5mQ20uTThdK+0kR7UEaDrAWEQcRiBtWJzga4eRpP6afNwwLsX2SET2JhVB1Q==}
|
resolution: {integrity: sha512-7CEBgcMjVmitjYo5q8JTJVra6X5mQ20uTThdK+0kR7UEaDrAWEQcRiBtWJzga4eRpP6afNwwLsX2SET2JhVB1Q==}
|
||||||
|
|
||||||
|
|
@ -2295,6 +2310,10 @@ packages:
|
||||||
resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
|
resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
|
is-blob@2.1.0:
|
||||||
|
resolution: {integrity: sha512-SZ/fTft5eUhQM6oF/ZaASFDEdbFVe89Imltn9uZr03wdKMcWNVYSMjQPFtg05QuNkt5l5c135ElvXEQG0rk4tw==}
|
||||||
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
is-builtin-module@3.2.1:
|
is-builtin-module@3.2.1:
|
||||||
resolution: {integrity: sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==}
|
resolution: {integrity: sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
|
|
@ -4540,7 +4559,7 @@ snapshots:
|
||||||
'@types/node': 20.5.1
|
'@types/node': 20.5.1
|
||||||
chalk: 4.1.2
|
chalk: 4.1.2
|
||||||
cosmiconfig: 8.3.6(typescript@5.8.2)
|
cosmiconfig: 8.3.6(typescript@5.8.2)
|
||||||
cosmiconfig-typescript-loader: 4.4.0(@types/node@20.5.1)(cosmiconfig@8.3.6(typescript@5.8.2))(ts-node@10.9.2(@types/node@20.5.1)(typescript@5.8.2))(typescript@5.8.2)
|
cosmiconfig-typescript-loader: 4.4.0(@types/node@20.5.1)(cosmiconfig@8.3.6(typescript@5.0.4))(ts-node@10.9.2(@types/node@20.17.22)(typescript@5.0.4))(typescript@5.8.2)
|
||||||
lodash.isplainobject: 4.0.6
|
lodash.isplainobject: 4.0.6
|
||||||
lodash.merge: 4.6.2
|
lodash.merge: 4.6.2
|
||||||
lodash.uniq: 4.5.0
|
lodash.uniq: 4.5.0
|
||||||
|
|
@ -5494,6 +5513,8 @@ snapshots:
|
||||||
|
|
||||||
binary-extensions@2.3.0: {}
|
binary-extensions@2.3.0: {}
|
||||||
|
|
||||||
|
blueimp-canvas-to-blob@3.29.0: {}
|
||||||
|
|
||||||
boolbase@1.0.0: {}
|
boolbase@1.0.0: {}
|
||||||
|
|
||||||
brace-expansion@1.1.11:
|
brace-expansion@1.1.11:
|
||||||
|
|
@ -5680,6 +5701,11 @@ snapshots:
|
||||||
array-ify: 1.0.0
|
array-ify: 1.0.0
|
||||||
dot-prop: 5.3.0
|
dot-prop: 5.3.0
|
||||||
|
|
||||||
|
compressorjs@1.2.1:
|
||||||
|
dependencies:
|
||||||
|
blueimp-canvas-to-blob: 3.29.0
|
||||||
|
is-blob: 2.1.0
|
||||||
|
|
||||||
computeds@0.0.1: {}
|
computeds@0.0.1: {}
|
||||||
|
|
||||||
concat-map@0.0.1: {}
|
concat-map@0.0.1: {}
|
||||||
|
|
@ -5716,7 +5742,7 @@ snapshots:
|
||||||
|
|
||||||
convert-source-map@2.0.0: {}
|
convert-source-map@2.0.0: {}
|
||||||
|
|
||||||
cosmiconfig-typescript-loader@4.4.0(@types/node@20.5.1)(cosmiconfig@8.3.6(typescript@5.8.2))(ts-node@10.9.2(@types/node@20.5.1)(typescript@5.8.2))(typescript@5.8.2):
|
cosmiconfig-typescript-loader@4.4.0(@types/node@20.5.1)(cosmiconfig@8.3.6(typescript@5.0.4))(ts-node@10.9.2(@types/node@20.17.22)(typescript@5.0.4))(typescript@5.8.2):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 20.5.1
|
'@types/node': 20.5.1
|
||||||
cosmiconfig: 8.3.6(typescript@5.8.2)
|
cosmiconfig: 8.3.6(typescript@5.8.2)
|
||||||
|
|
@ -6590,6 +6616,8 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
binary-extensions: 2.3.0
|
binary-extensions: 2.3.0
|
||||||
|
|
||||||
|
is-blob@2.1.0: {}
|
||||||
|
|
||||||
is-builtin-module@3.2.1:
|
is-builtin-module@3.2.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
builtin-modules: 3.3.0
|
builtin-modules: 3.3.0
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue