Files
tjt_czjs_backend/doc/前端开发文档.md

1465 lines
28 KiB
Markdown
Raw Normal View History

2026-01-19 18:54:03 +08:00
# Lyzsys 前端开发文档
## 目录
- [项目概述](#项目概述)
- [技术栈](#技术栈)
- [项目结构](#项目结构)
- [开发指南](#开发指南)
- [核心功能](#核心功能)
- [组件库](#组件库)
- [样式指南](#样式指南)
- [部署指南](#部署指南)
---
## 项目概述
Lyzsys 前端是基于 Vue 3 + TypeScript + Element Plus 构建的现代化管理系统,采用 Composition API 和模块化架构,支持多租户、权限管理、国际化等功能。
### 核心特性
- **Vue 3 Composition API**: 充分利用 Vue 3 的新特性
- **TypeScript**: 完整的类型支持
- **Vite 构建**: 极速的开发体验
- **Element Plus**: 企业级 UI 组件库
- **权限管理**: 基于 RBAC 的权限控制
- **国际化**: 支持多语言切换
- **主题定制**: 灵活的主题配置
---
## 技术栈
### 核心框架
| 技术 | 版本 | 说明 |
|------|------|------|
| Vue | 3.2+ | 渐进式 JavaScript 框架 |
| TypeScript | 4.x | JavaScript 的超集 |
| Vite | 4.x | 下一代前端构建工具 |
| Vue Router | 4.x | Vue.js 官方路由管理器 |
| Pinia | 2.x | Vue 官方状态管理库 |
### UI 框架
| 技术 | 版本 | 说明 |
|------|------|------|
| Element Plus | 2.x | 基于 Vue 3 的组件库 |
| UnoCSS | - | 原子化 CSS 引擎 |
| Animate.css | - | CSS 动画库 |
| Iconify | - | 统一的图标框架 |
### 工具库
| 技术 | 版本 | 说明 |
|------|------|------|
| Axios | - | HTTP 客户端 |
| Day.js | - | 轻量级日期处理库 |
| Lodash | - | JavaScript 实用工具库 |
| Crypto-js | - | JavaScript 加密库 |
| DOMPurify | - | XSS 过滤器 |
| WangEditor | - | 富文本编辑器 |
| ECharts | - | 数据可视化库 |
### 开发工具
| 技术 | 版本 | 说明 |
|------|------|------|
| ESLint | - | 代码检查工具 |
| Prettier | - | 代码格式化工具 |
| Stylelint | - | CSS 代码检查工具 |
| Commitlint | - | Git 提交信息检查 |
| unplugin-auto-import | - | 自动导入 API |
| unplugin-vue-components | - | 自动导入组件 |
---
## 项目结构
### 目录结构
```
lyzsys-ui-admin/
├── .github/ # GitHub Actions 配置
├── .husky/ # Git Hooks 配置
├── .vscode/ # VSCode 配置
├── public/ # 静态资源
├── src/ # 源代码
│ ├── api/ # API 接口管理
│ │ ├── ai/ # AI 相关接口
│ │ ├── bpm/ # 工作流接口
│ │ ├── crm/ # CRM 接口
│ │ ├── erp/ # ERP 接口
│ │ ├── system/ # 系统管理接口
│ │ └── login/ # 登录接口
│ ├── assets/ # 静态资源
│ │ ├── images/ # 图片
│ │ ├── styles/ # 样式文件
│ │ └── svg/ # SVG 图标
│ ├── components/ # 全局组件
│ ├── config/ # 全局配置
│ ├── directives/ # 自定义指令
│ ├── hooks/ # 组合式函数
│ ├── layout/ # 布局组件
│ ├── locales/ # 国际化文件
│ │ ├── en/ # 英文
│ │ └── zh-CN/ # 简体中文
│ ├── plugins/ # 插件配置
│ ├── router/ # 路由配置
│ ├── store/ # 状态管理
│ │ ├── modules/ # 模块化 Store
│ │ └── index.ts # Store 入口
│ ├── styles/ # 全局样式
│ ├── types/ # TypeScript 类型定义
│ ├── utils/ # 工具函数
│ ├── views/ # 页面组件
│ ├── App.vue # 应用根组件
│ ├── main.ts # 应用入口
│ └── permission.ts # 路由权限控制
├── types/ # 全局类型定义
├── .env.base # 基础环境变量
├── .env.dev # 开发环境变量
├── .env.pro # 生产环境变量
├── .env.test # 测试环境变量
├── .eslintrc.js # ESLint 配置
├── .gitignore # Git 忽略文件
├── .prettierrc.js # Prettier 配置
├── index.html # HTML 模板
├── package.json # 项目依赖
├── tsconfig.json # TypeScript 配置
└── vite.config.ts # Vite 配置
```
### 核心文件说明
#### main.ts
应用入口文件,负责初始化 Vue 应用:
```typescript
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import { setupStore } from './store'
import { setupRouter } from './router'
import { setupElPlus, setupIcons } from './plugins'
async function bootstrap() {
const app = createApp(App)
// 配置 Store
setupStore(app)
// 配置 Router
await setupRouter(app)
// 配置插件
setupElPlus(app)
setupIcons(app)
// 挂载应用
app.mount('#app')
}
bootstrap()
```
#### App.vue
应用根组件:
```vue
<template>
<ConfigProvider :locale="getLocale">
<router-view />
</ConfigProvider>
</template>
<script setup lang="ts">
import { ConfigProvider } from 'element-plus'
import { useLocale } from './locales/useLocale'
import { getLocale } from './locales/getLocale'
</script>
```
#### permission.ts
路由权限控制:
```typescript
import router from './router'
import { useUserStore } from './store/modules/user'
import { usePermissionStore } from './store/modules/permission'
router.beforeEach(async (to, from, next) => {
const userStore = useUserStore()
const permissionStore = usePermissionStore()
// 检查是否登录
if (userStore.getToken) {
// 已登录
if (to.path === '/login') {
next({ path: '/' })
} else {
// 检查是否已获取权限
if (permissionStore.getIsAddRouters) {
next()
} else {
// 获取权限和路由
await permissionStore.generateRoutes()
next({ ...to, replace: true })
}
}
} else {
// 未登录
if (to.path === '/login') {
next()
} else {
next(`/login?redirect=${to.path}`)
}
}
})
```
---
## 开发指南
### 环境准备
#### 必需软件
| 软件 | 版本要求 | 下载地址 |
|------|----------|----------|
| Node.js | 16+ | https://nodejs.org/ |
| pnpm | 8+ | https://pnpm.io/ |
| VSCode | 最新版 | https://code.visualstudio.com/ |
#### 推荐插件
- Vue - Official
- TypeScript Vue Plugin (Volar)
- ESLint
- Prettier - Code formatter
- Stylelint
- UnoCSS
### 快速开始
#### 1. 克隆项目
```bash
git clone https://github.com/your-org/lyzsys.git
cd lyzsys/lyzsys-ui-admin
```
#### 2. 安装依赖
```bash
pnpm install
```
#### 3. 启动开发服务器
```bash
pnpm dev
```
#### 4. 访问应用
- 应用地址: http://localhost:5173
- 用户名: admin
- 密码: admin123
### 开发规范
#### 命名规范
**文件命名**:
- 组件文件:大驼峰 `UserList.vue`
- 工具文件:小驼峰 `formatDate.ts`
- 样式文件:小驼峰 `userList.scss`
**变量命名**:
```typescript
// 常量:全大写
const MAX_SIZE = 100
// 变量:小驼峰
const userName = 'admin'
// 接口:大驼峰
interface UserInfo {
id: number
name: string
}
// 类型:大驼峰
type UserRole = 'admin' | 'user'
// 枚举:大驼峰
enum UserStatus {
Active = 'active',
Inactive = 'inactive'
}
```
**组件命名**:
```vue
<script setup lang="ts">
// 组件名:大驼峰
defineOptions({
name: 'UserList'
})
</script>
```
#### 注释规范
**函数注释**:
```typescript
/**
* 获取用户列表
* @param params 查询参数
* @returns 用户列表
*/
async function getUserList(params: UserPageReqVO) {
return await userApi.getUserPage(params)
}
```
**组件注释**:
```vue
<!--
@description 用户列表组件
@author Lyzsys Team
-->
<template>
<!-- ... -->
</template>
```
#### 代码风格
**使用 Composition API**:
```vue
<script setup lang="ts">
import { ref, computed, onMounted } from 'vue'
// 响应式数据
const loading = ref(false)
const userList = ref<User[]>([])
// 计算属性
const totalCount = computed(() => userList.value.length)
// 方法
async function fetchUsers() {
loading.value = true
try {
userList.value = await userApi.getUserList()
} finally {
loading.value = false
}
}
// 生命周期
onMounted(() => {
fetchUsers()
})
</script>
```
**使用 TypeScript**:
```typescript
interface User {
id: number
name: string
email: string
}
type UserRole = 'admin' | 'user' | 'guest'
const user: User = {
id: 1,
name: 'Admin',
email: 'admin@example.com'
}
const role: UserRole = 'admin'
```
### 组件开发
#### 创建组件
```vue
<!-- components/UserList.vue -->
<template>
<div class="user-list">
<el-table :data="userList" :loading="loading">
<el-table-column prop="name" label="姓名" />
<el-table-column prop="email" label="邮箱" />
<el-table-column label="操作">
<template #default="{ row }">
<el-button link @click="handleEdit(row)">编辑</el-button>
<el-button link @click="handleDelete(row)">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { ElMessage } from 'element-plus'
interface User {
id: number
name: string
email: string
}
defineOptions({
name: 'UserList'
})
const loading = ref(false)
const userList = ref<User[]>([])
async function fetchUsers() {
loading.value = true
try {
const { data } = await userApi.getUserList()
userList.value = data
} finally {
loading.value = false
}
}
function handleEdit(user: User) {
console.log('编辑用户', user)
}
function handleDelete(user: User) {
console.log('删除用户', user)
}
onMounted(() => {
fetchUsers()
})
</script>
<style scoped lang="scss">
.user-list {
padding: 20px;
}
</style>
```
#### 组件通信
**Props**:
```vue
<script setup lang="ts">
interface Props {
userId: number
userName?: string
}
const props = withDefaults(defineProps<Props>(), {
userName: ''
})
</script>
```
**Emits**:
```vue
<script setup lang="ts">
interface Emits {
(e: 'update:modelValue', value: string): void
(e: 'change', value: string): void
}
const emit = defineEmits<Emits>()
function handleChange(value: string) {
emit('update:modelValue', value)
emit('change', value)
}
</script>
```
**Slots**:
```vue
<template>
<div class="card">
<slot name="header">
<h3>默认标题</h3>
</slot>
<slot>
默认内容
</slot>
<slot name="footer">
<el-button>确定</el-button>
</slot>
</div>
</template>
```
### API 开发
#### API 定义
```typescript
// api/system/user/index.ts
import request from '@/utils/request'
// 获取用户分页
export function getUserPage(params: UserPageReqVO) {
return request.get({ url: '/system/user/page', params })
}
// 获取用户详情
export function getUser(id: number) {
return request.get({ url: `/system/user/get?id=${id}` })
}
// 创建用户
export function createUser(data: UserCreateReqVO) {
return request.post({ url: '/system/user/create', data })
}
// 更新用户
export function updateUser(data: UserUpdateReqVO) {
return request.put({ url: '/system/user/update', data })
}
// 删除用户
export function deleteUser(id: number) {
return request.delete({ url: `/system/user/delete?id=${id}` })
}
```
#### API 调用
```vue
<script setup lang="ts">
import { ref } from 'vue'
import { getUserPage } from '@/api/system/user'
const loading = ref(false)
const userList = ref([])
async function fetchUsers() {
loading.value = true
try {
const { data } = await getUserPage({
pageNo: 1,
pageSize: 10
})
userList.value = data.list
} finally {
loading.value = false
}
}
</script>
```
### 路由开发
#### 路由配置
```typescript
// router/modules/system.ts
import type { AppRouteModule } from '@/router/types'
const system: AppRouteModule = {
path: '/system',
name: 'System',
component: 'LAYOUT',
redirect: '/system/user',
meta: {
title: '系统管理',
icon: 'system',
orderNo: 1000
},
children: [
{
path: 'user',
name: 'SystemUser',
component: () => import('@/views/system/user/index.vue'),
meta: {
title: '用户管理',
icon: 'user',
noCache: true
}
},
{
path: 'role',
name: 'SystemRole',
component: () => import('@/views/system/role/index.vue'),
meta: {
title: '角色管理',
icon: 'role',
noCache: true
}
}
]
}
export default system
```
#### 路由跳转
```typescript
import { useRouter } from 'vue-router'
const router = useRouter()
// 路径跳转
router.push('/system/user')
// 命名路由跳转
router.push({ name: 'SystemUser' })
// 带参数跳转
router.push({
path: '/system/user',
query: { id: 1 }
})
// 替换当前路由
router.replace('/system/user')
// 后退
router.back()
// 前进
router.forward()
```
### 状态管理
#### Store 定义
```typescript
// store/modules/user.ts
import { defineStore } from 'pinia'
import { getUserInfo, login } from '@/api/system/user'
interface UserState {
token: string
userInfo: UserInfo | null
}
export const useUserStore = defineStore('user', {
state: (): UserState => ({
token: '',
userInfo: null
}),
getters: {
getToken: (state) => state.token,
getUserInfo: (state) => state.userInfo
},
actions: {
setToken(token: string) {
this.token = token
},
async login(params: LoginReqVO) {
const { data } = await login(params)
this.setToken(data.token)
},
async getUserInfoAction() {
const { data } = await getUserInfo()
this.userInfo = data
},
async logout() {
this.token = ''
this.userInfo = null
}
},
persist: {
key: 'user-store',
storage: localStorage
}
})
```
#### Store 使用
```vue
<script setup lang="ts">
import { useUserStore } from '@/store/modules/user'
const userStore = useUserStore()
// 访问 state
console.log(userStore.token)
// 访问 getters
console.log(userStore.getToken)
// 调用 actions
await userStore.login({
username: 'admin',
password: 'admin123'
})
// 重置 state
userStore.$reset()
</script>
```
---
## 核心功能
### 权限管理
#### 权限指令
```vue
<template>
<!-- 有权限时显示 -->
<el-button v-hasPermi="['system:user:create']">创建用户</el-button>
<!-- 有角色时显示 -->
<el-button v-hasRole="['admin']">管理员操作</el-button>
<!-- 同时满足多个权限 -->
<el-button v-hasPermi="['system:user:update', 'system:user:delete']">
操作
</el-button>
</template>
```
#### 权限函数
```typescript
import { usePermission } from '@/hooks/web/usePermission'
const { hasPermission, hasRole } = usePermission()
// 检查权限
if (hasPermission(['system:user:create'])) {
// 有权限
}
// 检查角色
if (hasRole(['admin'])) {
// 是管理员
}
```
### 国际化
#### 使用翻译
```vue
<template>
<!-- 使用翻译 -->
<h1>{{ $t('common.title') }}</h1>
<!-- 带参数的翻译 -->
<p>{{ $t('common.welcome', { name: 'Admin' }) }}</p>
</template>
<script setup lang="ts">
import { useI18n } from '@/hooks/web/useI18n'
const { t } = useI18n()
// 使用翻译
const message = t('common.title')
const welcome = t('common.welcome', { name: 'Admin' })
</script>
```
#### 添加翻译
```typescript
// locales/zh-CN/common.ts
export default {
title: 'Lyzsys 管理系统',
welcome: '欢迎,{name}',
logout: '退出登录'
}
```
```typescript
// locales/en/common.ts
export default {
title: 'Lyzsys Admin',
welcome: 'Welcome, {name}',
logout: 'Logout'
}
```
### 主题定制
#### 修改主题色
```typescript
// styles/variables.scss
$primary-color: #409eff;
$success-color: #67c23a;
$warning-color: #e6a23c;
$danger-color: #f56c6c;
$error-color: #f56c6c;
```
#### 动态切换主题
```vue
<script setup lang="ts">
import { useAppStore } from '@/store/modules/app'
const appStore = useAppStore()
// 切换暗黑模式
function toggleDarkMode() {
appStore.setDarkMode(!appStore.getDarkMode)
}
</script>
```
### 文件上传
#### 单文件上传
```vue
<template>
<el-upload
:action="uploadUrl"
:headers="uploadHeaders"
:on-success="handleSuccess"
:before-upload="beforeUpload"
>
<el-button type="primary">上传文件</el-button>
</el-upload>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { ElMessage } from 'element-plus'
import { getAccessToken } from '@/utils/auth'
const uploadUrl = import.meta.env.VITE_BASE_URL + '/admin-api/infra/file/upload'
const uploadHeaders = ref({
Authorization: 'Bearer ' + getAccessToken()
})
function beforeUpload(file: File) {
const isLt2M = file.size / 1024 / 1024 < 2
if (!isLt2M) {
ElMessage.error('上传文件大小不能超过 2MB!')
}
return isLt2M
}
function handleSuccess(response: any) {
if (response.code === 0) {
ElMessage.success('上传成功')
console.log('文件 URL:', response.data)
} else {
ElMessage.error(response.msg)
}
}
</script>
```
#### 多文件上传
```vue
<template>
<el-upload
:action="uploadUrl"
:headers="uploadHeaders"
multiple
:limit="3"
:on-exceed="handleExceed"
:on-success="handleSuccess"
>
<el-button type="primary">多文件上传</el-button>
</el-upload>
</template>
<script setup lang="ts">
function handleExceed() {
ElMessage.warning('最多只能上传 3 个文件')
}
</script>
```
### 表单验证
#### 表单定义
```vue
<template>
<el-form
ref="formRef"
:model="form"
:rules="rules"
label-width="100px"
>
<el-form-item label="用户名" prop="username">
<el-input v-model="form.username" placeholder="请输入用户名" />
</el-form-item>
<el-form-item label="邮箱" prop="email">
<el-input v-model="form.email" placeholder="请输入邮箱" />
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input
v-model="form.password"
type="password"
placeholder="请输入密码"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleSubmit">提交</el-button>
<el-button @click="handleReset">重置</el-button>
</el-form-item>
</el-form>
</template>
<script setup lang="ts">
import { ref, reactive } from 'vue'
import type { FormInstance, FormRules } from 'element-plus'
const formRef = ref<FormInstance>()
const form = reactive({
username: '',
email: '',
password: ''
})
const rules: FormRules = {
username: [
{ required: true, message: '请输入用户名', trigger: 'blur' },
{ min: 3, max: 20, message: '长度在 3 到 20 个字符', trigger: 'blur' }
],
email: [
{ required: true, message: '请输入邮箱', trigger: 'blur' },
{ type: 'email', message: '请输入正确的邮箱地址', trigger: 'blur' }
],
password: [
{ required: true, message: '请输入密码', trigger: 'blur' },
{ min: 6, max: 20, message: '长度在 6 到 20 个字符', trigger: 'blur' }
]
}
async function handleSubmit() {
if (!formRef.value) return
await formRef.value.validate((valid) => {
if (valid) {
console.log('表单数据:', form)
// 提交表单
}
})
}
function handleReset() {
formRef.value?.resetFields()
}
</script>
```
### 表格操作
#### 基础表格
```vue
<template>
<el-table :data="tableData" :loading="loading" border>
<el-table-column prop="id" label="ID" width="80" />
<el-table-column prop="username" label="用户名" />
<el-table-column prop="email" label="邮箱" />
<el-table-column prop="status" label="状态">
<template #default="{ row }">
<el-tag :type="row.status === 'active' ? 'success' : 'danger'">
{{ row.status === 'active' ? '激活' : '禁用' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="200" fixed="right">
<template #default="{ row }">
<el-button link @click="handleEdit(row)">编辑</el-button>
<el-button link @click="handleDelete(row)">删除</el-button>
</template>
</el-table-column>
</el-table>
</template>
<script setup lang="ts">
import { ref } from 'vue'
interface User {
id: number
username: string
email: string
status: string
}
const loading = ref(false)
const tableData = ref<User[]>([])
function handleEdit(user: User) {
console.log('编辑用户', user)
}
function handleDelete(user: User) {
console.log('删除用户', user)
}
</script>
```
#### 分页表格
```vue
<template>
<div>
<el-table :data="tableData" :loading="loading" border>
<!-- 表格列 -->
</el-table>
<el-pagination
v-model:current-page="queryParams.pageNo"
v-model:page-size="queryParams.pageSize"
:total="total"
:page-sizes="[10, 20, 50, 100]"
layout="total, sizes, prev, pager, next, jumper"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
</template>
<script setup lang="ts">
import { ref, reactive } from 'vue'
const loading = ref(false)
const tableData = ref([])
const total = ref(0)
const queryParams = reactive({
pageNo: 1,
pageSize: 10
})
async function fetchTableData() {
loading.value = true
try {
const { data } = await userApi.getUserPage(queryParams)
tableData.value = data.list
total.value = data.total
} finally {
loading.value = false
}
}
function handleSizeChange() {
fetchTableData()
}
function handleCurrentChange() {
fetchTableData()
}
// 初始加载
fetchTableData()
</script>
```
---
## 组件库
### Element Plus
#### 按钮
```vue
<el-button>默认按钮</el-button>
<el-button type="primary">主要按钮</el-button>
<el-button type="success">成功按钮</el-button>
<el-button type="warning">警告按钮</el-button>
<el-button type="danger">危险按钮</el-button>
<el-button link>文字按钮</el-button>
```
#### 表单
```vue
<el-input v-model="value" placeholder="请输入内容" />
<el-input v-model="value" type="textarea" />
<el-input v-model="value" type="password" />
```
#### 选择器
```vue
<el-select v-model="value" placeholder="请选择">
<el-option label="选项1" value="1" />
<el-option label="选项2" value="2" />
</el-select>
```
#### 日期选择器
```vue
<el-date-picker
v-model="value"
type="date"
placeholder="选择日期"
/>
<el-date-picker
v-model="value"
type="daterange"
start-placeholder="开始日期"
end-placeholder="结束日期"
/>
```
#### 对话框
```vue
<el-dialog v-model="visible" title="提示" width="30%">
<span>这是一段内容</span>
<template #footer>
<el-button @click="visible = false">取消</el-button>
<el-button type="primary" @click="visible = false">确定</el-button>
</template>
</el-dialog>
```
#### 消息提示
```typescript
import { ElMessage, ElMessageBox, ElNotification } from 'element-plus'
// 消息提示
ElMessage.success('操作成功')
ElMessage.warning('警告消息')
ElMessage.error('错误消息')
ElMessage.info('提示消息')
// 确认框
ElMessageBox.confirm('确定要删除吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
.then(() => {
ElMessage.success('删除成功')
})
.catch(() => {
ElMessage.info('已取消删除')
})
// 通知
ElNotification({
title: '通知',
message: '这是一条通知消息',
type: 'success'
})
```
### 自定义组件
#### 图表组件 (ECharts)
```vue
<template>
<div ref="chartRef" style="width: 100%; height: 400px"></div>
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue'
import * as echarts from 'echarts'
import type { EChartsOption } from 'echarts'
const chartRef = ref<HTMLDivElement>()
let chartInstance: echarts.ECharts | null = null
onMounted(() => {
if (chartRef.value) {
chartInstance = echarts.init(chartRef.value)
const option: EChartsOption = {
title: {
text: '示例图表'
},
xAxis: {
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
},
yAxis: {},
series: [
{
type: 'line',
data: [150, 230, 224, 218, 135, 147, 260]
}
]
}
chartInstance.setOption(option)
}
})
onUnmounted(() => {
chartInstance?.dispose()
})
</script>
```
#### 富文本编辑器 (WangEditor)
```vue
<template>
<div ref="editorRef" style="height: 500px"></div>
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue'
import { createEditor, createToolbar } from '@wangeditor/editor-for-vue'
const editorRef = ref<HTMLDivElement>()
let editor: any = null
let toolbar: any = null
onMounted(() => {
if (editorRef.value) {
editor = createEditor({
selector: editorRef.value,
html: '<p>默认内容</p>',
config: {}
})
toolbar = createToolbar({
editor,
config: {}
})
}
})
onUnmounted(() => {
editor?.destroy()
toolbar?.destroy()
})
</script>
```
---
## 样式指南
### CSS 预处理器
使用 SCSS 作为 CSS 预处理器:
```scss
// 使用变量
$primary-color: #409eff;
$border-radius: 4px;
// 使用嵌套
.button {
background: $primary-color;
border-radius: $border-radius;
&:hover {
background: darken($primary-color, 10%);
}
&.active {
background: lighten($primary-color, 10%);
}
}
```
### UnoCSS
使用原子化 CSS
```vue
<template>
<div class="flex items-center justify-center h-screen bg-gray-100">
<div class="p-6 bg-white rounded-lg shadow-lg">
<h1 class="text-2xl font-bold text-gray-800">标题</h1>
<p class="mt-4 text-gray-600">内容</p>
</div>
</div>
</template>
```
### 响应式设计
```scss
// 使用媒体查询
.container {
padding: 20px;
@media (max-width: 768px) {
padding: 10px;
}
@media (max-width: 480px) {
padding: 5px;
}
}
```
### 主题定制
```scss
// 自定义主题色
:root {
--el-color-primary: #409eff;
--el-color-success: #67c23a;
--el-color-warning: #e6a23c;
--el-color-danger: #f56c6c;
}
// 暗黑模式
.dark {
--el-bg-color: #1a1a1a;
--el-text-color-primary: #ffffff;
}
```
---
## 部署指南
### 本地构建
```bash
# 开发环境构建
pnpm build:dev
# 生产环境构建
pnpm build:prod
# 测试环境构建
pnpm build:test
```
### 环境变量配置
```bash
# .env.base
VITE_BASE_URL=/api
# .env.dev
VITE_BASE_URL=http://localhost:48080
# .env.prod
VITE_BASE_URL=https://api.example.com
```
### Docker 部署
#### 1. 构建镜像
```bash
docker build -t lyzsys/lyzsys-ui-admin:latest .
```
#### 2. 运行容器
```bash
docker run -d \
--name lyzsys-ui-admin \
-p 80:80 \
lyzsys/lyzsys-ui-admin:latest
```
### Nginx 配置
```nginx
server {
listen 80;
server_name example.com;
root /usr/share/nginx/html;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
location /api {
proxy_pass http://backend:48080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
gzip on;
gzip_types text/plain text/css application/json application/javascript;
}
```
---
## 附录
### 常见问题
#### Q1: 如何添加新页面?
1.`views/` 目录下创建页面组件
2.`router/modules/` 中配置路由
3. 添加国际化翻译(如需要)
4. 在后台系统中配置菜单权限
#### Q2: 如何调用后端 API
1.`api/` 目录下创建 API 文件
2. 定义 API 接口函数
3. 在组件中导入并调用
4. 处理响应数据
#### Q3: 如何实现权限控制?
1. 使用 `v-hasPermi` 指令控制按钮显示
2. 使用 `v-hasRole` 指令控制角色访问
3. 在路由配置中设置权限 meta
4. 后端接口进行权限验证
#### Q4: 如何切换语言?
1.`locales/` 目录下添加语言文件
2. 使用 `$t()` 函数进行翻译
3. 在语言切换器中调用 `setLocale()` 方法
### 参考资源
- [Vue 3 官方文档](https://cn.vuejs.org/)
- [TypeScript 官方文档](https://www.typescriptlang.org/zh/)
- [Vite 官方文档](https://cn.vitejs.dev/)
- [Element Plus 官方文档](https://element-plus.org/zh-CN/)
- [Pinia 官方文档](https://pinia.vuejs.org/zh/)
- [UnoCSS 官方文档](https://unocss.dev/)
---
**文档版本**: v1.0.0
**最后更新**: 2025-01-19
**维护团队**: Lyzsys 开发团队