1276 lines
27 KiB
Markdown
1276 lines
27 KiB
Markdown
# CRMEB 页面设计规范与 Uni-App-X UVue 复刻指南
|
||
|
||
## 📋 目录
|
||
|
||
1. [CRMEB 项目架构分析](#crmeb-项目架构分析)
|
||
2. [页面布局模式](#页面布局模式)
|
||
3. [样式系统设计](#样式系统设计)
|
||
4. [组件设计规范](#组件设计规范)
|
||
5. [工程化配置](#工程化配置)
|
||
6. [UVue 复刻方案](#uvue-复刻方案)
|
||
7. [迁移检查清单](#迁移检查清单)
|
||
|
||
---
|
||
|
||
## CRMEB 项目架构分析
|
||
|
||
### 1. 项目结构概览
|
||
|
||
```
|
||
CRMEB/template/admin/
|
||
├── src/
|
||
│ ├── layout/ # 布局系统
|
||
│ │ ├── index.vue # 主布局容器(支持多种布局模式)
|
||
│ │ ├── main/ # 主要布局模式
|
||
│ │ │ ├── defaults.vue # 默认布局
|
||
│ │ │ ├── classic.vue # 经典布局
|
||
│ │ │ ├── transverse.vue # 横向布局
|
||
│ │ │ └── columns.vue # 分栏布局
|
||
│ │ ├── navBars/ # 导航栏系统
|
||
│ │ │ ├── breadcrumb/ # 面包屑
|
||
│ │ │ └── tagsView/ # 标签页
|
||
│ │ ├── navMenu/ # 侧边栏菜单
|
||
│ │ ├── footer/ # 页脚
|
||
│ │ └── component/ # 布局相关组件
|
||
│ ├── components/ # 全局可复用组件(60+)
|
||
│ │ ├── cards/ # 卡片组件
|
||
│ │ ├── from/ # 表单相关
|
||
│ │ ├── searchFrom/ # 搜索表单
|
||
│ │ └── ...
|
||
│ ├── pages/ # 页面模块(16个大类)
|
||
│ │ ├── account/ # 账户管理
|
||
│ │ ├── agent/ # 代理管理
|
||
│ │ ├── app/ # APP管理
|
||
│ │ ├── cms/ # CMS内容
|
||
│ │ ├── finance/ # 财务
|
||
│ │ ├── order/ # 订单
|
||
│ │ ├── product/ # 商品
|
||
│ │ ├── system/ # 系统设置
|
||
│ │ ├── user/ # 用户管理
|
||
│ │ └── ...
|
||
│ ├── styles/ # 全局样式
|
||
│ ├── router/ # 路由配置
|
||
│ ├── store/ # 状态管理(Vuex)
|
||
│ ├── utils/ # 工具函数
|
||
│ └── ...
|
||
├── package.json # 项目依赖(Vue 2)
|
||
├── vue.config.js # Webpack 配置
|
||
├── .prettierrc.js # 代码格式化规则
|
||
└── babel.config.js # Babel 配置
|
||
```
|
||
|
||
### 2. 核心设计特点
|
||
|
||
#### 2.1 多布局支持
|
||
|
||
CRMEB 支持 4 种布局模式:
|
||
|
||
- **Defaults**: 侧边栏 + 顶部菜单 + 内容区
|
||
- **Classic**: 经典布局(左菜单 + 内容)
|
||
- **Transverse**: 顶部菜单 + 内容
|
||
- **Columns**: 三栏布局(侧菜单 + 侧栏 + 内容)
|
||
|
||
#### 2.2 标签页系统
|
||
|
||
- 每个打开的页面都生成一个标签
|
||
- 支持标签页关闭、固定、刷新
|
||
- 与路由历史联动
|
||
|
||
#### 2.3 面包屑导航
|
||
|
||
- 动态生成,根据路由元信息
|
||
- 支持多级导航回溯
|
||
|
||
#### 2.4 响应式设计
|
||
|
||
- 自动监听窗口大小
|
||
- < 1000px 时自动切换移动端布局
|
||
- 侧边栏自动收起
|
||
|
||
---
|
||
|
||
## 页面布局模式
|
||
|
||
### CRMEB 的四种布局
|
||
|
||
#### 模式 1: Defaults(默认布局 - 最常用)
|
||
|
||
```
|
||
┌─────────────────────────────────────────┐
|
||
│ Logo │ Breadcrumb │ Tags │ User │ ← NavBars
|
||
├─────────┼─────────────────────────────────┤
|
||
│ Menu │ │
|
||
│ │ Content Area │
|
||
│ │ (Page Components) │
|
||
│ │ │
|
||
├─────────┴─────────────────────────────────┤
|
||
│ Footer │
|
||
└─────────────────────────────────────────┘
|
||
```
|
||
|
||
**特点**:
|
||
|
||
- 左侧固定菜单栏
|
||
- 顶部面包屑 + 标签页
|
||
- 主内容区占据剩余空间
|
||
|
||
#### 模式 2: Classic(经典布局)
|
||
|
||
```
|
||
┌─────────────────────────────────────────┐
|
||
│ Logo │ Breadcrumb │ Tags │ User Settings │ ← NavBars
|
||
├──────┴─────────────────────────────────────┤
|
||
│ Menu │ Content Area │
|
||
│ │ (Page Components) │
|
||
│ │ │
|
||
├──────┴─────────────────────────────────────┤
|
||
│ Footer │
|
||
└─────────────────────────────────────────────┘
|
||
```
|
||
|
||
#### 模式 3: Transverse(横向菜单)
|
||
|
||
```
|
||
┌────────────────────────────────────────┐
|
||
│ Logo │ Menu 1 │ Menu 2 │ ... │ Settings│ ← Top Menu
|
||
├────────────────────────────────────────┤
|
||
│ Breadcrumb │ Tags │ Actions │
|
||
├────────────────────────────────────────┤
|
||
│ │
|
||
│ Content Area │
|
||
│ (Page Components) │
|
||
│ │
|
||
└────────────────────────────────────────┘
|
||
```
|
||
|
||
#### 模式 4: Columns(三栏布局)
|
||
|
||
```
|
||
┌──────────────────────────────────────────┐
|
||
│ NavBars (Breadcrumb + Tags) │
|
||
├─────────┬──────────┬──────────────────────┤
|
||
│ Menu │ SubMenu │ Content Area │
|
||
│ │ │ (Page Components) │
|
||
│ │ │ │
|
||
└─────────┴──────────┴──────────────────────┘
|
||
```
|
||
|
||
---
|
||
|
||
## 样式系统设计
|
||
|
||
### 1. 全局样式架构
|
||
|
||
```scss
|
||
styles/
|
||
├── common.scss # 通用样式重置、基础类名
|
||
├── variables.scss # CSS 变量、主题颜色
|
||
├── animate.scss # 动画库
|
||
├── element-ui.scss # Element UI 主题覆盖
|
||
└── index.scss # 主入口文件
|
||
```
|
||
|
||
### 2. 颜色系统
|
||
|
||
CRMEB 使用标准设计系统颜色:
|
||
|
||
- **主颜色**: `#1890ff`(蓝色)
|
||
- **成功**: `#52c41a`(绿色)
|
||
- **警告**: `#faad14`(黄色)
|
||
- **错误**: `#ff4d4f`(红色)
|
||
- **边框**: `#d9d9d9`(灰色)
|
||
- **文字**: `#000000` / `#666666` / `#999999`
|
||
|
||
### 3. 间距系统
|
||
|
||
```scss
|
||
$space-xs: 4px;
|
||
$space-sm: 8px;
|
||
$space: 12px;
|
||
$space-md: 16px;
|
||
$space-lg: 24px;
|
||
$space-xl: 32px;
|
||
```
|
||
|
||
### 4. 圆角系统
|
||
|
||
```scss
|
||
$radius-xs: 2px;
|
||
$radius-sm: 4px;
|
||
$radius: 6px;
|
||
$radius-lg: 8px;
|
||
$radius-xl: 12px;
|
||
```
|
||
|
||
### 5. 阴影系统
|
||
|
||
```scss
|
||
$shadow-sm: 0 2px 4px rgba(0, 0, 0, 0.06);
|
||
$shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||
$shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.15);
|
||
```
|
||
|
||
---
|
||
|
||
## 组件设计规范
|
||
|
||
### 1. 组件命名规范
|
||
|
||
```
|
||
常用组件类型:
|
||
- Cards/ # 卡片展示(数据统计卡、信息卡)
|
||
- Form/ # 表单相关(表单控件、表单验证)
|
||
- List/ # 列表显示(表格、数据列表)
|
||
- Modal/ # 模态框(确认框、详情框)
|
||
- Table/ # 表格组件(支持排序、分页、筛选)
|
||
- Upload/ # 上传组件(图片、视频、文件)
|
||
- Search/ # 搜索组件(高级搜索、快速搜索)
|
||
```
|
||
|
||
### 2. 常用组件库
|
||
|
||
CRMEB 使用 Element UI 作为基础组件库:
|
||
|
||
- `el-button` - 按钮
|
||
- `el-input` - 输入框
|
||
- `el-select` - 选择器
|
||
- `el-table` - 表格
|
||
- `el-form` - 表单
|
||
- `el-dialog` - 对话框
|
||
- `el-tree` - 树形控件
|
||
- `el-pagination` - 分页
|
||
|
||
### 3. 页面组件结构
|
||
|
||
```vue
|
||
<template>
|
||
<div class="page-container">
|
||
<!-- 页面标题 / 操作栏 -->
|
||
<div class="page-header">
|
||
<h1>{{ pageTitle }}</h1>
|
||
<div class="page-actions">
|
||
<el-button type="primary">新增</el-button>
|
||
<el-button>导出</el-button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 搜索表单 -->
|
||
<div class="search-container">
|
||
<SearchForm @search="handleSearch" />
|
||
</div>
|
||
|
||
<!-- 列表 / 内容区 -->
|
||
<div class="content-container">
|
||
<el-table :data="tableData" />
|
||
</div>
|
||
|
||
<!-- 分页 -->
|
||
<div class="pagination-container">
|
||
<el-pagination @current-change="handlePageChange" />
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
export default {
|
||
name: "PageName",
|
||
components: {
|
||
SearchForm: () => import("@/components/searchFrom/index"),
|
||
},
|
||
data() {
|
||
return {
|
||
pageTitle: "页面标题",
|
||
tableData: [],
|
||
};
|
||
},
|
||
};
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
.page-container {
|
||
padding: 20px;
|
||
}
|
||
|
||
.page-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 20px;
|
||
|
||
h1 {
|
||
font-size: 20px;
|
||
font-weight: 600;
|
||
}
|
||
}
|
||
|
||
.search-container {
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.content-container {
|
||
background: #fff;
|
||
border-radius: 4px;
|
||
padding: 20px;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.pagination-container {
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
}
|
||
</style>
|
||
```
|
||
|
||
---
|
||
|
||
## 工程化配置
|
||
|
||
### 1. 构建工具配置
|
||
|
||
**vue.config.js** (Webpack):
|
||
|
||
```javascript
|
||
module.exports = {
|
||
productionSourceMap: false,
|
||
configureWebpack: {
|
||
resolve: {
|
||
alias: {
|
||
"@": path.resolve(__dirname, "./src"),
|
||
},
|
||
},
|
||
},
|
||
chainWebpack: (config) => {
|
||
// 优化大文件分割
|
||
config.optimization.splitChunks({
|
||
cacheGroups: {
|
||
vendor: {
|
||
test: /[\\/]node_modules[\\/]/,
|
||
name: "chunk-vendors",
|
||
priority: 10,
|
||
},
|
||
common: {
|
||
minChunks: 2,
|
||
priority: 5,
|
||
reuseExistingChunk: true,
|
||
},
|
||
},
|
||
});
|
||
},
|
||
};
|
||
```
|
||
|
||
### 2. 代码格式化配置
|
||
|
||
**.prettierrc.js**:
|
||
|
||
```javascript
|
||
module.exports = {
|
||
printWidth: 100,
|
||
tabWidth: 2,
|
||
useTabs: false,
|
||
semi: true,
|
||
singleQuote: true,
|
||
trailingComma: "es5",
|
||
bracketSpacing: true,
|
||
arrowParens: "always",
|
||
};
|
||
```
|
||
|
||
### 3. ESLint 配置
|
||
|
||
**.eslintrc.js**:
|
||
|
||
```javascript
|
||
module.exports = {
|
||
root: true,
|
||
env: {
|
||
node: true,
|
||
browser: true,
|
||
es2021: true,
|
||
},
|
||
extends: ["plugin:vue/essential", "eslint:recommended"],
|
||
parserOptions: {
|
||
parser: "babel-eslint",
|
||
ecmaVersion: 2020,
|
||
},
|
||
rules: {
|
||
"no-console": process.env.NODE_ENV === "production" ? "warn" : "off",
|
||
"no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off",
|
||
},
|
||
};
|
||
```
|
||
|
||
### 4. Babel 配置
|
||
|
||
**babel.config.js**:
|
||
|
||
```javascript
|
||
module.exports = {
|
||
presets: ["@vue/cli-plugin-babel/preset"],
|
||
plugins: [],
|
||
};
|
||
```
|
||
|
||
---
|
||
|
||
## UVue 复刻方案
|
||
|
||
### 1. 布局系统复刻
|
||
|
||
#### 1.1 AdminLayout 增强版
|
||
|
||
**layouts/admin/AdminLayout.uvue** - 支持多种布局:
|
||
|
||
```uvue
|
||
<template>
|
||
<view class="admin-layout" :class="layoutClass">
|
||
<!-- 模式1: Defaults(默认布局) -->
|
||
<template v-if="layoutMode === 'defaults'">
|
||
<AdminAside :collapsed="isCollapsed" @toggle="toggleCollapse" />
|
||
<view class="admin-main-defaults">
|
||
<AdminNavBar :breadcrumb="breadcrumb" />
|
||
<AdminTagsView :tabs="tabs" />
|
||
<view class="admin-content-defaults">
|
||
<slot></slot>
|
||
</view>
|
||
<AdminFooter />
|
||
</view>
|
||
</template>
|
||
|
||
<!-- 模式2: Classic(经典布局) -->
|
||
<template v-else-if="layoutMode === 'classic'">
|
||
<view class="admin-sidebar-classic">
|
||
<AdminAside :collapsed="isCollapsed" @toggle="toggleCollapse" />
|
||
</view>
|
||
<view class="admin-main-classic">
|
||
<AdminNavBar />
|
||
<view class="admin-content-classic">
|
||
<slot></slot>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<!-- 模式3: Columns(三栏布局) -->
|
||
<template v-else-if="layoutMode === 'columns'">
|
||
<AdminAside :collapsed="isCollapsed" @toggle="toggleCollapse" />
|
||
<AdminSubSider :collapsed="isSubCollapsed" @toggle="toggleSubCollapse" />
|
||
<view class="admin-main-columns">
|
||
<AdminNavBar />
|
||
<view class="admin-content-columns">
|
||
<slot></slot>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup lang="uts">
|
||
import { ref, computed, watch, onMounted, provide } from 'vue'
|
||
import { onShow } from '@dcloudio/uni-app'
|
||
import AdminAside from './components/AdminAside.uvue'
|
||
import AdminSubSider from './components/AdminSubSider.uvue'
|
||
import AdminNavBar from './components/AdminNavBar.uvue'
|
||
import AdminTagsView from './components/AdminTagsView.uvue'
|
||
import AdminFooter from './components/AdminFooter.uvue'
|
||
|
||
// Props
|
||
interface AdminLayoutProps {
|
||
currentPage: string
|
||
layoutMode?: 'defaults' | 'classic' | 'columns'
|
||
}
|
||
|
||
const props = withDefaults(defineProps<AdminLayoutProps>(), {
|
||
layoutMode: 'defaults'
|
||
})
|
||
|
||
// State
|
||
const isCollapsed = ref(false)
|
||
const isSubCollapsed = ref(false)
|
||
const tabs = ref([])
|
||
const breadcrumb = ref('')
|
||
|
||
// Computed
|
||
const layoutClass = computed(() => `layout-${props.layoutMode}`)
|
||
|
||
// Methods
|
||
const toggleCollapse = () => {
|
||
isCollapsed.value = !isCollapsed.value
|
||
}
|
||
|
||
const toggleSubCollapse = () => {
|
||
isSubCollapsed.value = !isSubCollapsed.value
|
||
}
|
||
|
||
// Provide to children
|
||
provide('layoutMode', props.layoutMode)
|
||
provide('isCollapsed', isCollapsed)
|
||
</script>
|
||
|
||
<style scoped lang="uts">
|
||
.admin-layout {
|
||
width: 100%;
|
||
height: 100vh;
|
||
display: flex;
|
||
flex-direction: column;
|
||
background: #f5f5f5;
|
||
}
|
||
|
||
/* Defaults 布局样式 */
|
||
.layout-defaults {
|
||
flex-direction: row;
|
||
}
|
||
|
||
.admin-main-defaults {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.admin-content-defaults {
|
||
flex: 1;
|
||
overflow-y: auto;
|
||
padding: 20px;
|
||
}
|
||
|
||
/* Classic 布局样式 */
|
||
.layout-classic {
|
||
flex-direction: row;
|
||
}
|
||
|
||
.admin-sidebar-classic {
|
||
width: 200px;
|
||
height: 100vh;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.admin-main-classic {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.admin-content-classic {
|
||
flex: 1;
|
||
overflow-y: auto;
|
||
padding: 20px;
|
||
}
|
||
|
||
/* Columns 布局样式 */
|
||
.layout-columns {
|
||
flex-direction: row;
|
||
}
|
||
|
||
.admin-main-columns {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.admin-content-columns {
|
||
flex: 1;
|
||
overflow-y: auto;
|
||
padding: 20px;
|
||
}
|
||
</style>
|
||
```
|
||
|
||
### 2. 样式系统复刻
|
||
|
||
#### 2.1 主样式文件
|
||
|
||
**uni.scss** - 全局 SCSS 变量:
|
||
|
||
```scss
|
||
// 颜色系统
|
||
$primary-color: #1890ff;
|
||
$success-color: #52c41a;
|
||
$warning-color: #faad14;
|
||
$error-color: #ff4d4f;
|
||
$info-color: #1890ff;
|
||
|
||
$text-primary: #000000;
|
||
$text-secondary: #666666;
|
||
$text-disabled: #999999;
|
||
|
||
$border-color: #d9d9d9;
|
||
$background-color: #f5f5f5;
|
||
|
||
// 间距系统
|
||
$space-xs: 4px;
|
||
$space-sm: 8px;
|
||
$space: 12px;
|
||
$space-md: 16px;
|
||
$space-lg: 24px;
|
||
$space-xl: 32px;
|
||
|
||
// 圆角系统
|
||
$radius-xs: 2px;
|
||
$radius-sm: 4px;
|
||
$radius: 6px;
|
||
$radius-lg: 8px;
|
||
$radius-xl: 12px;
|
||
|
||
// 阴影系统
|
||
$shadow-sm: 0 2px 4px rgba(0, 0, 0, 0.06);
|
||
$shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||
$shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.15);
|
||
|
||
// 字体大小
|
||
$font-size-xs: 12px;
|
||
$font-size-sm: 13px;
|
||
$font-size: 14px;
|
||
$font-size-md: 16px;
|
||
$font-size-lg: 18px;
|
||
$font-size-xl: 20px;
|
||
|
||
// 行高
|
||
$line-height-xs: 1.2;
|
||
$line-height-sm: 1.4;
|
||
$line-height: 1.6;
|
||
$line-height-lg: 1.8;
|
||
|
||
// 过渡动画
|
||
$transition-duration: 0.3s;
|
||
$transition-timing: cubic-bezier(0.645, 0.045, 0.355, 1);
|
||
```
|
||
|
||
#### 2.2 通用样式类
|
||
|
||
**styles/common.scss** - 常用工具类:
|
||
|
||
```scss
|
||
// 布局相关
|
||
.flex {
|
||
display: flex;
|
||
}
|
||
|
||
.flex-center {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.flex-between {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
}
|
||
|
||
.flex-col {
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
// 间距相关
|
||
.m-xs {
|
||
margin: $space-xs;
|
||
}
|
||
.m-sm {
|
||
margin: $space-sm;
|
||
}
|
||
.m {
|
||
margin: $space;
|
||
}
|
||
.m-md {
|
||
margin: $space-md;
|
||
}
|
||
.m-lg {
|
||
margin: $space-lg;
|
||
}
|
||
.m-xl {
|
||
margin: $space-xl;
|
||
}
|
||
|
||
.p-xs {
|
||
padding: $space-xs;
|
||
}
|
||
.p-sm {
|
||
padding: $space-sm;
|
||
}
|
||
.p {
|
||
padding: $space;
|
||
}
|
||
.p-md {
|
||
padding: $space-md;
|
||
}
|
||
.p-lg {
|
||
padding: $space-lg;
|
||
}
|
||
.p-xl {
|
||
padding: $space-xl;
|
||
}
|
||
|
||
// 文字相关
|
||
.text-center {
|
||
text-align: center;
|
||
}
|
||
.text-left {
|
||
text-align: left;
|
||
}
|
||
.text-right {
|
||
text-align: right;
|
||
}
|
||
|
||
.text-primary {
|
||
color: $text-primary;
|
||
}
|
||
.text-secondary {
|
||
color: $text-secondary;
|
||
}
|
||
.text-disabled {
|
||
color: $text-disabled;
|
||
}
|
||
|
||
.text-xs {
|
||
font-size: $font-size-xs;
|
||
}
|
||
.text-sm {
|
||
font-size: $font-size-sm;
|
||
}
|
||
.text {
|
||
font-size: $font-size;
|
||
}
|
||
.text-md {
|
||
font-size: $font-size-md;
|
||
}
|
||
.text-lg {
|
||
font-size: $font-size-lg;
|
||
}
|
||
|
||
// 显示/隐藏
|
||
.hidden {
|
||
display: none;
|
||
}
|
||
.block {
|
||
display: block;
|
||
}
|
||
.inline-block {
|
||
display: inline-block;
|
||
}
|
||
|
||
// 溢出处理
|
||
.truncate {
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.line-clamp-2 {
|
||
overflow: hidden;
|
||
display: -webkit-box;
|
||
-webkit-line-clamp: 2;
|
||
-webkit-box-orient: vertical;
|
||
}
|
||
|
||
// 边框
|
||
.border {
|
||
border: 1px solid $border-color;
|
||
}
|
||
.border-top {
|
||
border-top: 1px solid $border-color;
|
||
}
|
||
.border-bottom {
|
||
border-bottom: 1px solid $border-color;
|
||
}
|
||
.border-left {
|
||
border-left: 1px solid $border-color;
|
||
}
|
||
.border-right {
|
||
border-right: 1px solid $border-color;
|
||
}
|
||
|
||
// 圆角
|
||
.rounded {
|
||
border-radius: $radius;
|
||
}
|
||
.rounded-sm {
|
||
border-radius: $radius-sm;
|
||
}
|
||
.rounded-lg {
|
||
border-radius: $radius-lg;
|
||
}
|
||
|
||
// 阴影
|
||
.shadow-sm {
|
||
box-shadow: $shadow-sm;
|
||
}
|
||
.shadow {
|
||
box-shadow: $shadow;
|
||
}
|
||
.shadow-lg {
|
||
box-shadow: $shadow-lg;
|
||
}
|
||
|
||
// 背景色
|
||
.bg-white {
|
||
background-color: #ffffff;
|
||
}
|
||
.bg-light {
|
||
background-color: $background-color;
|
||
}
|
||
.bg-primary {
|
||
background-color: $primary-color;
|
||
}
|
||
|
||
// 透明度
|
||
.opacity-50 {
|
||
opacity: 0.5;
|
||
}
|
||
.opacity-75 {
|
||
opacity: 0.75;
|
||
}
|
||
```
|
||
|
||
### 3. 页面模板复刻
|
||
|
||
#### 3.1 标准列表页面
|
||
|
||
**pages/mall/admin/template/ListPage.uvue**:
|
||
|
||
```uvue
|
||
<template>
|
||
<AdminLayout :currentPage="currentPage">
|
||
<view class="list-page">
|
||
<!-- 页面标题和操作栏 -->
|
||
<view class="page-header flex-between">
|
||
<text class="page-title">{{ pageTitle }}</text>
|
||
<view class="page-actions">
|
||
<button @click="handleAdd" class="btn btn-primary">{{ addButtonText }}</button>
|
||
<button @click="handleExport" class="btn btn-default">导出</button>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 搜索表单 -->
|
||
<view class="search-form-container bg-white p-md rounded shadow-sm">
|
||
<SearchForm :fields="searchFields" @search="handleSearch" />
|
||
</view>
|
||
|
||
<!-- 列表内容 -->
|
||
<view class="list-container bg-white p-md rounded shadow-sm">
|
||
<view class="list-toolbar flex-between mb-md">
|
||
<text class="text-secondary">共 {{ total }} 条记录</text>
|
||
<view class="list-tools">
|
||
<button @click="handleRefresh" class="btn btn-sm">刷新</button>
|
||
<button @click="handleDelete" class="btn btn-sm">删除</button>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="list-table">
|
||
<table-view :data="listData" :columns="columns" @row-click="handleRowClick" />
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 分页 -->
|
||
<view class="pagination-container flex-center mt-lg">
|
||
<pagination
|
||
:current="pagination.current"
|
||
:pageSize="pagination.pageSize"
|
||
:total="total"
|
||
@change="handlePageChange"
|
||
/>
|
||
</view>
|
||
</view>
|
||
</AdminLayout>
|
||
</template>
|
||
|
||
<script setup lang="uts">
|
||
import { ref, reactive } from 'vue'
|
||
import AdminLayout from '@/layouts/admin/AdminLayout.uvue'
|
||
import SearchForm from '@/layouts/admin/components/SearchForm.uvue'
|
||
import TableView from '@/components/TableView.uvue'
|
||
import Pagination from '@/components/Pagination.uvue'
|
||
|
||
// 页面配置
|
||
const currentPage = 'list-page'
|
||
const pageTitle = '数据列表'
|
||
const addButtonText = '新增'
|
||
|
||
// 数据状态
|
||
const listData = ref([])
|
||
const total = ref(0)
|
||
|
||
// 分页信息
|
||
const pagination = reactive({
|
||
current: 1,
|
||
pageSize: 20,
|
||
})
|
||
|
||
// 搜索字段配置
|
||
const searchFields = ref([
|
||
{ key: 'name', label: '名称', type: 'text', placeholder: '请输入名称' },
|
||
{ key: 'status', label: '状态', type: 'select', options: [
|
||
{ label: '启用', value: 1 },
|
||
{ label: '禁用', value: 0 },
|
||
]},
|
||
{ key: 'date', label: '日期', type: 'daterange' },
|
||
])
|
||
|
||
// 表格列配置
|
||
const columns = ref([
|
||
{ prop: 'id', label: 'ID', width: 60 },
|
||
{ prop: 'name', label: '名称', minWidth: 120 },
|
||
{ prop: 'status', label: '状态', width: 80, formatter: (row: any) => row.status ? '启用' : '禁用' },
|
||
{ prop: 'createTime', label: '创建时间', width: 160 },
|
||
{ label: '操作', width: 120, fixed: 'right', slots: ['actions'] },
|
||
])
|
||
|
||
// 方法
|
||
const handleSearch = (filters: any) => {
|
||
pagination.current = 1
|
||
fetchList(filters)
|
||
}
|
||
|
||
const handlePageChange = (page: number) => {
|
||
pagination.current = page
|
||
fetchList()
|
||
}
|
||
|
||
const handleAdd = () => {
|
||
uni.navigateTo({ url: '/pages/mall/admin/list/add' })
|
||
}
|
||
|
||
const handleRefresh = () => {
|
||
fetchList()
|
||
}
|
||
|
||
const handleDelete = () => {
|
||
// 删除逻辑
|
||
}
|
||
|
||
const handleRowClick = (row: any) => {
|
||
uni.navigateTo({ url: `/pages/mall/admin/list/edit?id=${row.id}` })
|
||
}
|
||
|
||
const handleExport = () => {
|
||
// 导出逻辑
|
||
}
|
||
|
||
const fetchList = async (filters?: any) => {
|
||
// API 请求逻辑
|
||
// listData.value = response.data
|
||
// total.value = response.total
|
||
}
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
.list-page {
|
||
padding: 20px;
|
||
}
|
||
|
||
.page-header {
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.page-title {
|
||
font-size: $font-size-lg;
|
||
font-weight: 600;
|
||
color: $text-primary;
|
||
}
|
||
|
||
.page-actions {
|
||
display: flex;
|
||
gap: 10px;
|
||
}
|
||
|
||
.search-form-container {
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.list-container {
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.list-toolbar {
|
||
border-bottom: 1px solid $border-color;
|
||
padding-bottom: 12px;
|
||
}
|
||
|
||
.list-tools {
|
||
display: flex;
|
||
gap: 10px;
|
||
}
|
||
|
||
.pagination-container {
|
||
margin: 20px 0;
|
||
}
|
||
|
||
.btn {
|
||
padding: 8px 16px;
|
||
border: none;
|
||
border-radius: $radius;
|
||
font-size: $font-size;
|
||
cursor: pointer;
|
||
transition: all $transition-duration $transition-timing;
|
||
}
|
||
|
||
.btn-primary {
|
||
background-color: $primary-color;
|
||
color: #fff;
|
||
}
|
||
|
||
.btn-primary:active {
|
||
opacity: 0.8;
|
||
}
|
||
|
||
.btn-default {
|
||
background-color: $background-color;
|
||
color: $text-primary;
|
||
border: 1px solid $border-color;
|
||
}
|
||
|
||
.btn-sm {
|
||
padding: 6px 12px;
|
||
font-size: $font-size-sm;
|
||
}
|
||
</style>
|
||
```
|
||
|
||
#### 3.2 表单页面
|
||
|
||
**pages/mall/admin/template/FormPage.uvue**:
|
||
|
||
```uvue
|
||
<template>
|
||
<AdminLayout :currentPage="currentPage">
|
||
<view class="form-page">
|
||
<!-- 页面标题 -->
|
||
<view class="page-header">
|
||
<text class="page-title">{{ pageTitle }}</text>
|
||
</view>
|
||
|
||
<!-- 表单容器 -->
|
||
<form-view
|
||
ref="formRef"
|
||
:model="formData"
|
||
:fields="formFields"
|
||
:loading="loading"
|
||
@submit="handleSubmit"
|
||
/>
|
||
</view>
|
||
</AdminLayout>
|
||
</template>
|
||
|
||
<script setup lang="uts">
|
||
import { ref, reactive } from 'vue'
|
||
import AdminLayout from '@/layouts/admin/AdminLayout.uvue'
|
||
import FormView from '@/components/FormView.uvue'
|
||
|
||
const currentPage = 'form-page'
|
||
const pageTitle = '编辑数据'
|
||
const loading = ref(false)
|
||
|
||
const formData = reactive({
|
||
name: '',
|
||
description: '',
|
||
status: 1,
|
||
category: '',
|
||
tags: [],
|
||
attachments: [],
|
||
})
|
||
|
||
const formFields = ref([
|
||
{
|
||
key: 'name',
|
||
label: '名称',
|
||
type: 'text',
|
||
required: true,
|
||
placeholder: '请输入名称',
|
||
rules: [{ required: true, message: '名称不能为空' }],
|
||
},
|
||
{
|
||
key: 'description',
|
||
label: '描述',
|
||
type: 'textarea',
|
||
placeholder: '请输入描述',
|
||
rows: 4,
|
||
},
|
||
{
|
||
key: 'category',
|
||
label: '分类',
|
||
type: 'select',
|
||
required: true,
|
||
options: [
|
||
{ label: '分类1', value: 1 },
|
||
{ label: '分类2', value: 2 },
|
||
],
|
||
},
|
||
{
|
||
key: 'status',
|
||
label: '状态',
|
||
type: 'radio',
|
||
options: [
|
||
{ label: '启用', value: 1 },
|
||
{ label: '禁用', value: 0 },
|
||
],
|
||
},
|
||
{
|
||
key: 'tags',
|
||
label: '标签',
|
||
type: 'checkbox',
|
||
options: [
|
||
{ label: '热销', value: 'hot' },
|
||
{ label: '新品', value: 'new' },
|
||
{ label: '推荐', value: 'recommend' },
|
||
],
|
||
},
|
||
{
|
||
key: 'attachments',
|
||
label: '附件',
|
||
type: 'upload',
|
||
multiple: true,
|
||
accept: 'file',
|
||
},
|
||
])
|
||
|
||
const handleSubmit = async (data: any) => {
|
||
loading.value = true
|
||
try {
|
||
// API 提交逻辑
|
||
uni.showToast({ title: '提交成功', icon: 'success' })
|
||
setTimeout(() => {
|
||
uni.navigateBack()
|
||
}, 1500)
|
||
} catch (error) {
|
||
uni.showToast({ title: '提交失败', icon: 'error' })
|
||
} finally {
|
||
loading.value = false
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
.form-page {
|
||
padding: 20px;
|
||
max-width: 800px;
|
||
margin: 0 auto;
|
||
}
|
||
|
||
.page-header {
|
||
margin-bottom: 24px;
|
||
}
|
||
|
||
.page-title {
|
||
font-size: $font-size-lg;
|
||
font-weight: 600;
|
||
color: $text-primary;
|
||
}
|
||
</style>
|
||
```
|
||
|
||
---
|
||
|
||
## 组件库清单
|
||
|
||
### 必须实现的组件
|
||
|
||
#### 1. 基础组件
|
||
|
||
- [ ] Button(按钮)
|
||
- [ ] Input(输入框)
|
||
- [ ] Select(选择器)
|
||
- [ ] Checkbox(复选框)
|
||
- [ ] Radio(单选框)
|
||
- [ ] Switch(开关)
|
||
- [ ] DatePicker(日期选择器)
|
||
|
||
#### 2. 容器组件
|
||
|
||
- [ ] Card(卡片)
|
||
- [ ] Modal(模态框)
|
||
- [ ] Drawer(抽屉)
|
||
- [ ] Tabs(标签页)
|
||
- [ ] Collapse(折叠面板)
|
||
|
||
#### 3. 数据展示
|
||
|
||
- [ ] Table(表格)
|
||
- [ ] List(列表)
|
||
- [ ] Pagination(分页)
|
||
- [ ] Tree(树形控件)
|
||
- [ ] Empty(空状态)
|
||
|
||
#### 4. 表单组件
|
||
|
||
- [ ] Form(表单)
|
||
- [ ] Upload(上传)
|
||
- [ ] SearchForm(搜索表单)
|
||
- [ ] Filter(高级筛选)
|
||
|
||
#### 5. 反馈组件
|
||
|
||
- [ ] Message(消息)
|
||
- [ ] Toast(提示)
|
||
- [ ] Confirm(确认框)
|
||
- [ ] Loading(加载中)
|
||
|
||
#### 6. 导航组件
|
||
|
||
- [ ] Menu(菜单)
|
||
- [ ] Breadcrumb(面包屑)
|
||
- [ ] Tabs(标签)
|
||
- [ ] Pagination(分页)
|
||
|
||
---
|
||
|
||
## 迁移检查清单
|
||
|
||
### Phase 1: 基础设施
|
||
|
||
- [ ] 创建样式系统文件
|
||
- [ ] uni.scss(全局变量)
|
||
- [ ] styles/common.scss(通用类)
|
||
- [ ] styles/animate.scss(动画)
|
||
|
||
- [ ] 更新 AdminLayout 支持多布局
|
||
- [ ] Defaults 布局
|
||
- [ ] Classic 布局
|
||
- [ ] Columns 布局
|
||
|
||
- [ ] 配置工程化工具
|
||
- [ ] .eslintrc 配置
|
||
- [ ] .prettierrc 配置
|
||
- [ ] tsconfig.json 优化
|
||
|
||
### Phase 2: 核心组件
|
||
|
||
- [ ] 实现基础 UI 组件库
|
||
- [ ] 实现 FormView 表单组件
|
||
- [ ] 实现 TableView 表格组件
|
||
- [ ] 实现 SearchForm 搜索组件
|
||
|
||
### Phase 3: 页面模板
|
||
|
||
- [ ] 创建列表页面模板
|
||
- [ ] 创建表单页面模板
|
||
- [ ] 创建详情页面模板
|
||
- [ ] 创建仪表板页面模板
|
||
|
||
### Phase 4: 样式规范化
|
||
|
||
- [ ] 统一所有页面的样式
|
||
- [ ] 规范间距使用
|
||
- [ ] 规范颜色使用
|
||
- [ ] 规范排版样式
|
||
|
||
### Phase 5: 文档完善
|
||
|
||
- [ ] 编写组件使用文档
|
||
- [ ] 编写样式规范文档
|
||
- [ ] 编写页面开发指南
|
||
- [ ] 维护变更日志
|
||
|
||
---
|
||
|
||
## 推荐阅读
|
||
|
||
- [ADMIN_SIDEBAR_COMPLETE_GUIDE.md](ADMIN_SIDEBAR_COMPLETE_GUIDE.md) - 侧边栏完整指南
|
||
- [CRMEB_DASHBOARD_GUIDE.md](CRMEB_DASHBOARD_GUIDE.md) - 仪表板设计指南
|
||
- [UNI_APP_X_PAGE_FIX_GUIDE.md](UNI_APP_X_PAGE_FIX_GUIDE.md) - uni-app-x 页面修复指南
|
||
|
||
---
|
||
|
||
**文档维护者**: AI Assistant
|
||
**最后更新**: 2026-01-31
|
||
**版本**: 1.0
|