Browse Source

样式细化与统一

master
hejl 6 days ago
parent
commit
94be8ab0c1
  1. 1479
      gofaster/app/dist/renderer/js/index.js
  2. 221
      gofaster/app/src/renderer/assets/README-COMMON-STYLES.md
  3. 576
      gofaster/app/src/renderer/assets/common-styles.css
  4. 359
      gofaster/app/src/renderer/modules/role-management/views/RoleManagement.vue
  5. 127
      gofaster/app/src/renderer/modules/system-settings/views/Settings.vue
  6. 348
      gofaster/app/src/renderer/modules/user-management/views/UserManagement.vue
  7. 392
      gofaster/app/src/renderer/modules/user-management/views/UserProfile.vue

1479
gofaster/app/dist/renderer/js/index.js vendored

File diff suppressed because it is too large Load Diff

221
gofaster/app/src/renderer/assets/README-COMMON-STYLES.md

@ -0,0 +1,221 @@ @@ -0,0 +1,221 @@
# 公共样式使用指南
## 概述
`common-styles.css` 文件包含了系统中所有管理页面的通用样式,旨在提供一致的用户界面体验。
## 包含的样式
### 1. 管理页面基础样式
- `.management-page` - 管理页面的基础容器样式
- 统一的页面内边距和布局
### 2. 搜索栏和输入控件样式
- `.search-bar` - 搜索栏容器
- `.search-input` - 搜索输入框
- `.filters` - 筛选器容器
- `.filters select` - 筛选器下拉选择框
- `.setting-item input[type="text"]` - 文本输入框
- `.setting-item input[type="number"]` - 数字输入框
- `.setting-item select` - 下拉选择框
- 统一的输入控件样式和焦点效果
- 响应式设计支持
### 3. 表格样式
- `.data-table` - 数据表格容器
- `table`, `th`, `td` - 表格基础样式
- 统一的字体大小和间距
### 4. 状态徽章
- `.status-badge` - 状态徽章基础样式
- `.status-badge.active` - 激活状态
- `.status-badge.inactive` - 非激活状态
### 5. 角色标签
- `.role-tags` - 角色标签容器
- `.role-tag` - 单个角色标签
### 6. 按钮样式
- `.btn` - 基础按钮样式
- `.btn-primary`, `.btn-info`, `.btn-danger` - 不同颜色变体
- `.btn-sm` - 小尺寸按钮
- 表格操作按钮的特殊样式
### 7. 分页样式
- `.pagination` - 分页容器
- `.page-info` - 页码信息
### 8. 页面头部和卡片样式(统一)
- `.page-header`, `.profile-header` - 页面头部统一样式
- `.page-header h2`, `.profile-header h1` - 页面标题统一样式(支持图标)
- `.card-header`, `.settings-section h3` - 卡片头部统一样式(支持图标)
- `.profile-card`, `.settings-section` - 卡片容器统一样式
- `.info-item`, `.setting-item` - 字段项统一样式
- `.info-item label`, `.setting-item label` - 字段标签统一样式
- `.profile-actions`, `.settings-actions` - 操作按钮区域统一样式
### 9. 模态框样式
- `.modal-overlay` - 模态框遮罩
- `.modal` - 模态框容器
- `.modal-header`, `.modal-body` - 模态框内容区域
- `.form-group` - 表单组样式
- `.form-group input`, `.form-group select`, `.form-group textarea` - 模态框输入控件(使用统一样式)
### 10. 响应式设计
- 移动端适配样式
- 不同屏幕尺寸的布局调整
## 使用方法
### 1. 在Vue组件中引入
```vue
<style scoped>
@import '../../../assets/common-styles.css';
/* 页面特定样式 */
.your-specific-styles {
/* 你的特定样式 */
}
</style>
```
### 2. 在HTML模板中使用
```vue
<template>
<!-- 管理页面容器 -->
<div class="your-page management-page">
<!-- 页面头部 -->
<div class="page-header">
<h2><i class="fas fa-cog"></i> 页面标题</h2>
<p class="profile-subtitle">页面描述</p>
</div>
<!-- 搜索栏 -->
<div class="search-bar">
<div class="search-input">
<i class="fas fa-search"></i>
<input type="text" placeholder="搜索..." />
</div>
<div class="filters">
<select>
<option>筛选选项</option>
</select>
<button class="btn btn-primary">操作按钮</button>
</div>
</div>
<!-- 数据表格 -->
<div class="data-table">
<table>
<thead>
<tr>
<th>列标题</th>
</tr>
</thead>
<tbody>
<tr>
<td>数据内容</td>
</tr>
</tbody>
</table>
</div>
<!-- 分页 -->
<div class="pagination">
<button class="btn btn-sm">上一页</button>
<span class="page-info">第 1 页,共 10 页</span>
<button class="btn btn-sm">下一页</button>
</div>
<!-- 信息卡片 -->
<div class="settings-content">
<div class="settings-section">
<h3><i class="fas fa-user-cog"></i> 分组标题</h3>
<div class="setting-item">
<label>文本输入</label>
<input type="text" placeholder="请输入文本" />
</div>
<div class="setting-item">
<label>数字输入</label>
<input type="number" placeholder="请输入数字" />
</div>
<div class="setting-item">
<label>下拉选择</label>
<select>
<option>选项1</option>
<option>选项2</option>
</select>
</div>
</div>
</div>
<!-- 操作按钮 -->
<div class="settings-actions">
<button class="btn btn-secondary">取消</button>
<button class="btn btn-primary">保存</button>
</div>
</div>
</template>
```
## 样式类名说明
### 容器类
- `management-page` - 管理页面主容器
- `data-table` - 数据表格容器
- `settings-content` - 内容区域容器
### 布局类
- `search-bar` - 搜索栏布局
- `info-grid` - 信息网格布局
- `roles-list` - 角色列表布局
- `page-header` - 页面头部布局
- `settings-section` - 设置分组布局
### 组件类
- `status-badge` - 状态徽章
- `role-tag` - 角色标签
- `btn` - 按钮基础类
- `modal` - 模态框
- `input[type="text"]` - 文本输入框
- `input[type="number"]` - 数字输入框
- `select` - 下拉选择框
### 状态类
- `active` - 激活状态
- `inactive` - 非激活状态
- `primary` - 主要样式
- `danger` - 危险样式
## 自定义样式
如果需要自定义样式,建议:
1. 在公共样式基础上添加特定样式
2. 使用更具体的选择器来覆盖公共样式
3. 保持与公共样式的一致性
```vue
<style scoped>
@import '../../../assets/common-styles.css';
/* 自定义样式 */
.your-page .btn-primary {
background: #your-color;
}
.your-page .status-badge.active {
background: #your-active-color;
}
</style>
```
## 维护说明
- 修改公共样式时,请确保不影响现有页面的显示
- 新增样式时,请遵循现有的命名规范
- 定期检查所有使用公共样式的页面,确保样式一致性

576
gofaster/app/src/renderer/assets/common-styles.css

@ -0,0 +1,576 @@ @@ -0,0 +1,576 @@
/* ===== 通用管理页面样式 ===== */
/* 页面容器 */
.management-page {
padding: 20px;
padding-top: 10px;
}
/* 搜索栏样式 */
.search-bar {
display: flex;
gap: 20px;
margin-bottom: 6px;
margin-top: 0;
align-items: center;
flex-wrap: wrap;
justify-content: space-between;
}
.search-input {
position: relative;
flex: 0 0 280px;
min-width: 200px;
max-width: 350px;
}
.search-input i {
position: absolute;
left: 12px;
top: 50%;
transform: translateY(-50%);
color: var(--text-muted);
font-size: 12px;
}
/* 输入控件统一样式 */
.search-input input,
.setting-item input[type="text"],
.setting-item input[type="number"],
.setting-item select {
width: 100%;
padding: 8px 12px;
border: 1px solid var(--input-border);
border-radius: 6px;
font-size: 12px;
background-color: var(--input-bg);
color: var(--input-text);
box-sizing: border-box;
}
/* 搜索输入框特殊样式(左侧图标) */
.search-input input {
padding-left: 35px;
}
/* 设置项输入框特殊样式(最小宽度) */
.setting-item input[type="text"],
.setting-item input[type="number"],
.setting-item select {
min-width: 200px;
}
/* 输入控件焦点样式 */
.search-input input:focus,
.setting-item input[type="text"]:focus,
.setting-item input[type="number"]:focus,
.setting-item select:focus {
outline: none;
border-color: var(--accent-color);
box-shadow: 0 0 0 2px rgba(74, 158, 255, 0.2);
}
.filters {
display: flex;
gap: 15px;
flex-wrap: wrap;
flex: 1;
justify-content: flex-end;
align-items: center;
min-width: 0;
}
.filters select {
padding: 8px 12px;
border: 1px solid var(--input-border);
border-radius: 6px;
font-size: 12px;
background-color: var(--input-bg);
color: var(--input-text);
min-width: 100px;
max-width: 150px;
flex: 0 0 auto;
box-sizing: border-box;
}
.filters select:focus {
outline: none;
border-color: var(--accent-color);
box-shadow: 0 0 0 2px rgba(74, 158, 255, 0.2);
}
/* 表格样式 */
.data-table {
background: var(--card-bg);
border-radius: 8px;
box-shadow: 0 2px 8px var(--shadow-color);
overflow: hidden;
margin-bottom: 20px;
}
table {
width: 100%;
border-collapse: collapse;
}
th, td {
padding: 8px;
text-align: left;
border-bottom: 1px solid var(--border-color);
font-size: 12px;
}
th {
background: var(--bg-secondary);
font-weight: normal;
color: var(--text-primary);
font-size: 14px;
}
/* 状态徽章 */
.status-badge {
padding: 4px 8px;
border-radius: 12px;
font-size: 12px;
font-weight: normal;
}
.status-badge.active {
background: #e8f5e8;
color: #2e7d32;
}
.status-badge.inactive {
background: #ffebee;
color: #c62828;
}
/* 角色标签 */
.role-tags {
display: flex;
gap: 4px;
flex-wrap: wrap;
}
.role-tag {
background: #e3f2fd;
color: #1976d2;
padding: 2px 6px;
border-radius: 4px;
font-size: 14px;
}
/* 操作按钮 */
.actions {
display: flex;
gap: 8px;
}
.btn {
padding: 8px 16px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 12px;
display: inline-flex;
align-items: center;
gap: 6px;
transition: all 0.2s;
}
.btn-primary {
background: #1976d2;
color: white;
}
.btn-primary:hover {
background: #1565c0;
}
.btn-info {
background: #0288d1;
color: white;
}
.btn-danger {
background: #d32f2f;
color: white;
}
.btn-sm {
padding: 6px 12px;
font-size: 10px;
}
/* 表格操作按钮样式优化 */
.actions .btn-sm {
background: none;
border: none;
padding: 6px 10px;
margin: 0 -2px;
color: var(--text-primary);
transition: all 0.2s;
}
.actions .btn-sm i {
font-size: 14px;
}
.actions .btn-sm:hover {
background: var(--bg-secondary);
color: var(--accent-color);
transform: scale(1.1);
}
.actions .btn-sm.btn-info:hover {
color: #2196f3;
}
.actions .btn-sm.btn-primary:hover {
color: #1976d2;
}
.actions .btn-sm.btn-danger:hover {
color: #d32f2f;
}
/* 分页样式 */
.pagination {
display: flex;
justify-content: center;
align-items: center;
gap: 20px;
}
.page-info {
color: #666;
font-size: 14px;
}
/* 分页按钮字体大小统一 */
.pagination .btn-sm {
font-size: 10px;
}
/* ===== 个人资料页面样式 ===== */
/* 个人资料容器 */
.user-profile {
padding: 20px;
}
/* 页面头部 - 统一样式 */
.page-header,
.profile-header {
text-align: center;
margin-bottom: 26px;
}
.page-header h2,
.profile-header h1 {
font-size: 16px;
color: var(--text-primary);
margin-bottom: 10px;
margin: 0;
}
.profile-subtitle {
font-size: 12px;
color: var(--text-secondary);
margin: 0;
}
/* 内容区域 */
.profile-content {
max-width: 800px;
margin: 0 auto;
}
/* 卡片样式 - 统一样式 */
.profile-card,
.settings-section {
background: var(--card-bg);
border-radius: 8px;
padding: 20px;
margin-bottom: 20px;
box-shadow: 0 2px 8px var(--shadow-color);
}
/* 卡片头部 - 统一样式 */
.card-header,
.settings-section h3 {
margin: 0 0 16px 0;
color: var(--text-primary);
font-size: 14px;
border-bottom: 2px solid var(--border-color);
padding-bottom: 8px;
}
.card-header h2,
.settings-section h3 {
margin: 0;
font-size: 14px;
color: var(--text-primary);
}
/* 信息网格 */
.info-grid {
display: flex;
flex-direction: column;
gap: 0;
}
/* 字段项 - 统一样式 */
.info-item,
.setting-item {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 16px;
padding: 12px 0;
border-bottom: 1px solid #f5f5f5;
}
.info-item:last-child,
.setting-item:last-child {
border-bottom: none;
margin-bottom: 0;
}
/* 字段标签 - 统一样式 */
.info-item label,
.setting-item label {
font-weight: 500;
color: var(--text-primary);
min-width: 200px;
font-size: 12px;
}
.info-item span {
color: var(--text-primary);
font-size: 12px;
text-align: right;
flex: 1;
}
/* 角色列表 */
.roles-list {
display: flex;
flex-direction: column;
gap: 16px;
}
.role-item {
background: var(--card-bg);
border-radius: 8px;
padding: 16px;
border: 1px solid var(--border-color);
margin-bottom: 12px;
}
.role-header {
margin-bottom: 12px;
}
.role-name {
display: block;
font-size: 12px;
font-weight: 600;
color: var(--text-primary);
margin-bottom: 8px;
}
.role-description {
color: var(--text-secondary);
font-size: 12px;
}
.role-permissions h4 {
margin: 0 0 8px 0;
color: var(--text-primary);
font-size: 12px;
}
.permissions-grid {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.permission-tag {
background: var(--accent-color);
color: white;
padding: 4px 12px;
border-radius: 16px;
font-size: 12px;
border: none;
}
.no-roles {
text-align: center;
color: var(--text-secondary);
padding: 40px 20px;
font-size: 12px;
}
/* 操作按钮区域 - 统一样式 */
.profile-actions,
.settings-actions {
display: flex;
gap: 16px;
justify-content: flex-end;
margin-top: 26px;
}
/* ===== 模态框样式 ===== */
.modal-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0,0,0,0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
}
.modal {
background: white;
border-radius: 8px;
width: 90%;
max-width: 500px;
max-height: 90vh;
overflow-y: auto;
box-sizing: border-box;
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 20px;
border-bottom: 1px solid #eee;
}
.modal-header h3 {
margin: 0;
font-size: 14px;
font-weight: normal;
}
.close-btn {
background: none;
border: none;
font-size: 14px;
cursor: pointer;
color: #999;
}
.modal-body {
padding: 20px;
box-sizing: border-box;
}
.form-group {
margin-bottom: 20px;
}
.form-group label {
display: block;
margin-bottom: 8px;
font-weight: normal;
color: #333;
font-size: 14px;
}
.form-group input,
.form-group select,
.form-group textarea {
width: 100%;
padding: 8px 12px;
border: 1px solid var(--input-border);
border-radius: 6px;
font-size: 12px;
background-color: var(--input-bg);
color: var(--input-text);
box-sizing: border-box;
}
.form-group input:focus,
.form-group select:focus,
.form-group textarea:focus {
outline: none;
border-color: var(--accent-color);
box-shadow: 0 0 0 2px rgba(74, 158, 255, 0.2);
}
.form-actions {
display: flex;
gap: 12px;
justify-content: flex-end;
margin-top: 30px;
}
/* ===== 响应式设计 ===== */
@media (max-width: 768px) {
.management-page,
.user-profile {
padding: 15px;
}
.search-bar {
flex-direction: column;
align-items: stretch;
gap: 15px;
justify-content: flex-start;
}
.search-input {
flex: 1;
min-width: auto;
max-width: none;
}
.filters {
justify-content: space-between;
flex: none;
}
.filters select {
flex: 1;
min-width: auto;
max-width: none;
}
.profile-header h1 {
font-size: 16px;
}
.info-item {
flex-direction: column;
align-items: flex-start;
gap: 12px;
}
.info-item label {
min-width: auto;
}
.info-item span {
text-align: left;
}
.profile-actions {
flex-direction: column;
align-items: center;
}
.action-btn {
width: 100%;
max-width: 300px;
}
}

359
gofaster/app/src/renderer/modules/role-management/views/RoleManagement.vue

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
<template>
<div class="role-management">
<div class="role-management management-page">
<!-- 搜索和操作 -->
<div class="search-bar">
<div class="search-input">
@ -18,20 +18,20 @@ @@ -18,20 +18,20 @@
</div>
</div>
<!-- 角色列表 -->
<div class="role-table">
<!-- 角色列表 -->
<div class="role-table data-table">
<div v-if="loading" class="loading">
<i class="fas fa-spinner fa-spin"></i>
<span>加载中...</span>
</div>
<i class="fas fa-spinner fa-spin"></i>
<span>加载中...</span>
</div>
<div v-else-if="roles.length === 0" class="empty-state">
<p><i class="fas fa-inbox"></i> 暂无角色数据</p>
<button class="btn btn-primary" @click="createNewRole">
<i class="fas fa-plus"></i> 创建第一个角色
</button>
</div>
<p><i class="fas fa-inbox"></i> 暂无角色数据</p>
<button class="btn btn-primary" @click="createNewRole">
<i class="fas fa-plus"></i> 创建第一个角色
</button>
</div>
<table v-else>
<thead>
<tr>
@ -66,27 +66,27 @@ @@ -66,27 +66,27 @@
</tr>
</tbody>
</table>
</div>
<!-- 分页 -->
<div v-if="total > pageSize" class="pagination">
<button
:disabled="currentPage === 1"
@click="handleCurrentChange(currentPage - 1)"
class="btn btn-sm"
>
<i class="fas fa-chevron-left"></i> 上一页
</button>
<span class="page-info">
{{ currentPage }} {{ Math.ceil(total / pageSize) }}
</span>
<button
:disabled="currentPage >= Math.ceil(total / pageSize)"
@click="handleCurrentChange(currentPage + 1)"
class="btn btn-sm"
>
下一页 <i class="fas fa-chevron-right"></i>
</button>
</div>
<!-- 分页 -->
<div v-if="total > pageSize" class="pagination">
<button
:disabled="currentPage === 1"
@click="handleCurrentChange(currentPage - 1)"
class="btn btn-sm"
>
<i class="fas fa-chevron-left"></i> 上一页
</button>
<span class="page-info">
{{ currentPage }} {{ Math.ceil(total / pageSize) }}
</span>
<button
:disabled="currentPage >= Math.ceil(total / pageSize)"
@click="handleCurrentChange(currentPage + 1)"
class="btn btn-sm"
>
下一页 <i class="fas fa-chevron-right"></i>
</button>
</div>
<!-- 创建/编辑角色对话框 -->
@ -362,95 +362,9 @@ export default { @@ -362,95 +362,9 @@ export default {
</script>
<style scoped>
.role-management {
padding: 20px;
padding-top: 10px;
}
.search-bar {
display: flex;
gap: 20px;
margin-bottom: 6px;
margin-top: 0;
align-items: center;
flex-wrap: wrap;
justify-content: space-between;
}
.search-input {
position: relative;
flex: 0 0 280px;
min-width: 200px;
max-width: 350px;
}
/* 响应式设计 */
@media (max-width: 768px) {
.search-bar {
flex-direction: column;
align-items: stretch;
gap: 15px;
justify-content: flex-start;
}
.search-input {
flex: 1;
min-width: auto;
max-width: none;
}
.filters {
justify-content: space-between;
flex: none;
}
}
/* 中等屏幕优化 */
@media (max-width: 1024px) and (min-width: 769px) {
.search-input {
flex: 0 0 250px;
min-width: 200px;
max-width: 300px;
}
}
.search-input i {
position: absolute;
left: 12px;
top: 50%;
transform: translateY(-50%);
color: var(--text-muted);
font-size: 12px;
}
.search-input input {
width: 100%;
padding: 8px 10px 8px 35px;
border: 1px solid var(--input-border);
border-radius: 6px;
font-size: 12px;
background-color: var(--input-bg);
color: var(--input-text);
}
.filters {
display: flex;
gap: 15px;
flex-wrap: wrap;
flex: 1;
justify-content: flex-end;
align-items: center;
min-width: 0;
}
.role-table {
background: var(--card-bg);
border-radius: 8px;
box-shadow: 0 2px 8px var(--shadow-color);
overflow: hidden;
margin-bottom: 20px;
}
@import '../../../assets/common-styles.css';
/* 角色管理特定样式 */
.loading {
display: flex;
flex-direction: column;
@ -466,8 +380,6 @@ export default { @@ -466,8 +380,6 @@ export default {
color: var(--accent-color);
}
.empty-state {
text-align: center;
padding: 40px;
@ -488,209 +400,22 @@ export default { @@ -488,209 +400,22 @@ export default {
color: var(--text-muted);
}
table {
width: 100%;
border-collapse: collapse;
}
th, td {
padding: 8px;
text-align: left;
border-bottom: 1px solid var(--border-color);
font-size: 12px;
}
th {
background: var(--bg-secondary);
font-weight: normal;
color: var(--text-primary);
font-size: 14px;
}
.actions {
display: flex;
gap: 8px;
}
.btn {
padding: 8px 16px;
border: none;
border-radius: 4px;
cursor: pointer;
.role-description {
color: var(--text-secondary);
font-size: 12px;
display: inline-flex;
align-items: center;
gap: 6px;
transition: all 0.2s;
}
.btn-primary {
background: #1976d2;
color: white;
}
.btn-primary:hover {
background: #1565c0;
}
.btn-info {
background: #0288d1;
color: white;
margin-top: 4px;
}
.btn-danger {
background: #d32f2f;
color: white;
}
.btn-secondary {
background: #757575;
color: white;
}
.btn-sm {
padding: 6px 12px;
font-size: 10px;
}
/* 表格操作按钮样式优化 */
.actions .btn-sm {
background: none;
border: none;
padding: 6px 10px;
margin: 0 -2px;
color: var(--text-primary);
transition: all 0.2s;
}
.actions .btn-sm i {
font-size: 14px;
}
.actions .btn-sm:hover {
background: var(--bg-secondary);
color: var(--accent-color);
transform: scale(1.1);
}
.actions .btn-sm.btn-info:hover {
color: #2196f3;
}
.actions .btn-sm.btn-primary:hover {
.permission-count {
background: #e3f2fd;
color: #1976d2;
}
.actions .btn-sm.btn-danger:hover {
color: #d32f2f;
}
.btn:hover {
opacity: 0.9;
}
.btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.pagination {
display: flex;
justify-content: center;
align-items: center;
gap: 20px;
}
.page-info {
color: #666;
font-size: 14px;
}
.modal-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0,0,0,0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
}
.modal {
background: var(--card-bg);
border-radius: 8px;
width: 90%;
max-width: 500px;
max-height: 90vh;
overflow-y: auto;
box-sizing: border-box;
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 20px;
border-bottom: 1px solid var(--border-color);
}
.modal-header h3 {
margin: 0;
font-size: 14px;
font-weight: normal;
}
.close-btn {
background: none;
border: none;
font-size: 14px;
cursor: pointer;
color: #999;
}
.modal-body {
padding: 20px;
box-sizing: border-box;
}
.form-group {
margin-bottom: 20px;
}
.form-group label {
display: block;
margin-bottom: 8px;
font-weight: normal;
color: #333;
font-size: 14px;
}
.form-group input,
.form-group textarea {
width: 100%;
padding: 10px;
border: 1px solid #ddd;
padding: 2px 6px;
border-radius: 4px;
font-size: 14px;
box-sizing: border-box;
font-size: 12px;
}
.form-group textarea {
resize: vertical;
min-height: 80px;
}
.form-actions {
display: flex;
gap: 12px;
justify-content: flex-end;
margin-top: 30px;
}
.icon {
font-size: 14px;
}
</style>

127
gofaster/app/src/renderer/modules/system-settings/views/Settings.vue

@ -1,13 +1,13 @@ @@ -1,13 +1,13 @@
<template>
<div class="settings">
<div class="settings management-page">
<div class="page-header">
<h2>用户设置</h2>
<h2><i class="fas fa-cog"></i> 用户设置</h2>
</div>
<div class="settings-content">
<!-- 个人偏好 -->
<div class="settings-section">
<h3>个人偏好</h3>
<!-- 个人偏好 -->
<div class="settings-section">
<h3><i class="fas fa-user-cog"></i> 个人偏好</h3>
<div class="setting-item">
<label>应用名称</label>
<input v-model="settings.appName" type="text" placeholder="GoFaster" />
@ -29,9 +29,9 @@ @@ -29,9 +29,9 @@
</div>
</div>
<!-- 应用设置 -->
<div class="settings-section">
<h3>应用设置</h3>
<!-- 应用设置 -->
<div class="settings-section">
<h3><i class="fas fa-tools"></i> 应用设置</h3>
<div class="setting-item">
<label>请求超时时间 ()</label>
<input v-model="settings.timeout" type="number" min="5" max="60" />
@ -42,9 +42,9 @@ @@ -42,9 +42,9 @@
</div>
</div>
<!-- 用户设置 -->
<div class="settings-section">
<h3>用户设置</h3>
<!-- 用户设置 -->
<div class="settings-section">
<h3><i class="fas fa-user-shield"></i> 用户设置</h3>
<div class="setting-item">
<label>关闭窗口不登出</label>
<div class="toggle-switch">
@ -70,9 +70,9 @@ @@ -70,9 +70,9 @@
</div>
</div>
<!-- 通知偏好 -->
<div class="settings-section">
<h3>通知偏好</h3>
<!-- 通知偏好 -->
<div class="settings-section">
<h3><i class="fas fa-bell"></i> 通知偏好</h3>
<div class="setting-item">
<label>桌面通知</label>
<div class="toggle-switch">
@ -101,9 +101,9 @@ @@ -101,9 +101,9 @@
</div>
</div>
<!-- 数据管理 -->
<div class="settings-section">
<h3>数据管理</h3>
<!-- 数据管理 -->
<div class="settings-section">
<h3><i class="fas fa-database"></i> 数据管理</h3>
<div class="setting-item">
<label>数据缓存大小 (MB)</label>
<input v-model="settings.cacheSize" type="number" min="50" max="1000" />
@ -327,80 +327,22 @@ export default { @@ -327,80 +327,22 @@ export default {
</script>
<style scoped>
.settings {
padding: 20px;
/* 移除强制高度和滚动条设置,让内容自然流动 */
}
.page-header {
margin-bottom: 30px;
}
.page-header h2 {
margin: 0;
color: var(--text-primary);
font-size: 24px;
}
@import '../../../assets/common-styles.css';
/* 系统设置特定样式 */
.settings-content {
max-width: 800px;
}
.settings-section {
background: var(--card-bg);
border-radius: 8px;
padding: 24px;
margin-bottom: 24px;
box-shadow: 0 2px 8px var(--shadow-color);
}
.settings-section h3 {
margin: 0 0 20px 0;
color: var(--text-primary);
font-size: 18px;
border-bottom: 2px solid var(--border-color);
padding-bottom: 8px;
}
.setting-item {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 20px;
padding: 16px 0;
border-bottom: 1px solid #f5f5f5;
}
.setting-item:last-child {
border-bottom: none;
margin-bottom: 0;
}
.setting-item label {
font-weight: 500;
color: var(--text-primary);
min-width: 200px;
/* 设置标题图标样式 */
.page-header h2 i,
.settings-section h3 i {
margin-right: 8px;
color: var(--accent-color);
font-size: 0.9em;
}
.setting-item input[type="text"],
.setting-item input[type="number"],
.setting-item select {
padding: 8px 12px;
border: 1px solid var(--input-border);
border-radius: 4px;
font-size: 14px;
min-width: 200px;
background-color: var(--input-bg);
color: var(--input-text);
}
.setting-item input[type="text"]:focus,
.setting-item input[type="number"]:focus,
.setting-item select:focus {
outline: none;
border-color: var(--accent-color);
box-shadow: 0 0 0 2px rgba(74, 158, 255, 0.2);
}
/* 开关样式 */
.toggle-switch {
@ -462,25 +404,6 @@ export default { @@ -462,25 +404,6 @@ export default {
margin-top: 30px;
}
.btn {
padding: 12px 24px;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 14px;
font-weight: 500;
transition: all 0.2s;
}
.btn-primary {
background: #1976d2;
color: white;
}
.btn-primary:hover {
background: #1565c0;
}
.btn-secondary {
background: #757575;
color: white;

348
gofaster/app/src/renderer/modules/user-management/views/UserManagement.vue

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
<template>
<div class="user-management">
<div class="user-management management-page">
<!-- 搜索和筛选 -->
<div class="search-bar">
<div class="search-input">
@ -30,7 +30,7 @@ @@ -30,7 +30,7 @@
</div>
<!-- 用户列表 -->
<div class="user-table">
<div class="user-table data-table">
<table>
<thead>
<tr>
@ -382,342 +382,9 @@ export default { @@ -382,342 +382,9 @@ export default {
</script>
<style scoped>
.user-management {
padding: 20px;
padding-top: 10px;
/* 移除强制高度和滚动条设置,让内容自然流动 */
}
.search-bar {
display: flex;
gap: 20px;
margin-bottom: 6px;
margin-top: 0;
align-items: center;
flex-wrap: wrap;
justify-content: space-between;
}
.search-input {
position: relative;
flex: 0 0 280px;
min-width: 200px;
max-width: 350px;
}
/* 响应式设计 */
@media (max-width: 768px) {
.search-bar {
flex-direction: column;
align-items: stretch;
gap: 15px;
justify-content: flex-start;
}
.search-input {
flex: 1;
min-width: auto;
max-width: none;
}
.filters {
justify-content: space-between;
flex: none;
}
.filters select {
flex: 1;
min-width: auto;
max-width: none;
}
}
/* 中等屏幕优化 */
@media (max-width: 1024px) and (min-width: 769px) {
.search-input {
flex: 0 0 250px;
min-width: 200px;
max-width: 300px;
}
.filters select {
min-width: 90px;
max-width: 130px;
}
}
.search-input i {
position: absolute;
left: 12px;
top: 50%;
transform: translateY(-50%);
color: var(--text-muted);
font-size: 12px;
}
.search-input input {
width: 100%;
padding: 8px 10px 8px 35px;
border: 1px solid var(--input-border);
border-radius: 6px;
font-size: 12px;
background-color: var(--input-bg);
color: var(--input-text);
}
.filters {
display: flex;
gap: 15px;
flex-wrap: wrap;
flex: 1;
justify-content: flex-end;
align-items: center;
min-width: 0;
}
.filters select {
padding: 6px 12px;
border: 1px solid var(--input-border);
border-radius: 4px;
font-size: 12px;
background-color: var(--input-bg);
color: var(--input-text);
min-width: 100px;
max-width: 150px;
flex: 0 0 auto;
}
.user-table {
background: var(--card-bg);
border-radius: 8px;
box-shadow: 0 2px 8px var(--shadow-color);
overflow: hidden;
margin-bottom: 20px;
}
table {
width: 100%;
border-collapse: collapse;
}
th, td {
padding: 8px;
text-align: left;
border-bottom: 1px solid var(--border-color);
font-size: 12px;
}
th {
background: var(--bg-secondary);
font-weight: normal;
color: var(--text-primary);
font-size: 14px;
}
.status-badge {
padding: 4px 8px;
border-radius: 12px;
font-size: 12px;
font-weight: normal;
}
.status-badge.active {
background: #e8f5e8;
color: #2e7d32;
}
.status-badge.inactive {
background: #ffebee;
color: #c62828;
}
.role-tags {
display: flex;
gap: 4px;
flex-wrap: wrap;
}
.role-tag {
background: #e3f2fd;
color: #1976d2;
padding: 2px 6px;
border-radius: 4px;
font-size: 14px;
}
.actions {
display: flex;
gap: 8px;
}
.btn {
padding: 8px 16px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 12px;
display: inline-flex;
align-items: center;
gap: 6px;
transition: all 0.2s;
}
.btn-primary {
background: #1976d2;
color: white;
}
.btn-primary:hover {
background: #1565c0;
}
.btn-info {
background: #0288d1;
color: white;
}
.btn-danger {
background: #d32f2f;
color: white;
}
.btn-secondary {
background: #757575;
color: white;
}
.btn-sm {
padding: 6px 12px;
font-size: 10px;
}
/* 表格操作按钮样式优化 */
.actions .btn-sm {
background: none;
border: none;
padding: 6px 10px;
margin: 0 -2px;
color: var(--text-primary);
transition: all 0.2s;
}
.actions .btn-sm i {
font-size: 14px;
}
.actions .btn-sm:hover {
background: var(--bg-secondary);
color: var(--accent-color);
transform: scale(1.1);
}
.actions .btn-sm.btn-info:hover {
color: #2196f3;
}
.actions .btn-sm.btn-primary:hover {
color: #1976d2;
}
.actions .btn-sm.btn-danger:hover {
color: #d32f2f;
}
.btn:hover {
opacity: 0.9;
}
.btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.pagination {
display: flex;
justify-content: center;
align-items: center;
gap: 20px;
}
.page-info {
color: #666;
font-size: 14px;
}
.modal-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0,0,0,0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
}
.modal {
background: white;
border-radius: 8px;
width: 90%;
max-width: 500px;
max-height: 90vh;
overflow-y: auto;
box-sizing: border-box;
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 20px;
border-bottom: 1px solid #eee;
}
.modal-header h3 {
margin: 0;
font-size: 14px;
font-weight: normal;
}
.close-btn {
background: none;
border: none;
font-size: 14px;
cursor: pointer;
color: #999;
}
.modal-body {
padding: 20px;
box-sizing: border-box;
}
.form-group {
margin-bottom: 20px;
}
.form-group label {
display: block;
margin-bottom: 8px;
font-weight: normal;
color: #333;
font-size: 14px;
}
.form-group input,
.form-group select {
width: 100%;
padding: 10px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 14px;
box-sizing: border-box;
}
@import '../../../assets/common-styles.css';
/* 用户管理特定样式 */
.role-checkboxes {
display: flex;
flex-direction: column;
@ -735,13 +402,6 @@ th { @@ -735,13 +402,6 @@ th {
width: auto;
}
.form-actions {
display: flex;
gap: 12px;
justify-content: flex-end;
margin-top: 30px;
}
.icon {
font-size: 14px;
}

392
gofaster/app/src/renderer/modules/user-management/views/UserProfile.vue

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@
<template>
<div class="user-profile">
<div class="profile-header">
<h1><i class="fas fa-user"></i> 个人资料</h1>
<div class="user-profile management-page">
<div class="page-header">
<h2><i class="fas fa-user"></i> 个人资料</h2>
<p class="profile-subtitle">查看和管理您的账户信息</p>
</div>
@ -22,101 +22,89 @@ @@ -22,101 +22,89 @@
</div>
<!-- 用户信息内容 -->
<div v-else-if="userInfo" class="profile-content">
<div v-else-if="userInfo" class="settings-content">
<!-- 基本信息卡片 -->
<div class="profile-card">
<div class="card-header">
<h2><i class="fas fa-info-circle"></i> 基本信息</h2>
</div>
<div class="card-content">
<div class="info-grid">
<div class="info-item">
<label>用户ID</label>
<span>{{ userInfo.id || 'N/A' }}</span>
</div>
<div class="info-item">
<label>用户名</label>
<span>{{ userInfo.username || userInfo.name || 'N/A' }}</span>
</div>
<div class="info-item">
<label>邮箱</label>
<span>{{ userInfo.email || 'N/A' }}</span>
</div>
<div class="info-item">
<label>手机号</label>
<span>{{ userInfo.phone || 'N/A' }}</span>
</div>
<div class="info-item">
<label>状态</label>
<span :class="['status-badge', getStatusClass(userInfo.status)]">
{{ getStatusText(userInfo.status) }}
</span>
</div>
<div class="info-item">
<label>注册时间</label>
<span>{{ formatDate(userInfo.created_at) || formatDate(userInfo.createdAt) || 'N/A' }}</span>
</div>
<div class="settings-section">
<h3><i class="fas fa-info-circle"></i> 基本信息</h3>
<div class="info-grid">
<div class="info-item">
<label>用户ID</label>
<span>{{ userInfo.id || 'N/A' }}</span>
</div>
<div class="info-item">
<label>用户名</label>
<span>{{ userInfo.username || userInfo.name || 'N/A' }}</span>
</div>
<div class="info-item">
<label>邮箱</label>
<span>{{ userInfo.email || 'N/A' }}</span>
</div>
<div class="info-item">
<label>手机号</label>
<span>{{ userInfo.phone || 'N/A' }}</span>
</div>
<div class="info-item">
<label>状态</label>
<span :class="['status-badge', getStatusClass(userInfo.status)]">
{{ getStatusText(userInfo.status) }}
</span>
</div>
<div class="info-item">
<label>注册时间</label>
<span>{{ formatDate(userInfo.created_at) || formatDate(userInfo.createdAt) || 'N/A' }}</span>
</div>
</div>
</div>
<!-- 登录信息卡片 -->
<div class="profile-card">
<div class="card-header">
<h2><i class="fas fa-lock"></i> 登录信息</h2>
</div>
<div class="card-content">
<div class="info-grid">
<div class="info-item">
<label>上次登录时间</label>
<span>{{ formatDate(userInfo.last_login_at) || formatDate(userInfo.lastLogin) || 'N/A' }}</span>
</div>
<div class="info-item">
<label>上次登录IP</label>
<span>{{ userInfo.last_login_ip || userInfo.lastLoginIP || 'N/A' }}</span>
</div>
</div>
<div class="settings-section">
<h3><i class="fas fa-lock"></i> 登录信息</h3>
<div class="info-grid">
<div class="info-item">
<label>上次登录时间</label>
<span>{{ formatDate(userInfo.last_login_at) || formatDate(userInfo.lastLogin) || 'N/A' }}</span>
</div>
<div class="info-item">
<label>上次登录IP</label>
<span>{{ userInfo.last_login_ip || userInfo.lastLoginIP || 'N/A' }}</span>
</div>
</div>
</div>
<!-- 角色信息卡片 -->
<div class="profile-card">
<div class="card-header">
<h2><i class="fas fa-crown"></i> 角色信息</h2>
</div>
<div class="card-content">
<div v-if="userInfo.roles && userInfo.roles.length > 0" class="roles-list">
<div v-for="role in userInfo.roles" :key="role.id" class="role-item">
<div class="role-header">
<span class="role-name">{{ role.name }}</span>
<span class="role-description">{{ role.description || '无描述' }}</span>
</div>
<div class="role-permissions">
<h4>权限列表</h4>
<div class="permissions-grid">
<span
v-for="permission in role.permissions"
:key="permission.id"
class="permission-tag"
>
{{ permission.name }}
</span>
</div>
<div class="settings-section">
<h3><i class="fas fa-crown"></i> 角色信息</h3>
<div v-if="userInfo.roles && userInfo.roles.length > 0" class="roles-list">
<div v-for="role in userInfo.roles" :key="role.id" class="role-item">
<div class="role-header">
<span class="role-name">{{ role.name }}</span>
<span class="role-description">{{ role.description || '无描述' }}</span>
</div>
<div class="role-permissions">
<h4>权限列表</h4>
<div class="permissions-grid">
<span
v-for="permission in role.permissions"
:key="permission.id"
class="permission-tag"
>
{{ permission.name }}
</span>
</div>
</div>
</div>
<div v-else class="no-roles">
<p>暂无角色信息</p>
</div>
</div>
<div v-else class="no-roles">
<p>暂无角色信息</p>
</div>
</div>
<!-- 操作按钮 -->
<div class="profile-actions">
<button @click="refreshProfile" class="action-btn refresh-btn">
<div class="settings-actions">
<button @click="refreshProfile" class="btn btn-secondary">
<i class="fas fa-sync-alt"></i> 刷新信息
</button>
<button @click="changePassword" class="action-btn password-btn">
<button @click="changePassword" class="btn btn-primary">
<i class="fas fa-lock"></i> 修改密码
</button>
</div>
@ -300,28 +288,9 @@ export default { @@ -300,28 +288,9 @@ export default {
</script>
<style scoped>
.user-profile {
padding: 20px;
/* 移除强制高度和滚动条设置,让内容自然流动 */
}
.profile-header {
text-align: center;
margin-bottom: 26px;
}
.profile-header h1 {
font-size: 16px;
color: var(--text-primary);
margin-bottom: 10px;
}
.profile-subtitle {
font-size: 12px;
color: var(--text-secondary);
margin: 0;
}
@import '../../../assets/common-styles.css';
/* 个人资料特定样式 */
.loading-container {
text-align: center;
padding: 60px 20px;
@ -370,200 +339,16 @@ export default { @@ -370,200 +339,16 @@ export default {
background: #c53030;
}
.profile-content {
max-width: 800px;
margin: 0 auto;
}
.profile-card {
background: var(--card-bg);
border-radius: 8px;
padding: 20px;
margin-bottom: 20px;
box-shadow: 0 2px 8px var(--shadow-color);
}
.card-header {
margin: 0 0 16px 0;
color: var(--text-primary);
font-size: 14px;
border-bottom: 2px solid var(--border-color);
padding-bottom: 8px;
}
.card-header h2 {
margin: 0;
font-size: 14px;
color: var(--text-primary);
}
.info-grid {
display: flex;
flex-direction: column;
gap: 0;
}
.info-item {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 16px;
padding: 12px 0;
border-bottom: 1px solid #f5f5f5;
}
.info-item:last-child {
border-bottom: none;
margin-bottom: 0;
}
.info-item label {
font-weight: 500;
color: var(--text-primary);
min-width: 200px;
font-size: 12px;
}
.info-item span {
color: var(--text-primary);
font-size: 12px;
text-align: right;
flex: 1;
}
.status-badge {
display: inline-block;
padding: 6px 12px;
border-radius: 20px;
font-size: 12px;
font-weight: 600;
text-align: center;
min-width: 80px;
}
.status-active {
background: #d4edda;
color: #155724;
}
.status-inactive {
background: #f8d7da;
color: #721c24;
}
.status-pending {
.status-badge.pending {
background: #fff3cd;
color: #856404;
}
.status-unknown {
.status-badge.unknown {
background: #e2e3e5;
color: #383d41;
}
.roles-list {
display: flex;
flex-direction: column;
gap: 16px;
}
.role-item {
background: var(--card-bg);
border-radius: 8px;
padding: 16px;
border: 1px solid var(--border-color);
margin-bottom: 12px;
}
.role-header {
margin-bottom: 12px;
}
.role-name {
display: block;
font-size: 12px;
font-weight: 600;
color: var(--text-primary);
margin-bottom: 8px;
}
.role-description {
color: var(--text-secondary);
font-size: 12px;
}
.role-permissions h4 {
margin: 0 0 8px 0;
color: var(--text-primary);
font-size: 12px;
}
.permissions-grid {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.permission-tag {
background: var(--accent-color);
color: white;
padding: 4px 12px;
border-radius: 16px;
font-size: 12px;
border: none;
}
.no-roles {
text-align: center;
color: var(--text-secondary);
padding: 40px 20px;
font-size: 12px;
}
.profile-actions {
display: flex;
gap: 16px;
justify-content: flex-end;
margin-top: 26px;
}
.action-btn {
padding: 12px 24px;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 12px;
font-weight: 500;
transition: all 0.2s;
}
.refresh-btn {
background: #1976d2;
color: white;
}
.refresh-btn:hover {
background: #1565c0;
}
.edit-btn {
background: #f39c12;
color: white;
}
.edit-btn:hover {
background: #e67e22;
}
.password-btn {
background: #e74c3c;
color: white;
}
.password-btn:hover {
background: #c0392b;
}
.empty-state {
text-align: center;
padding: 80px 20px;
@ -600,39 +385,4 @@ export default { @@ -600,39 +385,4 @@ export default {
.login-btn:hover {
background: #1565c0;
}
/* 响应式设计 */
@media (max-width: 768px) {
.user-profile {
padding: 15px;
}
.profile-header h1 {
font-size: 16px;
}
.info-item {
flex-direction: column;
align-items: flex-start;
gap: 12px;
}
.info-item label {
min-width: auto;
}
.info-item span {
text-align: left;
}
.profile-actions {
flex-direction: column;
align-items: center;
}
.action-btn {
width: 100%;
max-width: 300px;
}
}
</style>

Loading…
Cancel
Save