Skip to content

Commit dd501b4

Browse files
committed
style: 细微修改按钮样式
1 parent f00edda commit dd501b4

File tree

6 files changed

+100
-41
lines changed

6 files changed

+100
-41
lines changed
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# 列宽自定义功能实现计划
2+
3+
## 需求概述
4+
为 LabStorageManager 系统中的所有表格添加列宽自定义(拖动改变列宽)功能。
5+
6+
## 当前页面表格实现情况
7+
8+
| 页面 | 表格实现 | 分页 | 筛选/搜索 |
9+
|------|---------|------|-----------|
10+
| Dashboard | 原生 HTML table | 自定义 (slice) | 自定义 |
11+
| Inventory | TanStack Table | 自定义 (offset/limit) | 自定义 (globalFilter) |
12+
| ReagentOrders | TanStack Table | 自定义 | 自定义 |
13+
| ConsumableOrders | TanStack Table | 自定义 | 自定义 |
14+
| AdminUsers | TanStack Table | 自定义 | 自定义 |
15+
16+
**说明:** 所有页面的分页和筛选功能均使用自定义实现,非 TanStack 内置组件。
17+
18+
## 需求变更
19+
20+
### 1. Dashboard 表格改为 TanStack
21+
- Dashboard 当前使用原生 HTML table
22+
- 需要重构为 TanStack Table,与其他页面保持一致
23+
24+
### 2. 移动端无需加入此功能
25+
- 列宽调整功能仅在桌面端启用
26+
- 使用 `useMediaQuery` 检测移动端,隐藏拖拽手柄
27+
28+
### 3. 无需虚拟滚动
29+
- 当前分页每页最多 100 条
30+
- DOM 元素数量可控,无需虚拟滚动优化
31+
32+
## 技术方案
33+
34+
### TanStack Table 列宽调整
35+
TanStack Table v8 原生支持列宽调整,需要:
36+
-`useReactTable` 中配置 `columnResizeMode: 'onChange'`
37+
- 在列定义中设置 `size` 属性
38+
- 在表格元素上应用 `style={{ width: header.getSize() }}`
39+
- 添加可视化的拖拽手柄(Resize Handle)
40+
41+
## 实现步骤
42+
43+
1. 修改 Dashboard.tsx:将原生表格重构为 TanStack Table
44+
2. 修改 ResizableHeader.tsx:添加移动端检测逻辑
45+
3. 修改 Inventory.tsx:添加 ResizableHeader
46+
4. 修改 ReagentOrders.tsx:添加 ResizableHeader
47+
5. 修改 ConsumableOrders.tsx:添加 ResizableHeader
48+
6. 修改 AdminUsers.tsx:添加 ResizableHeader
49+
7. 添加全局 CSS 样式
50+
8. 测试验证
51+
52+
## localStorage 存储结构
53+
54+
```typescript
55+
interface ColumnSizes {
56+
[columnId: string]: number
57+
}
58+
59+
// Key: `table-column-sizes-${tableId}`
60+
// Value: JSON string of ColumnSizes
61+
```
62+
63+
## 页面表格标识
64+
65+
| 表格 | tableId |
66+
|------|---------|
67+
| Inventory | `inventory-table` |
68+
| ReagentOrders | `reagent-orders-table` |
69+
| ConsumableOrders | `consumable-orders-table` |
70+
| AdminUsers | `admin-users-table` |
71+
72+
## 注意事项
73+
74+
1. 拖拽手柄不应遮挡内容,需保证最小列宽(如 40px)
75+
2. 需要处理暗黑模式下的样式
76+
3. 避免拖拽时选中文字(user-select: none)
77+
4. 移动端检测:使用项目已有的 `useMobile` hook (`frontend/src/hooks/use-mobile.tsx`)

frontend/src/components/ui/button.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ const buttonVariants = cva(
99
variants: {
1010
variant: {
1111
default:
12-
"bg-primary text-base text-primary-foreground shadow-xs hover:bg-primary/90 border border-primary",
12+
"bg-primary text-base text-primary-foreground shadow-xs hover:bg-primary/90 border-0",
1313
destructive:
14-
"bg-destructive text-white text-base shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive hover:bg-destructive/70 dark:hover:bg-destructive/80",
14+
"bg-destructive text-destructive-foreground text-base shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive hover:bg-destructive/70 dark:hover:bg-destructive/80",
1515
outline:
1616
"border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
1717
secondary:

frontend/src/index.css

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -240,25 +240,6 @@
240240
opacity: 0;
241241
}
242242

243-
/* 表格行展开高度渐变动画 */
244-
@keyframes row-expand {
245-
from {
246-
max-height: 0;
247-
}
248-
to {
249-
max-height: 300px;
250-
}
251-
}
252-
253-
@keyframes row-collapse {
254-
from {
255-
max-height: 300px;
256-
}
257-
to {
258-
max-height: 0;
259-
}
260-
}
261-
262243
.table-row-expand-enter {
263244
animation: row-expand 0.25s ease-out forwards;
264245
}

frontend/src/pages/Dashboard.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -616,7 +616,7 @@ export function Dashboard() {
616616
<td className="p-3 align-middle text-base">{item.remaining_quantity} {item.unit}</td>
617617
<td className="p-3 align-middle text-base">{formatDateTime(item.borrow_time)}</td>
618618
<td className="p-3 align-middle text-base">
619-
<Button onClick={() => openReturnModal(item)} size="sm" className="h-8.5 text-sm/4 px-3">归还</Button>
619+
<Button onClick={() => openReturnModal(item)} size="sm" className="h-8 text-sm/4 px-3 bg-primary hover:bg-primary/80 border-0">归还</Button>
620620
</td>
621621
</tr>
622622
))}

frontend/src/pages/Inventory.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -201,10 +201,10 @@ const ActionButtons = React.memo(function ActionButtons({
201201
<Button
202202
size="sm"
203203
className={cn(
204-
"h-8.5 text-sm/4 px-3 transition-none",
204+
"h-8 text-sm/4 px-3",
205205
isConfirming
206-
? "bg-destructive hover:bg-destructive/90 border border-destructive"
207-
: "bg-primary hover:bg-primary/90 border border-primary",
206+
? "bg-destructive text-destructive-foreground hover:bg-destructive/70 dark:hover:bg-destructive/80"
207+
: "bg-primary hover:bg-primary/80 border-0",
208208
isLoading && "opacity-50 cursor-wait"
209209
)}
210210
onClick={handleClick}
@@ -1416,3 +1416,4 @@ export function InventoryPage() {
14161416
</div>
14171417
)
14181418
}
1419+

frontend/src/pages/Layout.tsx

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ export function Layout() {
116116
: 'gap-3 px-3',
117117
isActive
118118
? 'bg-primary text-primary-foreground'
119-
: 'text-sidebar-foreground hover:bg-muted hover:text-foreground'
119+
: 'text-sidebar-foreground hover:bg-muted'
120120
)}
121121
title={sidebarCollapsed ? item.title : undefined}
122122
>
@@ -155,7 +155,7 @@ export function Layout() {
155155
: 'gap-3 px-3',
156156
isActive
157157
? 'bg-primary text-primary-foreground'
158-
: 'text-sidebar-foreground hover:bg-muted hover:text-foreground'
158+
: 'text-sidebar-foreground hover:bg-muted'
159159
)}
160160
title={sidebarCollapsed ? item.title : undefined}
161161
>
@@ -179,7 +179,7 @@ export function Layout() {
179179
<div className="mt-auto p-3">
180180
<div className="pt-2">
181181
{/* 头像 */}
182-
<div className="flex items-center gap-3 mb-3">
182+
<div className={cn("flex items-center gap-3 mb-3", sidebarCollapsed ? "" : "ml-1")}>
183183
<div className="flex h-10 w-10 items-center justify-center rounded-full bg-primary text-primary-foreground flex-shrink-0">
184184
{user?.username?.charAt(0).toUpperCase() || 'U'}
185185
</div>
@@ -189,10 +189,10 @@ export function Layout() {
189189
sidebarCollapsed ? 'opacity-0 w-0' : 'opacity-100'
190190
)}
191191
>
192-
<p className="text-sm font-medium truncate text-sidebar-foreground whitespace-nowrap">
192+
<p className="text-base font-medium truncate text-sidebar-foreground whitespace-nowrap">
193193
{user?.full_name || user?.username}
194194
</p>
195-
<p className="text-xs text-sidebar-foreground/70 whitespace-nowrap">
195+
<p className="text-sm text-sidebar-foreground/70 whitespace-nowrap">
196196
{user?.role === 'admin' ? '管理员' : '用户'}
197197
</p>
198198
</div>
@@ -208,39 +208,39 @@ export function Layout() {
208208
)}
209209
>
210210
<Button
211-
variant="outline"
211+
variant="ghost"
212212
onClick={() => logout()}
213213
className={cn(
214-
"text-sidebar-foreground hover:bg-muted hover:text-foreground border-0 shadow-none min-w-0 overflow-hidden flex",
214+
"h-10 text-sidebar-foreground text-base hover:bg-muted min-w-0 overflow-hidden flex",
215215
sidebarCollapsed
216216
? "w-10 h-10 p-0 justify-center"
217217
: "flex-1 justify-start px-3"
218218
)}
219219
title={sidebarCollapsed ? "退出登录" : undefined}
220220
>
221-
<LogOut className="h-4 w-4 shrink-0" />
221+
<LogOut className="size-5 shrink-0" />
222222
{!sidebarCollapsed && (
223223
<span className="ml-2 whitespace-nowrap">
224224
退出登录
225225
</span>
226226
)}
227227
</Button>
228228
<Button
229-
variant="outline"
229+
variant="ghost"
230230
size="icon"
231231
onClick={toggleTheme}
232232
className={cn(
233-
"h-9 shrink-0 hover:bg-muted hover:text-foreground border-0 shadow-none text-sidebar-foreground",
233+
"size-10 shrink-0 hover:bg-muted shadow-none text-sidebar-foreground",
234234
sidebarCollapsed
235235
? "w-10"
236236
: ""
237237
)}
238238
title={sidebarCollapsed ? (theme === 'dark' ? '切换亮色' : '切换暗黑') : undefined}
239239
>
240240
{theme === 'dark' ? (
241-
<Sun className="h-4 w-4" />
241+
<Sun className="size-5" />
242242
) : (
243-
<Moon className="h-4 w-4" />
243+
<Moon className="size-5" />
244244
)}
245245
</Button>
246246
</div>
@@ -329,20 +329,20 @@ export function Layout() {
329329
{user?.username?.charAt(0).toUpperCase() || 'U'}
330330
</div>
331331
<div className="flex-1 min-w-0">
332-
<p className="text-sm font-medium truncate text-sidebar-foreground">
332+
<p className="text-base font-medium truncate text-sidebar-foreground">
333333
{user?.full_name || user?.username}
334334
</p>
335-
<p className="text-xs text-sidebar-foreground/70">
335+
<p className="text-sm text-sidebar-foreground/70">
336336
{user?.role === 'admin' ? '管理员' : '用户'}
337337
</p>
338338
</div>
339339
</div>
340340
<Button
341341
variant="ghost"
342-
className="w-full justify-start text-sidebar-foreground hover:bg-sidebar-foreground/10"
342+
className="w-full text-base h-10 justify-start text-sidebar-foreground hover:bg-muted"
343343
onClick={() => logout()}
344344
>
345-
<LogOut className="mr-2 h-4 w-4" />
345+
<LogOut className="mr-2 size-5" />
346346
退出登录
347347
</Button>
348348
</div>

0 commit comments

Comments
 (0)