24 KiB
24 KiB
固定资产管理系统 - 前端视觉重构台账
重构日期: 2026-03-17
重构范围: 全站前端视觉统一
版本: v2.0
一、重构概述
本次重构将项目前端视觉全面统一,建立了严格的视觉规范体系,确保所有页面风格一致、排版协调。
核心目标
- 统一页面结构 - 所有页面遵循相同的布局层次
- 统一组件样式 - 按钮、输入框、卡片等组件完全一致
- 统一间距系统 - 严格执行 4px 基准的间距规范
- 统一响应式策略 - 移动端/桌面端切换时机一致
二、关键文件清单
核心样式系统(1个)
| 文件路径 | 说明 | 变更类型 |
|---|---|---|
frontend/src/style.css |
全局样式系统 | 全面重写 |
布局框架(1个)
| 文件路径 | 说明 | 变更类型 |
|---|---|---|
frontend/src/layouts/MainLayout.vue |
侧边栏+顶部导航布局 | 结构调整 |
页面组件(18个)
| 模块 | 文件路径 | 说明 | 变更类型 |
|---|---|---|---|
| 登录 | frontend/src/views/Login.vue |
登录页 | 样式统一 |
| 首页 | frontend/src/views/dashboard/Dashboard.vue |
仪表盘 | 结构重构 |
| 资产列表 | frontend/src/views/equipment/EquipmentList.vue |
资产管理主页面 | 结构重构 |
| 资产表单 | frontend/src/views/equipment/EquipmentForm.vue |
新增/编辑资产 | 结构重构 |
| 借用列表 | frontend/src/views/borrow/BorrowList.vue |
借用记录 | 结构重构 |
| 扫码借出 | frontend/src/views/borrow/BorrowScan.vue |
扫码出库页面 | 样式统一 |
| 扫码归还 | frontend/src/views/borrow/ReturnScan.vue |
扫码入库页面 | 样式统一 |
| 统计分析 | frontend/src/views/statistics/Statistics.vue |
数据统计 | 结构重构 |
| 站内消息 | frontend/src/views/notifications/NotificationCenter.vue |
消息中心 | 结构重构 |
| 设置主框架 | frontend/src/views/settings/Settings.vue |
系统设置框架 | 结构重构 |
| 站点设置 | frontend/src/views/settings/components/SiteSettings.vue |
站点配置 | 样式统一 |
| 用户管理 | frontend/src/views/settings/components/UserManagement.vue |
用户管理 | 结构重构 |
| 人员管理 | frontend/src/views/settings/components/PersonManagement.vue |
人员管理 | 结构重构 |
| 部门管理 | frontend/src/views/settings/components/DepartmentManagement.vue |
部门管理 | 结构重构 |
| 资产类型 | frontend/src/views/settings/components/AssetTypeManagement.vue |
类型管理 | 样式统一 |
| 地址管理 | frontend/src/views/settings/components/StorageLocationManagement.vue |
地址管理 | 样式统一 |
| 维修管理 | frontend/src/views/settings/components/MaintenanceManagement.vue |
维修管理 | 结构重构 |
| 报废管理 | frontend/src/views/settings/components/DisposalManagement.vue |
报废管理 | 结构重构 |
| 操作日志 | frontend/src/views/settings/components/OperationLogList.vue |
日志查询 | 结构重构 |
| 组织同步 | frontend/src/views/settings/components/HrSyncManagement.vue |
HR同步 | 样式统一 |
总计: 20 个文件
三、视觉规范体系
3.1 颜色系统
/* 背景色 */
--bg-primary: #0d0d0d /* 页面主背景 - 纯黑 */
--bg-secondary: #141414 /* 卡片背景 - 深灰 */
--bg-tertiary: #1a1a1a /* 表头背景 */
--bg-elevated: #242424 /* 输入框背景 */
--bg-hover: #2a2a2a /* 悬停状态 */
/* 文字色 */
--text-primary: #ffffff /* 主文字 - 纯白 */
--text-secondary: #a1a1a1 /* 次要文字 - 灰白 */
--text-tertiary: #6e6e6e /* 辅助文字 - 深灰 */
/* 边框 */
--border-color: #2a2a2a /* 默认边框 */
--border-hover: #3a3a3a /* 悬停边框 */
/* 强调色 */
--accent-primary: #10a37f /* 主按钮、链接 - 青绿 */
--accent-primary-hover: #0d8c6d /* 按钮悬停 */
/* 状态色 */
--status-success: #10a37f /* 成功、可用 */
--status-warning: #f59e0b /* 警告、借出 */
--status-error: #ef4444 /* 错误、删除 */
--status-neutral: #6b7280 /* 中性、禁用 */
3.2 间距系统(严格执行)
| 变量 | 值 | 使用场景 |
|---|---|---|
--space-1 |
4px | 微调间距 |
--space-2 |
8px | 小间距 |
--space-3 |
12px | 按钮组间距、列表项间距 |
--space-4 |
16px | 卡片内间距、表单字段间距 |
--space-5 |
20px | 卡片 padding |
--space-6 |
24px | 页面级间距 |
--space-8 |
32px | 大区块间距 |
强制规范:
- 页面级间距统一使用
space-y-6(24px) - 卡片内元素间距统一使用
gap-4(16px) - 表单字段间距使用
field-stack(6px)
3.3 圆角系统
| 变量 | 值 | 使用场景 |
|---|---|---|
--radius-sm |
6px | 小按钮 |
--radius-md |
8px | 按钮、输入框 |
--radius-lg |
12px | 卡片、面板 |
--radius-xl |
16px | 弹窗 |
--radius-full |
9999px | 标签、圆形按钮 |
3.4 字体规范
| 级别 | 类名 | 大小 | 用途 |
|---|---|---|---|
| 页面标题 | .page-title |
24px | 页面主标题 |
| 区块标题 | .section-title |
16px | 卡片/列表标题 |
| 正文 | .input 等 |
14px | 普通文字 |
| 辅助文字 | .mobile-card__label |
11px | 标签、时间戳 |
四、页面结构规范
4.1 标准列表页结构
<template>
<div class="space-y-6">
<!-- 1. 页面头部 -->
<section class="page-header">
<div>
<p class="page-kicker">英文标签</p>
<h2 class="page-title">页面标题</h2>
<div class="mt-5 flex flex-wrap gap-3">
<!-- 主要操作按钮 -->
<button class="btn-primary text-sm">主要操作</button>
</div>
</div>
<div class="page-meta-grid">
<!-- 3个统计卡片 -->
<div class="page-meta">...</div>
<div class="page-meta">...</div>
<div class="page-meta">...</div>
</div>
</section>
<!-- 2. 筛选区域 -->
<section class="card">
<div class="filter-bar">
<div class="filter-bar__inputs">
<!-- 筛选输入框 -->
<div class="field-stack">
<label class="field-label">标签</label>
<input class="input" />
</div>
<select class="select">...</select>
</div>
<div class="filter-bar__actions">
<!-- 筛选按钮 -->
<button class="btn-secondary text-sm">重置</button>
<button class="btn-primary text-sm">查询</button>
</div>
</div>
</section>
<!-- 3. 数据列表 -->
<section class="card">
<div class="list-header">
<h3 class="section-title">列表标题</h3>
<span class="badge badge-neutral">共 XX 条</span>
</div>
<!-- 移动端:卡片列表 -->
<div class="mobile-card-list md:hidden">
<article class="mobile-card">
<div class="mobile-card__row">...</div>
<div class="mobile-card__meta">...</div>
</article>
</div>
<!-- 桌面端:表格 -->
<div class="hidden md:block">
<div class="table-container">
<table class="data-table min-w-[900px]">
...
</table>
</div>
</div>
<!-- 分页 -->
<div class="pagination-bar">
<p class="text-sm text-text-secondary">共 XX 条记录</p>
<div class="flex items-center gap-2">
<button class="btn-secondary text-sm">上一页</button>
<span class="text-sm text-text-primary">1 / 10</span>
<button class="btn-secondary text-sm">下一页</button>
</div>
</div>
</section>
</div>
</template>
4.2 标准表单页结构
<template>
<div class="space-y-6 pb-24 md:pb-0">
<!-- 页面头部 -->
<section class="page-header">
<div>
<p class="page-kicker">Field Entry</p>
<h2 class="page-title">表单标题</h2>
</div>
<div class="flex gap-3">
<button class="btn-secondary text-sm">次要操作</button>
</div>
</section>
<!-- 表单卡片 -->
<section class="card">
<h3 class="section-title mb-5">区块标题</h3>
<form @submit.prevent="handleSubmit" class="space-y-5">
<div class="field-grid">
<div class="field-stack">
<label class="field-label">字段名 *</label>
<input class="input" required />
</div>
<div class="field-stack lg:col-span-2">
<label class="field-label">长字段</label>
<textarea class="input" rows="3"></textarea>
</div>
</div>
<!-- 底部操作栏 -->
<div class="mobile-sticky-actions md:static">
<div class="flex flex-col gap-2 md:flex-row md:justify-end">
<button type="submit" class="btn-primary w-full md:w-auto">保存</button>
<button type="button" class="btn-secondary w-full md:w-auto">取消</button>
</div>
</div>
</form>
</section>
</div>
</template>
4.3 标准设置页结构
<template>
<div class="space-y-6">
<!-- 页面头部 -->
<section class="page-header">
<div>
<p class="page-kicker">英文标签</p>
<h2 class="page-title">设置标题</h2>
</div>
<div class="page-meta-grid">...</div>
</section>
<!-- 筛选/新增卡片 -->
<section class="card">
<div class="filter-bar">...</div>
</section>
<!-- 列表卡片 -->
<section class="card">
<div class="list-header">...</div>
<!-- 移动端卡片 / 桌面端表格 -->
<div class="pagination-bar">...</div>
</section>
<!-- 编辑弹窗 -->
<div v-if="editing" class="sheet-backdrop">
<div class="sheet-panel max-w-2xl">
<h3 class="text-xl font-semibold text-text-primary mb-4">编辑</h3>
<div class="space-y-4">
<div class="field-stack">...</div>
</div>
<div class="flex justify-end gap-3 mt-6">
<button class="btn-secondary" @click="close">取消</button>
<button class="btn-primary" @click="save">保存</button>
</div>
</div>
</div>
</div>
</template>
五、组件类名速查表
5.1 按钮
<!-- 主要按钮 -->
<button class="btn-primary">确认</button>
<!-- 次要按钮 -->
<button class="btn-secondary">取消</button>
<!-- 危险按钮 -->
<button class="btn-danger">删除</button>
<!-- 图标按钮 -->
<button class="btn-icon"><Icon /></button>
<!-- 小尺寸按钮 -->
<button class="btn-primary text-sm">小按钮</button>
5.2 表单
<!-- 字段组 -->
<div class="field-stack">
<label class="field-label">字段名</label>
<input class="input" />
</div>
<!-- 输入框 -->
<input class="input" type="text" placeholder="提示文字" />
<!-- 选择框 -->
<select class="select">
<option>选项</option>
</select>
<!-- 多行输入 -->
<textarea class="input" rows="3"></textarea>
<!-- 表单网格(2列) -->
<div class="field-grid">
<div class="field-stack">...</div>
<div class="field-stack">...</div>
</div>
<!-- 表单网格(跨2列) -->
<div class="field-stack lg:col-span-2">
<label class="field-label">长字段</label>
<textarea class="input" rows="3"></textarea>
</div>
5.3 卡片与面板
<!-- 主卡片 -->
<section class="card">...</section>
<!-- 内层面板 -->
<div class="panel">...</div>
5.4 标签
<span class="badge badge-success">成功</span>
<span class="badge badge-warning">警告</span>
<span class="badge badge-error">错误</span>
<span class="badge badge-neutral">中性</span>
5.5 表格
<div class="table-container">
<table class="data-table min-w-[900px]">
<thead>
<tr>
<th>列标题</th>
</tr>
</thead>
<tbody>
<tr>
<td>数据</td>
</tr>
</tbody>
</table>
</div>
5.6 移动端卡片列表
<div class="mobile-card-list md:hidden">
<article class="mobile-card">
<div class="mobile-card__row">
<p class="text-sm font-semibold text-text-primary">标题</p>
<span class="badge badge-success">状态</span>
</div>
<div class="mobile-card__meta">
<div>
<p class="mobile-card__label">标签</p>
<p class="mobile-card__value">值</p>
</div>
</div>
</article>
</div>
5.7 弹窗
<div class="sheet-backdrop">
<div class="sheet-panel max-w-2xl">
<h3 class="text-xl font-semibold text-text-primary mb-4">标题</h3>
<div class="space-y-4">...</div>
<div class="flex justify-end gap-3 mt-6">
<button class="btn-secondary">取消</button>
<button class="btn-primary">确认</button>
</div>
</div>
</div>
5.8 空状态
<p class="empty-state">暂无数据</p>
六、响应式断点规范
6.1 断点定义
| 断点 | 范围 | 类名前缀 |
|---|---|---|
| sm | >= 640px | sm: |
| md | >= 768px | md: |
| lg | >= 1024px | lg: |
| xl | >= 1280px | xl: |
6.2 列表切换策略
统一使用 md 断点:
<!-- 移动端显示,桌面端隐藏 -->
<div class="mobile-card-list md:hidden">...</div>
<!-- 移动端隐藏,桌面端显示 -->
<div class="hidden md:block">...</div>
6.3 网格响应式
<!-- 1列 -> 2列 -->
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">...</div>
<!-- 1列 -> 2列 -> 3列 -->
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">...</div>
<!-- 1列 -> 2列 -> 4列 -->
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">...</div>
七、新增/修改的 CSS 类名
7.1 页面结构
.page-header /* 页面头部容器 */
.page-kicker /* 英文标签 */
.page-title /* 页面标题 */
.page-meta-grid /* 统计卡片网格 */
.page-meta /* 统计卡片 */
.page-meta__label /* 统计标签 */
.page-meta__value /* 统计数值 */
.page-meta__subvalue /* 统计副标题 */
.list-header /* 列表头部 */
.section-title /* 区块标题 */
7.2 筛选区域
.filter-bar /* 筛选栏容器 */
.filter-bar__inputs /* 输入区 */
.filter-bar__actions /* 按钮区 */
7.3 表单系统
.field-grid /* 表单网格(响应式2列) */
.field-grid--3 /* 表单网格(响应式3列) */
.field-stack /* 字段组(标签+输入) */
.field-label /* 字段标签 */
7.4 表格系统
.table-container /* 表格容器(带边框和圆角) */
.data-table /* 数据表格 */
7.5 移动端卡片
.mobile-card-list /* 卡片列表容器 */
.mobile-card /* 单个卡片 */
.mobile-card__row /* 卡片行(标题+状态) */
.mobile-card__meta /* 卡片元信息网格 */
.mobile-card__label /* 标签 */
.mobile-card__value /* 值 */
7.6 其他
.empty-state /* 空状态 */
.pagination-bar /* 分页栏 */
.mobile-sticky-actions /* 移动端底部固定操作栏 */
.sheet-backdrop /* 弹窗遮罩 */
.sheet-panel /* 弹窗面板 */
八、开发注意事项
8.1 必须遵守的规范
- 页面间距: 所有页面根容器必须使用
space-y-6 - 卡片内边距: 所有
card内部使用p-5(已由 card 类自带) - 表单标签: 必须使用
field-label,禁止自定义样式 - 按钮顺序: 主要操作在左,次要操作在右(弹窗内相反)
- 列表头部: 必须包含
list-header+section-title
8.2 禁止使用的类名
已废弃的类名(虽然 style.css 保留了兼容,但新代码不应使用):
btn-apple-*系列input-applecard-appletext-apple-*text-system-label-*bg-system-gray-*border-system-gray-*surface-notepage-subtitlesection-subtitle
8.3 推荐的间距
- 页面级:
space-y-6(24px) - 卡片内:
gap-4(16px) - 按钮组:
gap-3(12px) - 列表项:
mobile-card-list自带 12px gap
禁止使用的间距:
gap-5(20px) - 非标准间距mt-5/mb-5- 使用mt-4(16px) 或mt-6(24px)
8.4 断点使用
- 列表切换统一使用
md断点 - 网格响应式使用
sm:和lg: - 不要混用
md和lg进行列表切换
九、示例页面参考
最标准的列表页
frontend/src/views/equipment/EquipmentList.vue
最标准的表单页
frontend/src/views/equipment/EquipmentForm.vue
最标准的设置页
frontend/src/views/settings/components/UserManagement.vue
十、构建验证
cd frontend
npm run build
预期结果:
- ✓ vue-tsc -b 无错误
- ✓ vite build 成功
- ✓ 所有 chunk 生成完成
附录:颜色使用速查
| 用途 | 类名 |
|---|---|
| 主文字 | text-text-primary |
| 次要文字 | text-text-secondary |
| 辅助文字 | text-text-tertiary |
| 强调色 | text-accent |
| 成功状态 | text-status-success |
| 警告状态 | text-status-warning |
| 错误状态 | text-status-error |
| 页面背景 | bg-bg-primary |
| 卡片背景 | bg-bg-secondary |
| 输入框背景 | bg-bg-elevated |
十一、移动端优化(新增)
优化日期: 2026-03-17
优化范围: 全站移动端体验增强
11.1 优化内容
样式系统增强 (style.css)
新增移动端全面优化样式(在文件末尾添加):
/* 移动端按钮尺寸优化 - 修复按钮过大问题 */
@media (max-width: 767px) {
.btn-primary, .btn-secondary, .btn-danger {
min-height: 40px;
padding: 0.5rem 0.875rem;
font-size: 13px;
}
}
/* 移动端徽章防止压缩 - 修复胶囊变圆问题 */
@media (max-width: 767px) {
.badge {
flex-shrink: 0;
white-space: nowrap;
padding: 0.25rem 0.5rem;
font-size: 10px;
}
}
/* 移动端卡片紧凑模式 - 修复卡片过大问题 */
@media (max-width: 767px) {
.card { padding: var(--space-3); border-radius: var(--radius-md); }
.panel { padding: var(--space-3); }
.mobile-card { padding: var(--space-3); }
}
/* 移动端页面头部优化 */
@media (max-width: 767px) {
.page-header { padding: var(--space-3); gap: var(--space-3); }
.page-title { font-size: 20px; }
.page-kicker { font-size: 10px; }
.page-meta { padding: var(--space-3); }
.page-meta__value { font-size: 16px; }
}
/* iOS 防缩放 */
@media (max-width: 767px) {
.input, .select, textarea.input {
font-size: 16px;
min-height: 48px;
}
}
/* 安全区域适配 */
@supports (padding: max(0px)) {
.mobile-sticky-actions {
padding-bottom: max(var(--space-4), env(safe-area-inset-bottom));
}
}
页面移动端适配
| 页面 | 优化内容 |
|---|---|
Dashboard.vue |
最近借用记录添加 mobile-card-list;统计卡片使用 grid-cols-2 并缩小字体 |
Statistics.vue |
Top 10 高价值资产添加 mobile-card-list 移动端卡片列表 |
EquipmentList.vue |
移动端卡片按钮使用 text-xs 并简化文字 |
NotificationCenter.vue |
按钮使用 text-xs sm:text-sm,"全部标记已读"简化为"全标已读" |
PersonManagement.vue |
按钮添加 text-xs sm:text-sm,文字简化 |
UserManagement.vue |
按钮添加 text-xs sm:text-sm |
AssetTypeManagement.vue |
按钮添加 text-xs sm:text-sm |
StorageLocationManagement.vue |
按钮添加 text-xs sm:text-sm |
DepartmentManagement.vue |
按钮添加 text-xs sm:text-sm,文字简化 |
MaintenanceManagement.vue |
按钮添加 text-xs sm:text-sm,"完成维修/取消维修"简化为"完成/取消" |
DisposalManagement.vue |
按钮添加 text-xs sm:text-sm,"通过审批/驳回申请"简化为"通过/驳回" |
OperationLogList.vue |
按钮添加 text-xs sm:text-sm |
HrSyncManagement.vue |
按钮添加 text-xs sm:text-sm,"刷新预览/立即同步"简化为"刷新/同步" |
SiteSettings.vue |
按钮添加 text-xs sm:text-sm |
移动端列表结构模板
<!-- 移动端卡片列表 (md:hidden) -->
<div class="mobile-card-list md:hidden">
<article v-for="item in list" :key="item.id" class="mobile-card">
<div class="mobile-card__row">
<p class="text-sm font-semibold text-text-primary">{{ item.name }}</p>
<span class="badge badge-success">状态</span>
</div>
<div class="mobile-card__meta mt-3">
<div>
<p class="mobile-card__label">标签</p>
<p class="mobile-card__value">{{ item.value }}</p>
</div>
</div>
</article>
<div v-if="list.length === 0" class="empty-state">暂无数据</div>
</div>
<!-- 桌面端表格 (hidden md:block) -->
<div class="hidden md:block">
<div class="table-container">
<table class="data-table">...</table>
</div>
</div>
11.2 移动端组件清单
| 组件类名 | 用途 | 移动端特性 |
|---|---|---|
.mobile-card-list |
卡片列表容器 | 垂直布局,12px 间距 |
.mobile-card |
单个卡片 | 触摸反馈、点击缩放效果 |
.mobile-card__row |
卡片标题行 | 标题+状态 横向排列 |
.mobile-card__meta |
卡片元信息 | 2列网格布局 |
.mobile-sticky-actions |
底部固定操作栏 | 移动端 fixed,桌面端 static |
.touch-option-list |
触摸选项列表 | 大按钮,易于触摸 |
.touch-option |
触摸选项 | 点击反馈效果 |
11.3 响应式断点策略
统一使用 md (768px) 作为列表切换断点:
<!-- 移动端显示,桌面端隐藏 -->
<div class="mobile-card-list md:hidden">...</div>
<!-- 移动端隐藏,桌面端显示 -->
<div class="hidden md:block">...</div>
11.4 移动端按钮规范
尺寸规范:
/* 移动端默认按钮 */
min-height: 40px;
padding: 0.5rem 0.875rem;
font-size: 13px;
/* 移动端小按钮 */
class="text-xs" /* 12px */
文字简化原则:
| 桌面端文字 | 移动端文字 |
|---|---|
| 全部标记已读 | 全标已读 |
| 刷新预览 | 刷新 |
| 立即同步 | 同步 |
| 通过审批 | 通过 |
| 驳回申请 | 驳回 |
| 完成维修 | 完成 |
| 取消维修 | 取消 |
| 完成处置 | 完成 |
| 新增使用者 | 新增 |
| 下载导入模板 | 下载模板 |
| 查看配件 N | 配件(N) |
| 收起配件 | 收起 |
| 打印标签 | 标签 |
Vue 模板示例:
<button class="btn-primary text-xs sm:text-sm">保存</button>
<button class="btn-secondary text-xs sm:text-sm">取消</button>
11.5 移动端表单优化
- 输入框字体大小: 统一使用
16px,防止 iOS 自动缩放 - 触摸目标: 按钮最小高度
40px(移动端) - 底部固定操作栏: 长表单使用
mobile-sticky-actions
<template>
<div class="space-y-6 pb-24 md:pb-0">
<!-- 表单内容 -->
<!-- 底部操作栏 -->
<div class="mobile-sticky-actions md:static">
<button type="submit" class="btn-primary w-full">保存</button>
</div>
</div>
</template>
11.6 移动端徽章(Badge)规范
防止压缩成圆:
@media (max-width: 767px) {
.badge {
flex-shrink: 0; /* 防止被压缩 */
white-space: nowrap; /* 防止文字换行 */
padding: 0.25rem 0.5rem;
font-size: 10px;
}
}
使用建议:
- 徽章文字尽量简短(2-4个字符)
- 使用
flex-shrink-0防止在 flex 容器中被压缩 - 使用
white-space: nowrap防止文字换行导致高度变化
11.7 移动端手势支持
/* 滑动容器 */
.swipe-container {
overflow-x: auto;
scroll-snap-type: x mandatory;
-webkit-overflow-scrolling: touch;
scrollbar-width: none;
}
.swipe-item {
scroll-snap-align: start;
flex-shrink: 0;
}
文档版本: v2.0
最后更新: 2026-03-17
维护者: Claude