update FRONTEND documentation

This commit is contained in:
beabigegg
2025-11-12 23:55:21 +08:00
parent 21bc2f92f1
commit fed112656f
5 changed files with 1748 additions and 1 deletions

View File

@@ -51,7 +51,9 @@
"Bash(TOKEN=\"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIzIiwidXNlcm5hbWUiOiJhZG1pbiIsImV4cCI6MTc2Mjk1ODUzOX0.S1JjFxVVmifdkN5F_dORt5jTRdTFN9MKJ8UJKuYacA8\")",
"Bash(tree:*)",
"Bash(done)",
"Bash(git add:*)"
"Bash(git add:*)",
"Bash(git commit:*)",
"Bash(git push)"
],
"deny": [],
"ask": []

511
FRONTEND_ANALYSIS.md Normal file
View File

@@ -0,0 +1,511 @@
# Tool_OCR 前端項目結構分析
## 項目概況
- **項目名稱**: Tool_OCR Frontend
- **框架**: React 19.2.0 (TypeScript)
- **構建工具**: Vite 7.2.2
- **樣式方案**: Tailwind CSS 4.1.17
- **路由管理**: React Router v7.9.5
- **狀態管理**: Zustand 5.0.8
- **數據獲取**: TanStack React Query v5.90.7
- **國際化**: i18next 25.6.2
- **源碼行數**: ~2,700 行
- **開發語言**: TypeScript
- **運行端口**: 12011
---
## 前端技術棧詳解
### 核心框架
- **React 19.2.0**: 最新版 React用於構建用戶界面
- 使用函數式組件
- React Hooks 進行狀態和副作用管理
- 嚴格模式StrictMode開啟
### 構建與開發
- **Vite 7.2.2**: 快速的前端構建工具
- 配置路徑別名 `@``./src`
- 開發服務器代理設定API 轉發到 localhost:12010
- TypeScript 支持
- **TypeScript ~5.9.3**: 類型檢查和增強開發體驗
- **ESLint + TypeScript ESLint**: 代碼質量檢查
- React Hooks 規則檢查
- React Refresh 支持
### 樣式設計
#### Tailwind CSS 4.1.17
- **CSS 框架**: 完全採用 Tailwind CSS
- **配置文件**: `/frontend/tailwind.config.js`
**主題配置 (HSL 色彩系統)**:
```
顏色變數 (CSS 自定義屬性):
- --background / --foreground (背景/前景)
- --primary / --primary-foreground (主色/主色前景)
- --secondary / --secondary-foreground (次色)
- --muted / --muted-foreground (灰色系)
- --accent / --accent-foreground (強調色)
- --destructive / --destructive-foreground (危險操作)
- --card / --card-foreground (卡片)
- --popover / --popover-foreground (彈出框)
- --border / --input (邊框/輸入框)
- --ring (焦點環)
```
**亮色模式**:
- 白色背景 (hsl(0 0% 100%))
- 深色文字 (hsl(222.2 84% 4.9%))
- 藍色主題 (hsl(221.2 83.2% 53.3%))
**暗色模式** (.dark class):
- 深色背景 (hsl(222.2 84% 4.9%))
- 淺色文字 (hsl(210 40% 98%))
#### PostCSS
- **配置文件**: `/frontend/postcss.config.js`
- **插件**: @tailwindcss/postcss (新版本原生支持)
#### 全局樣式
- **入口**: `/frontend/src/index.css`
- @tailwind 指令導入
- CSS 變數定義
- 亮色/暗色主題切換
---
## 項目目錄結構
```
frontend/
├── src/
│ ├── assets/ # 靜態資源
│ ├── components/ # React 組件
│ │ ├── ui/ # UI 基礎組件庫
│ │ │ ├── button.tsx # 按鈕組件 (多種變體)
│ │ │ ├── card.tsx # 卡片容器
│ │ │ ├── badge.tsx # 標籤組件
│ │ │ ├── table.tsx # 表格組件
│ │ │ ├── progress.tsx # 進度條
│ │ │ └── toast.tsx # 提示通知
│ │ ├── FileUpload.tsx # 文件上傳 (拖放支持)
│ │ ├── ResultsTable.tsx # 結果表格
│ │ ├── MarkdownPreview.tsx # Markdown 預覽
│ │ └── Layout.tsx # 主佈局組件
│ │
│ ├── pages/ # 頁面組件
│ │ ├── LoginPage.tsx # 登錄頁面
│ │ ├── UploadPage.tsx # 文件上傳頁面
│ │ ├── ProcessingPage.tsx # OCR 處理頁面
│ │ ├── ResultsPage.tsx # 結果查看頁面
│ │ ├── ExportPage.tsx # 導出配置頁面
│ │ └── SettingsPage.tsx # 系統設置頁面
│ │
│ ├── store/ # 狀態管理 (Zustand)
│ │ ├── authStore.ts # 認證狀態
│ │ └── uploadStore.ts # 上傳狀態
│ │
│ ├── services/ # API 服務層
│ │ └── api.ts # API 客戶端 (Axios)
│ │
│ ├── types/ # TypeScript 類型定義
│ │ └── api.ts # API 接口類型
│ │
│ ├── lib/ # 工具函數
│ │ └── utils.ts # cn() 函數 (Tailwind 類名合併)
│ │
│ ├── hooks/ # 自定義 React Hooks
│ │ └── (待擴展)
│ │
│ ├── i18n/ # 國際化配置
│ │ ├── index.ts # i18n 初始化
│ │ └── locales/
│ │ └── zh-TW.json # 繁體中文翻譯
│ │
│ ├── App.tsx # 應用根組件 (路由定義)
│ ├── main.tsx # 應用入口
│ ├── index.css # 全局樣式
│ └── App.css # 應用樣式 (可棄用)
├── public/ # 公開靜態資源
├── vite.config.ts # Vite 配置
├── tailwind.config.js # Tailwind 配置
├── postcss.config.js # PostCSS 配置
├── tsconfig.json # TypeScript 配置
├── tsconfig.app.json # 應用 TS 配置
├── tsconfig.node.json # Node TS 配置
├── eslint.config.js # ESLint 配置
├── index.html # HTML 入口
├── package.json # 依賴管理
├── package-lock.json # 依賴鎖定
└── .env # 環境變數
```
---
## 核心頁面和功能
### 頁面概述
| 頁面 | 路由 | 功能描述 | 行數 |
|------|------|--------|------|
| LoginPage | /login | 用戶認證 | 97 |
| UploadPage | /upload | 文件上傳,支持拖放 | 140 |
| ProcessingPage | /processing | 實時監控 OCR 處理進度 | 200 |
| ResultsPage | /results | 查看和下載 OCR 結果 | 157 |
| ExportPage | /export | 導出規則管理和結果導出 | 321 |
| SettingsPage | /settings | 系統配置和用戶偏好 | 325 |
### 總 UI 頁面代碼: ~1,240 行
---
## 組件架構
### UI 基礎組件庫 (/src/components/ui/)
採用現代化的無頭 UI 組件設計,配合 Tailwind CSS
1. **Button**
- 變體: default, destructive, outline, secondary, ghost, link
- 尺寸: default, sm, lg, icon
- 使用 cn() 實現動態類名合併
2. **Card**
- CardRoot, CardHeader, CardTitle, CardContent, CardFooter
- 容器組件,使用 Tailwind 樣式
3. **Table**
- 表格組件家族
- Table, TableHeader, TableBody, TableFooter, TableRow, TableHead, TableCell
4. **Badge**
- 標籤/徽章組件
- 用於狀態指示
5. **Progress**
- 進度條組件
- 百分比顯示
6. **Toast**
- 通知系統
- useToast() Hook
- 支持多個變體
### 業務組件
1. **FileUpload**
- react-dropzone 整合
- 支持拖放和點擊選擇
- 文件驗證 (類型、大小、數量)
- 自定義 accept 配置
2. **ResultsTable**
- 結果列表展示
3. **MarkdownPreview**
- Markdown 內容預覽
4. **Layout**
- 主體佈局
- 導航欄
- 頁頭
- 頁腳
---
## 狀態管理方案
### Zustand (v5.0.8)
#### 1. authStore.ts
```typescript
interface AuthState {
user: User | null
isAuthenticated: boolean
setUser: (user: User | null) => void
logout: () => void
}
```
- **持久化**: localStorage (auth-storage)
- **用途**: 管理登錄用戶信息和認證狀態
#### 2. uploadStore.ts
```typescript
interface UploadState {
batchId: number | null
files: FileInfo[]
uploadProgress: number
setBatchId: (id: number) => void
setFiles: (files: FileInfo[]) => void
setUploadProgress: (progress: number) => void
updateFileStatus: (fileId: number, status: string) => void
clearUpload: () => void
}
```
- **持久化**: localStorage (tool-ocr-upload-store)
- 只持久化: batchId, files (不持久化進度)
- **用途**: 管理當前上傳批次和文件信息
---
## API 服務層
### API 客戶端 (services/api.ts)
基於 Axios 的單例模式實現:
**配置**:
- Base URL: http://localhost:12010 (可通過 VITE_API_BASE_URL 環境變數覆蓋)
- API 版本: /api/v1
- 超時時間: 30 秒
- Content-Type: application/json
**功能模塊**:
1. **認證模塊**
- login(username, password)
- logout()
- Token 管理 (localStorage)
2. **文件上傳模塊**
- uploadFiles(files: File[])
- FormData multipart 上傳
3. **OCR 處理模塊**
- processOCR(batchId, lang, confidenceThreshold)
- getTaskStatus(taskId)
- getOCRResult(taskId)
- getBatchStatus(batchId)
4. **導出模塊**
- exportResults(batchId, format, options)
- exportPDF(fileId, cssTemplate)
- getExportRules()
- createExportRule(rule)
- updateExportRule(ruleId, rule)
- deleteExportRule(ruleId)
- getCSSTemplates()
5. **翻譯模塊** (計劃功能)
- translateDocument() [501 Not Implemented]
- getTranslationConfigs()
- createTranslationConfig()
**攔截器**:
- 請求攔截: 自動添加 Authorization Bearer token
- 響應攔截: 401 時清除 token 並重定向到登錄頁
---
## 類型定義
### 主要類型 (types/api.ts)
#### 認證
- LoginRequest, LoginResponse, User
#### 文件上傳
- UploadResponse, FileInfo
#### OCR 處理
- ProcessRequest, ProcessResponse, TaskStatus, BatchStatus, FileResult
#### OCR 結果
- OCRResult, OCRJsonData, TextBlock, LayoutInfo
#### 導出
- ExportRequest, ExportOptions, ExportRule, CSSTemplate
#### 翻譯 (Future)
- TranslateRequest, TranslateResponse, TranslationConfig
#### 錯誤處理
- ApiError, ApiResponse
---
## 國際化配置
### i18n (i18n/index.ts)
- **庫**: react-i18next v16.3.0
- **默認語言**: 繁體中文 (zh-TW)
- **翻譯文件**: /i18n/locales/zh-TW.json
### 翻譯內容結構
```json
{
"app": { title, subtitle },
"nav": { upload, processing, results, export, settings, logout },
"auth": { login, username, password, loginButton, loginError, welcomeBack },
"upload": { title, dragAndDrop, dropFilesHere, invalidFiles, ... },
"processing": { title, status, progress, currentFile, ... },
"results": { title, filename, status, confidence, ... },
"export": { title, format, formats, options, rules, cssTemplates, ... },
"settings": { ... },
"errors": { ... },
"common": { ... }
}
```
---
## 路由結構
### React Router v7.9.5 配置 (App.tsx)
```
/login → LoginPage (公開)
/ → Layout (受保護)
├── /upload → UploadPage
├── /processing → ProcessingPage
├── /results → ResultsPage
├── /export → ExportPage
└── /settings → SettingsPage
* → 重定向到 /
```
**保護機制**: ProtectedRoute 組件基於 authStore.isAuthenticated
---
## 樣式設計工具
### Tailwind 工具函數 (lib/utils.ts)
```typescript
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}
```
**功能**:
- clsx: 條件類名組合
- tailwind-merge: 解決 Tailwind 類名衝突
- 用於動態生成和合併 Tailwind 類
---
## 依賴概覽
### 主要依賴
```json
{
"react": "^19.2.0",
"react-dom": "^19.2.0",
"react-router-dom": "^7.9.5",
"zustand": "^5.0.8",
"@tanstack/react-query": "^5.90.7",
"axios": "^1.13.2",
"react-i18next": "^16.3.0",
"i18next": "^25.6.2",
"react-dropzone": "^14.3.8",
"tailwindcss": "^4.1.17",
"clsx": "^2.1.1",
"tailwind-merge": "^3.4.0"
}
```
### 開發依賴
```json
{
"typescript": "~5.9.3",
"vite": "^7.2.2",
"@vitejs/plugin-react": "^5.1.0",
"eslint": "^9.39.1",
"typescript-eslint": "^8.46.3",
"@tailwindcss/postcss": "^4.1.17",
"postcss": "^8.5.6",
"autoprefixer": "^10.4.22"
}
```
---
## 開發和構建
### 可用命令
```bash
npm run dev # 啟動開發服務器 (localhost:12011)
npm run build # 生產構建 (TypeScript 編譯 + Vite 打包)
npm run lint # ESLint 檢查
npm run preview # 預覽構建結果
```
### 開發服務器配置
- **端口**: 12011
- **代理**: /api → http://localhost:12010 (後端)
---
## 代碼質量
### ESLint 配置
- JavaScript ES2020 規範
- TypeScript 類型檢查
- React Hooks 規則 (recommended-latest)
- React Refresh 支持
- 瀏覽器全局變數支持
### TypeScript 配置
- 目標: ES2020
- 模塊: ESNext
- JSX: React-JSX (自動導入)
- 嚴格模式啟用
- 路徑別名: @ → ./src
---
## 文件統計
- **總文件數**: 28 個
- **源碼總大小**: 152 KB
- **代碼行數**: ~2,702 行 (TS/TSX/JSON)
- **UI 組件**: 6 個基礎組件
- **業務組件**: 4 個
- **頁面**: 6 個
- **工具函數**: 多個
---
## 樣式實現要點
1. **Tailwind CSS 優先**: 所有樣式都使用 Tailwind 工具類
2. **CSS 變數系統**: 使用 HSL 色彩空間,支持主題切換
3. **響應式設計**: 內置 Tailwind 響應式前綴支持
4. **可訪問性**: 焦點環、禁用狀態等 UI 反饋
5. **暗色模式**: 通過 .dark 類支持主題切換
6. **組件化**: UI 組件開箱即用,無需額外 CSS
---
## 總結
Tool_OCR 前端項目採用現代化的技術棧:
- **框架**: React 19 + TypeScript
- **構建**: Vite (快速開發和構建)
- **樣式**: Tailwind CSS 4 (工具類優先)
- **狀態**: Zustand (輕量級狀態管理)
- **數據**: React Query (服務器狀態管理)
- **路由**: React Router v7 (應用導航)
- **國際化**: i18next (多語言支持)
- **質量**: ESLint + TypeScript (靜態檢查)
**核心特點**:
1. 類型安全的開發環境
2. 響應式 UI 設計
3. 模塊化組件架構
4. 完整的狀態管理
5. API 層分離
6. 國際化就位
7. 開發友好 (HMR, 快速刷新)

652
FRONTEND_CODE_EXAMPLES.md Normal file
View File

@@ -0,0 +1,652 @@
# Tool_OCR 前端代碼示例和最佳實踐
## 1. Tailwind CSS 樣式使用示例
### 佈局組件 (Layout.tsx 提取)
```typescript
// 導航欄樣式示例
<header className="border-b bg-card">
<div className="container mx-auto px-4 py-4 flex items-center justify-between">
<h1 className="text-2xl font-bold text-foreground">{t('app.title')}</h1>
<button
className="px-4 py-2 text-sm font-medium text-foreground hover:text-primary transition-colors"
>
{t('nav.logout')}
</button>
</div>
</header>
{/* 導航選項卡 */}
<nav className="border-b bg-card">
<div className="container mx-auto px-4">
<ul className="flex space-x-1">
{navLinks.map((link) => (
<NavLink
to={link.to}
className={({ isActive }) =>
`block px-4 py-3 text-sm font-medium transition-colors ${
isActive
? 'text-primary border-b-2 border-primary'
: 'text-muted-foreground hover:text-foreground'
}`
}
>
{link.label}
</NavLink>
))}
</ul>
</div>
</nav>
```
### 按鈕變體示例 (button.tsx)
```typescript
// 默認按鈕
<Button>Save Changes</Button>
// 危險操作
<Button variant="destructive">Delete</Button>
// 輪廓樣式
<Button variant="outline">Cancel</Button>
// 幽靈按鈕
<Button variant="ghost">Remove</Button>
// 鏈接樣式
<Button variant="link">Learn More</Button>
// 不同尺寸
<Button size="sm">Small</Button>
<Button size="lg">Large</Button>
<Button size="icon">+</Button>
```
### 響應式卡片示例 (UploadPage.tsx 提取)
```typescript
<div className="max-w-4xl mx-auto space-y-6">
<Card>
<CardHeader>
<div className="flex items-center justify-between">
<CardTitle className="text-lg">
{t('upload.selectedFiles')} ({selectedFiles.length})
</CardTitle>
<Button variant="outline" size="sm" onClick={handleClearAll}>
{t('upload.clearAll')}
</Button>
</div>
</CardHeader>
<CardContent>
<div className="space-y-2">
{selectedFiles.map((file, index) => (
<div
key={index}
className="flex items-center justify-between p-3 bg-muted rounded-md"
>
<div className="flex-1 min-w-0">
<p className="text-sm font-medium text-foreground truncate">
{file.name}
</p>
<p className="text-xs text-muted-foreground">
{formatFileSize(file.size)}
</p>
</div>
<Button variant="ghost" size="sm" onClick={() => handleRemoveFile(index)}>
{t('upload.removeFile')}
</Button>
</div>
))}
</div>
</CardContent>
</Card>
</div>
```
### 文件上傳拖放區域 (FileUpload.tsx 提取)
```typescript
<Card
{...getRootProps()}
className={cn(
'border-2 border-dashed transition-colors cursor-pointer hover:border-primary/50',
{
'border-primary bg-primary/5': isDragActive && !isDragReject,
'border-destructive bg-destructive/5': isDragReject,
'opacity-50 cursor-not-allowed': disabled,
}
)}
>
<div className="p-12 text-center">
<input {...getInputProps()} />
<div className="mb-4">
<svg className="mx-auto h-12 w-12 text-muted-foreground" />
</div>
<div className="space-y-2">
{isDragActive ? (
<p className="text-lg font-medium text-primary">
{isDragReject ? t('upload.invalidFiles') : t('upload.dropFilesHere')}
</p>
) : (
<>
<p className="text-lg font-medium text-foreground">
{t('upload.dragAndDrop')}
</p>
<p className="text-sm text-muted-foreground">
{t('upload.supportedFormats')}
</p>
</>
)}
</div>
</div>
</Card>
```
---
## 2. React Query 使用示例
### 批次狀態查詢 (ResultsPage.tsx 提取)
```typescript
import { useQuery } from '@tanstack/react-query'
export default function ResultsPage() {
const { batchId } = useUploadStore()
const [selectedFileId, setSelectedFileId] = useState<number | null>(null)
// 獲取批次狀態
const { data: batchStatus, isLoading } = useQuery({
queryKey: ['batchStatus', batchId],
queryFn: () => apiClient.getBatchStatus(batchId!),
enabled: !!batchId, // 只在有 batchId 時查詢
})
// 獲取 OCR 結果
const { data: ocrResult, isLoading: isLoadingResult } = useQuery({
queryKey: ['ocrResult', selectedFileId],
queryFn: () => apiClient.getOCRResult(selectedFileId!.toString()),
enabled: !!selectedFileId,
})
if (!batchId) {
return <div>Please upload files first</div>
}
return (
<div>
{isLoading ? (
<p>Loading batch status...</p>
) : (
<ResultsTable data={batchStatus?.files} />
)}
</div>
)
}
```
---
## 3. Zustand 狀態管理示例
### 認證存儲 (authStore.ts)
```typescript
import { create } from 'zustand'
import { persist } from 'zustand/middleware'
import type { User } from '@/types/api'
interface AuthState {
user: User | null
isAuthenticated: boolean
setUser: (user: User | null) => void
logout: () => void
}
export const useAuthStore = create<AuthState>()(
persist(
(set) => ({
user: null,
isAuthenticated: false,
setUser: (user) =>
set({
user,
isAuthenticated: user !== null,
}),
logout: () =>
set({
user: null,
isAuthenticated: false,
}),
}),
{
name: 'auth-storage', // localStorage 鍵名
}
)
)
// 使用示例
function LoginPage() {
const setUser = useAuthStore((state) => state.setUser)
const handleLogin = async (username: string, password: string) => {
const response = await apiClient.login({ username, password })
setUser({ id: 1, username })
}
}
```
### 上傳狀態存儲 (uploadStore.ts)
```typescript
export const useUploadStore = create<UploadState>()(
persist(
(set) => ({
batchId: null,
files: [],
uploadProgress: 0,
setBatchId: (id) => {
set({ batchId: id })
},
setFiles: (files) => set({ files }),
setUploadProgress: (progress) => set({ uploadProgress: progress }),
updateFileStatus: (fileId, status) =>
set((state) => ({
files: state.files.map((file) =>
file.id === fileId ? { ...file, status } : file
),
})),
clearUpload: () =>
set({
batchId: null,
files: [],
uploadProgress: 0,
}),
}),
{
name: 'tool-ocr-upload-store',
// 只持久化 batchId 和 files不持久化進度
partialize: (state) => ({
batchId: state.batchId,
files: state.files,
}),
}
)
)
// 使用示例
function UploadPage() {
const { setBatchId, setFiles } = useUploadStore()
const handleUploadSuccess = (data: UploadResponse) => {
setBatchId(data.batch_id)
setFiles(data.files)
}
}
```
---
## 4. API 客戶端使用示例
### API 認證流程 (api.ts)
```typescript
// 登錄
const response = await apiClient.login({
username: 'admin',
password: 'password'
})
// Token 自動保存到 localStorage
// 後續請求自動附帶 token
const status = await apiClient.getBatchStatus(123)
// 請求頭自動包含: Authorization: Bearer <token>
// 登出
apiClient.logout()
// Token 自動從 localStorage 清除
```
### 文件上傳示例
```typescript
const handleUpload = async (files: File[]) => {
try {
const response = await apiClient.uploadFiles(files)
// response: { batch_id: 1, files: [...] }
setBatchId(response.batch_id)
setFiles(response.files)
} catch (error) {
// 自動處理 401 錯誤並重定向到登錄頁
showError(error.response?.data?.detail)
}
}
```
### 導出功能示例
```typescript
// 導出 PDF
const handleDownloadPDF = async (fileId: number) => {
const blob = await apiClient.exportPDF(fileId)
const url = window.URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = `ocr-result-${fileId}.pdf`
a.click()
window.URL.revokeObjectURL(url)
}
// 導出規則管理
const rules = await apiClient.getExportRules()
const newRule = await apiClient.createExportRule({
rule_name: 'My Rule',
config_json: { /* ... */ }
})
await apiClient.updateExportRule(rule.id, { rule_name: 'Updated' })
await apiClient.deleteExportRule(rule.id)
```
---
## 5. 國際化使用示例
### 在組件中使用翻譯
```typescript
import { useTranslation } from 'react-i18next'
export default function UploadPage() {
const { t } = useTranslation()
return (
<div>
<h1>{t('upload.title')}</h1>
<p>{t('upload.dragAndDrop')}</p>
{/* 帶插值的翻譯 */}
<p>{t('upload.fileCount', { count: 5 })}</p>
{/* 會渲染: "已選擇 5 個檔案" */}
<button>{t('upload.uploadButton')}</button>
</div>
)
}
```
### i18n 初始化 (i18n/index.ts)
```typescript
import i18n from 'i18next'
import { initReactI18next } from 'react-i18next'
import zhTW from './locales/zh-TW.json'
i18n.use(initReactI18next).init({
resources: {
'zh-TW': {
translation: zhTW,
},
},
lng: 'zh-TW',
fallbackLng: 'zh-TW',
interpolation: {
escapeValue: false,
},
})
export default i18n
```
---
## 6. 路由和保護示例
### 受保護的路由 (App.tsx)
```typescript
function ProtectedRoute({ children }: { children: React.ReactNode }) {
const isAuthenticated = useAuthStore((state) => state.isAuthenticated)
if (!isAuthenticated) {
return <Navigate to="/login" replace />
}
return <>{children}</>
}
function App() {
return (
<Routes>
{/* 公開路由 */}
<Route path="/login" element={<LoginPage />} />
{/* 受保護的路由 */}
<Route
path="/"
element={
<ProtectedRoute>
<Layout />
</ProtectedRoute>
}
>
<Route index element={<Navigate to="/upload" replace />} />
<Route path="upload" element={<UploadPage />} />
<Route path="processing" element={<ProcessingPage />} />
<Route path="results" element={<ResultsPage />} />
<Route path="export" element={<ExportPage />} />
<Route path="settings" element={<SettingsPage />} />
</Route>
{/* 全部匹配 */}
<Route path="*" element={<Navigate to="/" replace />} />
</Routes>
)
}
```
---
## 7. 類型定義示例
### API 類型 (types/api.ts)
```typescript
// 認證
export interface LoginRequest {
username: string
password: string
}
export interface LoginResponse {
access_token: string
token_type: string
}
// 文件上傳
export interface UploadResponse {
batch_id: number
files: FileInfo[]
}
export interface FileInfo {
id: number
filename: string
file_size: number
format: string
status: 'pending' | 'processing' | 'completed' | 'failed'
}
// OCR 結果
export interface OCRResult {
file_id: number
filename: string
status: string
markdown_content: string
json_data: OCRJsonData
confidence: number
processing_time: number
}
export interface TextBlock {
text: string
confidence: number
bbox: [number, number, number, number]
position: number
}
// 導出規則
export interface ExportRule {
id: number
rule_name: string
config_json: Record<string, any>
css_template?: string
created_at: string
}
```
---
## 8. 最佳實踐
### 1. 組件結構
```typescript
// 導入順序
import { useState } from 'react'
import { useNavigate } from 'react-router-dom'
import { useTranslation } from 'react-i18next'
import { useQuery } from '@tanstack/react-query'
// 內部導入
import { Button } from '@/components/ui/button'
import { Card } from '@/components/ui/card'
import { useAuthStore } from '@/store/authStore'
import { apiClient } from '@/services/api'
// 組件定義
export default function MyPage() {
// Hooks
const { t } = useTranslation()
const navigate = useNavigate()
const [state, setState] = useState(null)
// 查詢
const { data, isLoading } = useQuery({
queryKey: ['key'],
queryFn: () => apiClient.getData(),
})
// 狀態更新
const handleClick = () => {
// ...
}
// 渲染
return (
<div className="space-y-4">
{/* JSX */}
</div>
)
}
```
### 2. 錯誤處理
```typescript
const { toast } = useToast()
const handleAction = async () => {
try {
const result = await apiClient.doSomething()
toast({
title: t('success.title'),
description: t('success.message'),
variant: 'success',
})
} catch (error: any) {
const errorMessage = error.response?.data?.detail || t('errors.generic')
toast({
title: t('error.title'),
description: errorMessage,
variant: 'destructive',
})
}
}
```
### 3. 類名合併
```typescript
import { cn } from '@/lib/utils'
// 條件類名
const buttonClass = cn(
'base-classes',
{
'conditional-classes': isActive,
'other-classes': isDisabled,
},
customClassName
)
// 動態樣式
const cardClass = cn(
'p-4 rounded-lg',
variant === 'outlined' && 'border border-input',
variant === 'elevated' && 'shadow-lg'
)
```
### 4. React Query 配置
```typescript
// 主入口 (main.tsx)
const queryClient = new QueryClient({
defaultOptions: {
queries: {
retry: 1,
refetchOnWindowFocus: false,
staleTime: 1000 * 60 * 5, // 5 分鐘
},
},
})
// 使用示例
const { data, isLoading, error } = useQuery({
queryKey: ['items', id],
queryFn: () => apiClient.getItem(id),
enabled: !!id, // 條件查詢
staleTime: 1000 * 60 * 10, // 10 分鐘不新鮮
})
```
---
## 9. 環境變數
### .env 文件
```env
VITE_API_BASE_URL=http://localhost:12010
```
### 使用環境變數
```typescript
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || 'http://localhost:12010'
```
---
## 10. 常見開發流程
### 創建新頁面
1.`/src/pages` 創建 `NewPage.tsx`
2.`App.tsx` 添加路由
3. 使用 Zustand 管理狀態
4. 使用 React Query 獲取數據
5. 使用 Tailwind CSS 樣式
6. 使用 i18next 添加文字
### 添加新 API 接口
1.`types/api.ts` 定義類型
2.`services/api.ts` 添加方法
3. 在需要的地方使用 `apiClient.method()`
4. 使用 React Query 或直接調用
### 修改樣式
1. 優先使用 Tailwind CSS 工具類
2. 使用 cn() 合併類名
3. 修改 `tailwind.config.js` 自定義主題
4.`index.css` 添加全局樣式

397
FRONTEND_QUICK_REFERENCE.md Normal file
View File

@@ -0,0 +1,397 @@
# Tool_OCR 前端快速參考指南
## 文件位置速查表
### 主要文件位置
```
/Users/egg/Projects/Tool_OCR/frontend/
├── src/
│ ├── App.tsx # 路由定義
│ ├── main.tsx # 應用入口
│ ├── index.css # 全局樣式
│ ├── components/
│ │ ├── ui/ # UI 組件庫
│ │ ├── Layout.tsx # 主佈局
│ │ ├── FileUpload.tsx # 文件上傳
│ │ └── ...
│ ├── pages/ # 頁面
│ ├── store/ # 狀態管理
│ ├── services/api.ts # API 客戶端
│ ├── types/api.ts # 類型定義
│ ├── i18n/ # 國際化
│ └── lib/utils.ts # 工具函數
├── vite.config.ts # Vite 配置
├── tailwind.config.js # Tailwind 配置
├── tsconfig.json # TypeScript 配置
└── package.json # 依賴管理
```
---
## 技術棧速查
| 功能 | 技術 | 版本 |
|-----|------|------|
| UI 框架 | React | 19.2.0 |
| 語言 | TypeScript | 5.9.3 |
| 構建 | Vite | 7.2.2 |
| 樣式 | Tailwind CSS | 4.1.17 |
| 狀態管理 | Zustand | 5.0.8 |
| 數據獲取 | React Query | 5.90.7 |
| 路由 | React Router | 7.9.5 |
| 國際化 | i18next | 25.6.2 |
| HTTP | Axios | 1.13.2 |
| 檔案上傳 | react-dropzone | 14.3.8 |
---
## 常用命令
```bash
# 開發
cd frontend
npm run dev # 啟動開發服務器 (localhost:12011)
npm run lint # 代碼檢查
npm run build # 生產構建
# 類型檢查
npx tsc --noEmit # 檢查 TypeScript 錯誤
# 格式化
npm install -D prettier # (如果需要)
npx prettier --write src/ # 格式化代碼
```
---
## 路由結構
```
/login → LoginPage (公開)
/upload → UploadPage (受保護)
/processing → ProcessingPage (受保護)
/results → ResultsPage (受保護)
/export → ExportPage (受保護)
/settings → SettingsPage (受保護)
```
### 添加新路由
```typescript
// 在 App.tsx 中
<Route path="new-page" element={<NewPage />} />
// 在導航中
{ to: '/new-page', label: t('nav.newPage') }
```
---
## 常用代碼片段
### 使用 i18n 翻譯
```typescript
const { t } = useTranslation()
<h1>{t('key.path')}</h1>
```
### 使用 Zustand 狀態
```typescript
const { batchId, setBatchId } = useUploadStore()
const { user, logout } = useAuthStore()
```
### 調用 API
```typescript
const data = await apiClient.uploadFiles(files)
const status = await apiClient.getBatchStatus(batchId)
```
### React Query 查詢
```typescript
const { data, isLoading } = useQuery({
queryKey: ['key', id],
queryFn: () => apiClient.getData(id),
})
```
### Tailwind 樣式
```typescript
className="flex items-center justify-between p-4 bg-card rounded-lg"
className={cn('base', { 'conditional': isActive })}
```
### 提示通知
```typescript
const { toast } = useToast()
toast({
title: 'Success',
description: 'Action completed',
variant: 'success',
})
```
---
## 調試技巧
### 查看存儲在 localStorage 的狀態
```javascript
// 在瀏覽器控制台
console.log(JSON.parse(localStorage.getItem('auth-storage')))
console.log(JSON.parse(localStorage.getItem('tool-ocr-upload-store')))
```
### 查看 React Query 緩存
```javascript
// 在瀏覽器控制台安裝 React Query DevTools
// npm install @tanstack/react-query-devtools
```
### TypeScript 錯誤
```bash
# 運行編譯器檢查類型
npx tsc --noEmit
```
---
## 環境變數配置
### 開發環境 (.env)
```env
VITE_API_BASE_URL=http://localhost:12010
```
### 使用環境變數
```typescript
const baseURL = import.meta.env.VITE_API_BASE_URL
```
---
## 常見問題
### Q: 如何添加新的頁面?
A:
1.`/src/pages` 創建 `NewPage.tsx`
2.`App.tsx` 添加路由
3. 在 Layout.tsx 導航中添加鏈接
### Q: 如何修改主題顏色?
A:
1. 編輯 `src/index.css` 中的 CSS 變數
2. 或編輯 `tailwind.config.js`
### Q: 如何添加新的翻譯?
A:
1. 編輯 `src/i18n/locales/zh-TW.json`
2. 在組件中使用 `t('key.path')`
### Q: 如何調試 API 請求?
A:
1. 打開瀏覽器開發者工具 (Network 標籤)
2. 檢查 `/api/v1/` 的請求
### Q: 上傳文件怎樣無法工作?
A:
1. 檢查後端是否在運行 (localhost:12010)
2. 檢查文件格式是否被支持
3. 檢查文件大小是否超過 50MB
### Q: 認證登錄失敗?
A:
1. 檢查用戶名和密碼
2. 檢查後端認證端點 `/api/v1/auth/login`
3. 檢查 localStorage 中的 token
---
## 依賴更新
```bash
# 檢查過期依賴
npm outdated
# 更新依賴
npm update
# 更新到最新版本
npm install --save-latest package-name
# 清除 node_modules 並重新安裝
rm -rf node_modules package-lock.json
npm install
```
---
## 性能優化
### 代碼分割
```typescript
import { lazy, Suspense } from 'react'
const NewPage = lazy(() => import('./pages/NewPage'))
// 在 Routes 中
<Suspense fallback={<div>Loading...</div>}>
<NewPage />
</Suspense>
```
### 優化 React Query
```typescript
const { data } = useQuery({
queryKey: ['items'],
queryFn: () => apiClient.getItems(),
staleTime: 1000 * 60 * 5, // 5 分鐘內不重新獲取
gcTime: 1000 * 60 * 10, // 10 分鐘後從緩存中移除
})
```
### 優化組件
```typescript
// 使用 React.memo 避免不必要的重新渲染
export default React.memo(function MyComponent(props) {
return <div>{props.data}</div>
})
```
---
## 測試 (可選)
```bash
# 安裝測試工具
npm install -D vitest @testing-library/react
# 運行測試
npm test
# 生成覆蓋率報告
npm test -- --coverage
```
---
## 構建和部署
```bash
# 生產構建
npm run build
# 預覽構建
npm run preview
# 構建後的文件位置
# dist/
# 部署
# 將 dist/ 目錄上傳到服務器
# 配置 Web 服務器支持 SPA (所有路由都指向 index.html)
```
---
## 貢獻指南
### 代碼風格
- 使用 TypeScript 進行類型安全
- 遵循現有的命名約定
- 優先使用 Tailwind CSS
- 添加必要的類型定義
### 提交代碼
```bash
# 檢查代碼
npm run lint
# 提交
git add .
git commit -m "description of changes"
git push
```
---
## 有用的資源
### 文檔
- [React 文檔](https://react.dev)
- [Tailwind CSS](https://tailwindcss.com)
- [React Router](https://reactrouter.com)
- [Zustand](https://github.com/pmndrs/zustand)
- [React Query](https://tanstack.com/query)
- [i18next](https://www.i18next.com)
### 工具
- [Vite 文檔](https://vitejs.dev)
- [TypeScript 文檔](https://www.typescriptlang.org)
- [ESLint 文檔](https://eslint.org)
### IDE 擴展 (VS Code)
- Tailwind CSS IntelliSense
- Thunder Client (API 測試)
- React Developer Tools
- Redux DevTools (狀態檢查)
---
## 快速開始
```bash
# 1. 進入前端目錄
cd /Users/egg/Projects/Tool_OCR/frontend
# 2. 安裝依賴
npm install
# 3. 啟動開發服務器
npm run dev
# 4. 打開瀏覽器
# 訪問 http://localhost:12011
# 5. 登錄
# 使用後端提供的帳號密碼
# 6. 開始使用
# 上傳檔案 → 處理 → 查看結果 → 匯出
```
---
## 常用快捷鍵
### VS Code
- `Ctrl+Shift+F` (或 `Cmd+Shift+F` 在 Mac) - 全文搜索
- `Ctrl+K Ctrl+X` - 刪除行
- `Alt+Up/Down` - 移動行
- `Ctrl+/` - 註解行
### 瀏覽器開發者工具
- `F12``Ctrl+Shift+I` - 打開開發者工具
- `Ctrl+Shift+C` - 元素檢查器
- `Ctrl+Shift+M` - 響應式設計模式
---
## 總結速記
**架構**React 19 + TypeScript + Vite
**樣式**Tailwind CSS 4
**狀態**Zustand (輕量) + React Query (數據)
**路由**React Router v7
**API**Axios 單例客戶端
**國際化**i18next (繁體中文)
**開發端口**12011
**後端 API**localhost:12010
**核心文件**
- App.tsx (路由)
- main.tsx (入口)
- services/api.ts (API)
- store/*.ts (狀態)
- pages/ (頁面)
- components/ (組件)

185
FRONTEND_README.md Normal file
View File

@@ -0,0 +1,185 @@
# Tool_OCR 前端文檔索引
歡迎查閱 Tool_OCR 前端項目的完整文檔。本頁面將幫助您快速找到所需的信息。
## 文檔列表
### 1. FRONTEND_ANALYSIS.md
**完整的技術棧和項目結構分析**
包含內容:
- 項目概況和技術棧詳解
- 完整的目錄結構說明
- 核心頁面和功能概述
- 組件架構設計
- 狀態管理方案 (Zustand)
- API 服務層設計
- 類型定義系統
- 國際化配置
- 路由結構
- 依賴概覽
- 代碼質量檢查
- 樣式實現要點
**適合閱讀場景:**
- 全新成員了解項目整體架構
- 深入理解技術選擇和設計決策
- 查看完整的模塊組織結構
- 了解樣式系統的設計方式
### 2. FRONTEND_CODE_EXAMPLES.md
**實際代碼示例和最佳實踐**
包含內容:
- Tailwind CSS 使用示例 (佈局、按鈕、卡片等)
- React Query 數據獲取示例
- Zustand 狀態管理示例
- API 客戶端使用示例
- 國際化集成示例
- 路由和路由保護示例
- TypeScript 類型定義示例
- 最佳實踐指南 (組件結構、錯誤處理等)
- 環境變數配置
- 常見開發流程
**適合閱讀場景:**
- 開發新功能時參考代碼模式
- 尋找特定技術的使用示例
- 學習項目內的最佳實踐
- 複製粘貼代碼片段快速開發
### 3. FRONTEND_QUICK_REFERENCE.md
**快速查閱和常見問題**
包含內容:
- 文件位置速查表
- 技術棧版本速查
- 常用開發命令
- 路由結構速查
- 常用代碼片段
- 調試技巧
- 常見問題解答 (FAQ)
- 依賴更新指南
- 性能優化建議
- 構建和部署指南
- 有用資源鏈接
**適合閱讀場景:**
- 快速查找文件位置
- 尋找常用命令
- 解決常見問題
- 快速參考語法
- 了解開發工作流
## 快速開始路線圖
### 如果您是新開發者:
1. 先讀 **FRONTEND_QUICK_REFERENCE.md** 的「快速開始」部分
2. 再讀 **FRONTEND_ANALYSIS.md** 了解整體架構
3. 需要時查閱 **FRONTEND_CODE_EXAMPLES.md** 的相關示例
### 如果您需要開發新功能:
1. 查閱 **FRONTEND_QUICK_REFERENCE.md** 的「常用代碼片段」
2. 參考 **FRONTEND_CODE_EXAMPLES.md** 的相關示例
3. 根據功能類型選擇合適的設計模式
### 如果您遇到問題:
1. 查閱 **FRONTEND_QUICK_REFERENCE.md** 的「常見問題」
2. 查閱 **FRONTEND_QUICK_REFERENCE.md** 的「調試技巧」
3. 參考 **FRONTEND_CODE_EXAMPLES.md** 的「最佳實踐」
## 項目核心信息速記
### 技術棧
- **UI 框架**: React 19.2.0 + TypeScript
- **構建工具**: Vite 7.2.2
- **樣式**: Tailwind CSS 4.1.17
- **狀態管理**: Zustand 5.0.8 + React Query 5.90.7
- **路由**: React Router v7.9.5
- **HTTP**: Axios
- **國際化**: i18next (繁體中文)
### 開發環境
- **開發端口**: 12011
- **後端 API**: localhost:12010
- **命令**: `npm run dev` | `npm run build` | `npm run lint`
### 主要頁面
- `/login` - 登錄頁面
- `/upload` - 文件上傳
- `/processing` - OCR 處理
- `/results` - 結果查看
- `/export` - 結果導出
- `/settings` - 系統設置
### 核心目錄
- `/components` - React 組件
- `/pages` - 應用頁面
- `/store` - 狀態管理 (Zustand)
- `/services` - API 客戶端
- `/types` - TypeScript 類型
- `/i18n` - 國際化配置
## 文檔使用建議
### 打開文檔
所有文檔都保存在項目根目錄:
```
/Users/egg/Projects/Tool_OCR/FRONTEND_*.md
```
推薦使用 VS Code 或任何 Markdown 編輯器打開。
### 導航技巧
- 使用 Markdown 編輯器的大綱功能快速導航
- 使用 Ctrl+F (或 Cmd+F) 搜索關鍵詞
- 點擊標題鏈接快速跳轉
### 保持同步
文檔基於以下源代碼分析:
- React 19.2.0
- Vite 7.2.2
- Tailwind CSS 4.1.17
- 其他依賴均按 package.json 記錄
如果依賴升級或架構調整,請相應更新文檔。
## 常用快速鏈接
### 官方文檔
- [React 官方文檔](https://react.dev)
- [Tailwind CSS](https://tailwindcss.com)
- [Vite 文檔](https://vitejs.dev)
- [React Router](https://reactrouter.com)
- [Zustand](https://github.com/pmndrs/zustand)
- [React Query](https://tanstack.com/query)
- [i18next](https://www.i18next.com)
### IDE 推薦擴展 (VS Code)
- Tailwind CSS IntelliSense
- ES7+ React/Redux/React-Native snippets
- Thunder Client (API 測試)
- TypeScript Vue Plugin
- ESLint
## 文檔維護
這些文檔是對項目當前狀態的快照。當進行以下操作時應考慮更新:
- 升級主要依賴版本
- 更改項目結構
- 添加新的關鍵功能
- 改變設計模式或最佳實踐
- 優化或重構大型模塊
## 反饋和建議
如果發現文檔中有錯誤或遺漏,歡迎:
1. 直接編輯文檔並提交 PR
2. 創建 Issue 報告問題
3. 聯繫專案維護者
---
最後更新: 2024年11月12日
文檔覆蓋版本: React 19.2.0, Vite 7.2.2, Tailwind CSS 4.1.17