Skip to content

Commit dec7ac8

Browse files
committed
fix: 统一 API 数据结构,修复 lint 和类型错误
- 修复 UserStatus: banned → suspended - 修复 DashboardStats 字段: userChange → userGrowth 等 - 修复 LucideIcon 类型兼容性问题 - 修复 ESLint warnings (no-explicit-any, react-hooks/exhaustive-deps) - 配置本地开发 API 代理
1 parent b662f8d commit dec7ac8

8 files changed

Lines changed: 55 additions & 36 deletions

File tree

src/components/common/CommandPalette.tsx

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ import {
1414
Sun,
1515
Moon,
1616
LogOut,
17-
UserCheck
17+
UserCheck,
18+
type LucideIcon
1819
} from 'lucide-preact'
1920
import { accounts, activeAccountId, switchAccount, logout } from '../../stores/auth'
2021

@@ -26,7 +27,7 @@ interface CommandPaletteProps {
2627
interface Command {
2728
id: string
2829
label: string
29-
icon: any
30+
icon: LucideIcon
3031
action: () => void | boolean | Promise<void>
3132
keywords?: string[]
3233
category: string
@@ -158,7 +159,9 @@ export function CommandPalette({ open, onOpenChange }: CommandPaletteProps) {
158159
id: 'action-search',
159160
label: '全局搜索',
160161
icon: Search,
161-
action: () => console.log('全局搜索'),
162+
action: () => {
163+
// TODO: 实现全局搜索功能
164+
},
162165
keywords: ['search', 'find'],
163166
category: '操作'
164167
},
@@ -202,6 +205,14 @@ export function CommandPalette({ open, onOpenChange }: CommandPaletteProps) {
202205
return groups
203206
}, {} as Record<string, Command[]>)
204207

208+
// 执行命令
209+
const executeCommand = useCallback(async (cmd: Command) => {
210+
onOpenChange(false)
211+
setSearch('')
212+
setSelectedIndex(0)
213+
await cmd.action()
214+
}, [onOpenChange])
215+
205216
// 键盘快捷键
206217
useEffect(() => {
207218
const handleKeyDown = (e: KeyboardEvent) => {
@@ -240,20 +251,13 @@ export function CommandPalette({ open, onOpenChange }: CommandPaletteProps) {
240251

241252
document.addEventListener('keydown', handleKeyDown)
242253
return () => document.removeEventListener('keydown', handleKeyDown)
243-
}, [open, filteredCommands, selectedIndex])
254+
}, [open, filteredCommands, selectedIndex, executeCommand, onOpenChange])
244255

245256
// 重置选中索引当搜索改变时
246257
useEffect(() => {
247258
setSelectedIndex(0)
248259
}, [search])
249260

250-
const executeCommand = useCallback(async (cmd: Command) => {
251-
onOpenChange(false)
252-
setSearch('')
253-
setSelectedIndex(0)
254-
await cmd.action()
255-
}, [onOpenChange])
256-
257261
if (!open) return null
258262

259263
return (
@@ -310,7 +314,7 @@ export function CommandPalette({ open, onOpenChange }: CommandPaletteProps) {
310314
onClick={() => executeCommand(cmd)}
311315
onMouseEnter={() => setSelectedIndex(globalIndex)}
312316
>
313-
<Icon class="h-4 w-4" />
317+
<Icon className="h-4 w-4" />
314318
<span class="flex-1 text-left">{cmd.label}</span>
315319
{cmd.id.startsWith('account-') &&
316320
cmd.id === `account-${activeAccountId.value}` && (

src/components/common/TabBar.tsx

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { useEffect, useRef, useState, useCallback } from 'preact/hooks'
22
import { route, getCurrentUrl } from 'preact-router'
3-
import { ChevronLeft, ChevronRight, X, Home, Users, Settings, FileText } from 'lucide-preact'
3+
import { ChevronLeft, ChevronRight, X, Home, Users, Settings, FileText, type LucideIcon } from 'lucide-preact'
44
import {
55
tabs,
66
activeTabId,
@@ -48,7 +48,7 @@ const pathTitles: Record<string, string> = {
4848
}
4949

5050
// 路径到图标的映射
51-
const pathIcons: Record<string, any> = {
51+
const pathIcons: Record<string, LucideIcon> = {
5252
'/': Home,
5353
'/users': Users,
5454
'/settings': Settings,
@@ -62,7 +62,7 @@ const resolveTitle = (path: string): string => {
6262
return match ? match[1] : path.split('/').pop() || '新页面'
6363
}
6464

65-
const resolveIcon = (path: string): any => {
65+
const resolveIcon = (path: string): LucideIcon => {
6666
const match = Object.entries(pathIcons).find(
6767
([key]) => path === key || path.startsWith(`${key}/`)
6868
)
@@ -108,7 +108,7 @@ export function TabBar() {
108108
if (activeTab) {
109109
activeTab.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'center' })
110110
}
111-
}, [activeTabId.value])
111+
}, [])
112112

113113
// 监听路由变化,自动添加标签
114114
useEffect(() => {
@@ -130,7 +130,7 @@ export function TabBar() {
130130
useEffect(() => {
131131
checkScroll()
132132
scrollToActiveTab()
133-
}, [tabs.value, activeTabId.value, checkScroll, scrollToActiveTab])
133+
}, [checkScroll, scrollToActiveTab])
134134

135135
// 监听容器大小变化
136136
useEffect(() => {
@@ -251,15 +251,15 @@ export function TabBar() {
251251
: 'bg-muted/50 text-muted-foreground hover:bg-muted hover:text-foreground'
252252
}`}
253253
onClick={() => handleTabClick(tab)}
254-
onContextMenu={(e) => handleContextMenu(e as any, tab)}
254+
onContextMenu={(e) => handleContextMenu(e as unknown as MouseEvent, tab)}
255255
>
256256
{/* 活动指示器 */}
257257
{activeTabId.value === tab.id && (
258258
<div class="absolute bottom-0 left-0 right-0 h-0.5 bg-primary" />
259259
)}
260260

261261
{/* 图标 */}
262-
{Icon && <Icon class="h-3.5 w-3.5 shrink-0" />}
262+
{Icon && <Icon className="h-3.5 w-3.5 shrink-0" />}
263263

264264
{/* 标题 */}
265265
<span class="truncate text-sm">{tab.title}</span>
@@ -272,7 +272,7 @@ export function TabBar() {
272272
? 'opacity-100'
273273
: 'opacity-0 group-hover:opacity-100'
274274
}`}
275-
onClick={(e) => handleCloseTab(e as any, tab)}
275+
onClick={(e) => handleCloseTab(e as unknown as MouseEvent, tab)}
276276
>
277277
<X class="h-3 w-3" />
278278
</button>
@@ -306,7 +306,7 @@ export function TabBar() {
306306
class="w-full px-3 py-1.5 text-sm text-left hover:bg-accent hover:text-accent-foreground"
307307
onClick={() => {
308308
if (contextMenu.tab) {
309-
handleCloseTab(new MouseEvent('click') as any, contextMenu.tab)
309+
handleCloseTab(new MouseEvent('click'), contextMenu.tab)
310310
}
311311
}}
312312
>

src/lib/keep-alive.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import type { ComponentChildren } from 'preact'
12
import { signal } from '@preact/signals'
23
import { useEffect, useCallback } from 'preact/hooks'
34
import { getCurrentUrl } from 'preact-router'
@@ -129,13 +130,15 @@ export function useFormCache<T extends Record<string, unknown>>(
129130
(newValues: T) => {
130131
setValuesSignal(newValues)
131132
},
133+
// eslint-disable-next-line react-hooks/exhaustive-deps
132134
[cacheKey]
133135
)
134136

135137
// 清除缓存
136138
const clearCache = useCallback(() => {
137139
setValuesSignal(initialValues)
138140
clearPageState(cacheKey)
141+
// eslint-disable-next-line react-hooks/exhaustive-deps
139142
}, [cacheKey, initialValues])
140143

141144
return [values as unknown as T, saveValues, clearCache]
@@ -171,6 +174,7 @@ export function useStateCache<T>(
171174
customState: { ...pageState.customState, [key]: newValue },
172175
})
173176
},
177+
// eslint-disable-next-line react-hooks/exhaustive-deps
174178
[cacheKey, key]
175179
)
176180

@@ -181,7 +185,7 @@ export function useStateCache<T>(
181185
* KeepAlive 组件包装器
182186
*/
183187
interface KeepAliveWrapperProps {
184-
children: any
188+
children: ComponentChildren
185189
}
186190

187191
export function KeepAliveWrapper({ children }: KeepAliveWrapperProps) {

src/mock/modules/dashboard.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,13 @@ const { Random } = Mock
1515
function generateDashboardStats(): DashboardStats {
1616
return {
1717
totalUsers: Random.integer(1000, 5000),
18-
userChange: Random.float(-20, 20, 2, 2),
18+
userGrowth: Random.float(-20, 20, 2, 2),
1919
totalRevenue: Random.integer(50000, 200000),
20-
revenueChange: Random.float(-10, 30, 2, 2),
20+
revenueGrowth: Random.float(-10, 30, 2, 2),
2121
totalOrders: Random.integer(100, 1000),
22-
orderChange: Random.float(-15, 25, 2, 2),
22+
orderGrowth: Random.float(-15, 25, 2, 2),
2323
conversionRate: Random.float(1, 10, 2, 2),
24-
conversionChange: Random.float(-5, 15, 2, 2)
24+
rateGrowth: Random.float(-5, 15, 2, 2)
2525
}
2626
}
2727

src/mock/modules/users.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ const ROLES: Role[] = [
4343

4444
// 生成随机用户数据
4545
function generateUsers(count: number): User[] {
46-
const statuses: UserStatus[] = ['active', 'inactive', 'banned']
46+
const statuses: UserStatus[] = ['active', 'inactive', 'suspended']
4747
const departments = ['技术部', '市场部', '销售部', '人事部', '财务部', '运营部']
4848
const positions = ['经理', '主管', '专员', '助理', '工程师', '分析师']
4949

src/routes/DashboardView.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -122,28 +122,28 @@ export function DashboardView() {
122122
<StatCard
123123
title="总用户数"
124124
value={stats?.totalUsers.toLocaleString() || '0'}
125-
change={stats?.userChange || 0}
125+
change={stats?.userGrowth || 0}
126126
icon={Users}
127127
loading={loading}
128128
/>
129129
<StatCard
130130
title="总收入"
131131
value={${stats?.totalRevenue.toLocaleString() || '0'}`}
132-
change={stats?.revenueChange || 0}
132+
change={stats?.revenueGrowth || 0}
133133
icon={TrendingUp}
134134
loading={loading}
135135
/>
136136
<StatCard
137137
title="总订单"
138138
value={stats?.totalOrders.toLocaleString() || '0'}
139-
change={stats?.orderChange || 0}
139+
change={stats?.orderGrowth || 0}
140140
icon={ShoppingCart}
141141
loading={loading}
142142
/>
143143
<StatCard
144144
title="转化率"
145145
value={`${stats?.conversionRate || '0'}%`}
146-
change={stats?.conversionChange || 0}
146+
change={stats?.rateGrowth || 0}
147147
icon={Activity}
148148
loading={loading}
149149
/>

src/types/index.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ export interface Permission {
4646
description?: string
4747
}
4848

49-
export type UserStatus = 'active' | 'inactive' | 'banned'
49+
export type UserStatus = 'active' | 'inactive' | 'suspended'
5050

5151
/**
5252
* 认证相关类型
@@ -75,13 +75,13 @@ export interface ResetPasswordData {
7575
*/
7676
export interface DashboardStats {
7777
totalUsers: number
78-
userChange: number
78+
userGrowth: number
7979
totalRevenue: number
80-
revenueChange: number
80+
revenueGrowth: number
8181
totalOrders: number
82-
orderChange: number
82+
orderGrowth: number
8383
conversionRate: number
84-
conversionChange: number
84+
rateGrowth: number
8585
}
8686

8787
export interface ChartData {

vite.config.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,15 @@ import preact from '@preact/preset-vite'
44
// https://vite.dev/config/
55
export default defineConfig({
66
plugins: [preact()],
7+
server: {
8+
port: 5173,
9+
// API 代理配置 - 解决跨域问题
10+
proxy: {
11+
'/api': {
12+
target: process.env.VITE_API_BACKEND_URL || 'http://localhost:3000',
13+
changeOrigin: true,
14+
secure: false,
15+
},
16+
},
17+
},
718
})

0 commit comments

Comments
 (0)