本项目是基于 Vue3 + TypeScript + Vite + Element Plus 的前端管理系统,采用前后端分离架构,提供完整的权限管理、CRUD操作等功能。
git clone <repository-url>
cd zheda
使用 npm:
npm install
或使用 yarn:
yarn install
或使用国内镜像加速:
npm install --registry=https://registry.npm.taobao.org
在项目根目录创建环境变量文件(根据实际需要选择):
开发环境 (.env.development):
# 开发服务器端口
VITE_PORT=8080
# API 基础路径
VITE_API_URL=http://localhost:8000/api/
# 公共路径(开发环境通常为 ./)
VITE_PUBLIC_PATH=./
# 构建输出目录
VITE_DIST_PATH=dist
生产环境 (.env.production):
# API 基础路径(生产环境)
VITE_API_URL=https://your-api-domain.com/api/
# 公共路径(根据部署路径配置,如:/ 或 /admin/)
VITE_PUBLIC_PATH=/
# 构建输出目录
VITE_DIST_PATH=dist
本地生产环境 (.env.local_prod):
# 本地生产环境配置
VITE_API_URL=http://localhost:8000/api/
VITE_PUBLIC_PATH=/
VITE_DIST_PATH=dist
npm run dev
或
yarn dev
开发服务器启动后,访问: http://localhost:8080 (端口可在环境变量中配置)
zheda/
├── public/ # 静态资源目录(不会被 Vite 处理,直接复制到 dist)
│ ├── favicon.ico # 网站图标
│ ├── favicon1.ico # 备用图标
│ ├── favicon2.ico # 备用图标
│ └── version-build # 版本构建文件(自动生成)
├── src/ # 源代码目录
│ ├── api/ # API 接口定义
│ │ ├── login/ # 登录相关接口
│ │ │ └── index.ts # 登录 API
│ │ ├── menu/ # 菜单相关接口
│ │ └── system/ # 系统相关接口
│ │ ├── loginBackground.ts
│ │ └── ...
│ ├── assets/ # 静态资源(图片、样式等)
│ │ ├── style/ # 全局样式文件
│ │ ├── iconfont/ # 图标字体文件
│ │ └── *.png|jpg|svg # 图片资源
│ ├── components/ # 公共组件(可复用的 Vue 组件)
│ ├── directive/ # 自定义指令(Vue 指令)
│ ├── i18n/ # 国际化配置(多语言支持)
│ ├── layout/ # 布局组件(页面布局结构)
│ ├── plugin/ # 插件配置(第三方插件初始化)
│ │ └── permission/ # 权限插件
│ ├── router/ # 路由配置
│ │ ├── index.ts # 路由入口(路由实例和守卫)
│ │ ├── backEnd.ts # 后端控制路由逻辑
│ │ ├── frontEnd.ts # 前端控制路由逻辑
│ │ └── route.ts # 路由定义(静态路由)
│ ├── stores/ # Pinia 状态管理
│ │ ├── index.ts # Store 入口
│ │ ├── userInfo.ts # 用户信息 Store
│ │ ├── routesList.ts # 路由列表 Store
│ │ ├── btnPermission.ts # 按钮权限 Store
│ │ ├── columnPermission.ts # 列权限 Store
│ │ ├── themeConfig.ts # 主题配置 Store
│ │ └── ... # 其他 Store
│ ├── theme/ # 主题样式(颜色、布局等)
│ ├── types/ # TypeScript 类型定义
│ │ └── global.d.ts # 全局类型声明
│ ├── utils/ # 工具函数
│ │ ├── baseUrl.ts # 基础URL处理(API地址管理)
│ │ ├── service.ts # HTTP请求封装(Axios封装)
│ │ ├── storage.ts # 本地存储封装(LocalStorage/SessionStorage)
│ │ ├── authFunction.ts # 权限验证函数
│ │ ├── message.ts # 消息提示封装
│ │ ├── dictionary.ts # 字典数据管理
│ │ ├── upgrade.ts # 版本升级检查
│ │ └── ... # 其他工具函数
│ ├── views/ # 页面组件(业务页面)
│ │ └── system/ # 系统管理模块
│ │ └── company/ # 公司管理
│ │ ├── crud.tsx # CRUD 配置
│ │ ├── api.ts # API 接口
│ │ └── index.vue # 页面组件
│ ├── App.vue # 根组件(应用入口组件)
│ ├── main.ts # 入口文件(应用初始化)
│ └── settings.ts # Fast-Crud 配置(CRUD框架配置)
├── dist/ # 构建输出目录(生产环境,gitignore)
├── node_modules/ # 依赖包目录(gitignore)
├── index.html # HTML 模板
├── package.json # 项目依赖配置
├── package-lock.json # 依赖锁定文件
├── yarn.lock # Yarn 依赖锁定文件(如果使用 Yarn)
├── tsconfig.json # TypeScript 配置
├── vite.config.ts # Vite 构建配置
├── tailwind.config.js # Tailwind CSS 配置
├── postcss.config.js # PostCSS 配置
├── .env.development # 开发环境变量(需要创建)
├── .env.production # 生产环境变量(需要创建)
├── .env.local_prod # 本地生产环境变量(需要创建)
├── .gitignore # Git 忽略文件配置
├── README.md # 项目说明文档
├── DEVELOPMENT.md # 开发文档(本文档)
└── DEPLOYMENT.md # 部署文档
/src/api/ - API 接口层api.ts 文件request 方法进行请求src/views/system/company/api.ts/src/stores/ - 状态管理userInfo.ts: 用户信息(登录状态、用户数据)routesList.ts: 路由列表(动态路由)btnPermission.ts: 按钮权限列表themeConfig.ts: 主题配置(布局、颜色等)使用方式:
import { useUserInfo } from '/@/stores/userInfo';
const { userInfos } = storeToRefs(useUserInfo());
/src/utils/ - 工具函数service.ts: HTTP 请求封装,包含请求/响应拦截器storage.ts: 本地存储封装(LocalStorage/SessionStorage)authFunction.ts: 权限验证函数(auth、auths、authAll)baseUrl.ts: API 基础地址管理message.ts: 消息提示封装dictionary.ts: 字典数据管理/src/router/ - 路由系统createWebHashHistory)/src/views/ - 页面组件system/company/crud.tsx项目使用 ESLint 进行代码检查,建议在提交代码前运行:
npm run lint-fix
src/views/ 目录下创建页面组件src/router/ 中添加路由配置src/views/system/company/crud.tsx 的实现方式在 src/api/ 或对应业务模块目录下创建 API 文件,例如 src/views/system/company/api.ts:
import { request } from '/@/utils/service';
import { UserPageQuery, AddReq, DelReq, EditReq, InfoReq } from '@fast-crud/fast-crud';
// API 前缀(统一管理)
export const apiPrefix = '/api/platform-admin/tenants/';
// 获取列表(分页查询)
export function GetList(query: UserPageQuery) {
return request({
url: apiPrefix,
method: 'get',
params: query,
});
}
// 获取详情
export function GetObj(id: InfoReq) {
return request({
url: apiPrefix + id,
method: 'get',
});
}
// 新增
export function AddObj(obj: AddReq) {
return request({
url: apiPrefix,
method: 'post',
data: obj,
});
}
// 更新
export function UpdateObj(obj: EditReq) {
return request({
url: apiPrefix + obj.id + '/',
method: 'put',
data: obj,
});
}
// 删除
export function DelObj(id: DelReq) {
return request({
url: apiPrefix + id + '/',
method: 'delete',
data: { id },
});
}
// 自定义接口示例
export function updateTenantStatus(id: string, status: number) {
return request({
url: `${apiPrefix}${id}/activate/`,
method: 'post',
data: { status },
});
}
import { GetList, AddObj, UpdateObj, DelObj } from './api';
// 在 setup 函数中使用
const loadData = async () => {
try {
const res = await GetList({ page: 1, limit: 10 });
console.log(res.data);
} catch (error) {
console.error('加载数据失败', error);
}
};
请求拦截器 (src/utils/service.ts):
Authorization 头(从 SessionStorage 获取 token)baseURL(从环境变量获取)响应拦截器:
请求配置选项:
request({
url: '/api/xxx',
method: 'get' | 'post' | 'put' | 'delete',
params: {}, // GET 请求参数
data: {}, // POST/PUT 请求体
headers: {}, // 自定义请求头
timeout: 20000, // 超时时间(毫秒)
responseType: 'blob', // 响应类型(用于文件下载)
unpack: false, // 是否解包响应数据
})
项目提供了文件下载工具函数:
import { downloadFile, downloadFilePost } from '/@/utils/service';
// GET 方式下载
downloadFile({
url: '/api/export/',
params: { id: 1 },
method: 'get',
filename: '导出文件'
});
// POST 方式下载
downloadFilePost({
url: '/api/export/',
data: { ids: [1, 2, 3] },
method: 'post',
filename: '导出文件'
});
项目集成了 Fast-Crud 框架,可以快速生成 CRUD 页面。参考 src/views/system/company/crud.tsx 的实现。
import * as api from './api';
import { UserPageQuery, AddReq, DelReq, EditReq, CreateCrudOptionsProps, CreateCrudOptionsRet } from '@fast-crud/fast-crud';
export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProps): CreateCrudOptionsRet {
// 分页查询
const pageRequest = async (query: UserPageQuery) => {
return await api.GetList(query);
};
// 编辑请求
const editRequest = async ({ form, row }: EditReq) => {
form.id = row.id;
return await api.UpdateObj(form);
};
// 删除请求
const delRequest = async ({ row }: DelReq) => {
return await api.DelObj(row.id);
};
// 新增请求
const addRequest = async ({ form }: AddReq) => {
return await api.AddObj(form);
};
return {
crudOptions: {
// CRUD 配置
}
};
};
请求配置:
request: {
pageRequest, // 分页查询
addRequest, // 新增
editRequest, // 编辑
delRequest, // 删除
}
工具栏配置:
toolbar: {
buttons: {
search: { show: true }, // 搜索按钮
refresh: { show: true }, // 刷新按钮
export: { show: true }, // 导出按钮
columns: { show: true }, // 列设置按钮
}
}
搜索配置:
search: {
col: { span: 3 }, // 每列占用的栅格数
show: true, // 显示搜索区域
autoSearch: true, // 自动搜索
buttons: {
search: { size: 'small' }, // 查询按钮大小
reset: { size: 'small' }, // 重置按钮大小
}
}
操作栏配置:
actionbar: {
buttons: {
add: {
size: 'small',
show: true, // 或使用权限: auth('company:Create')
},
},
}
行操作配置:
rowHandle: {
fixed: 'right', // 固定在右侧
width: 260, // 操作栏宽度
buttons: {
view: { // 查看按钮
size: 'small',
text: '查看',
show: true,
},
edit: { // 编辑按钮
size: 'small',
show: true,
},
remove: { // 删除按钮
show: false,
},
// 自定义按钮
customAction: {
size: 'small',
text: '自定义操作',
click: async ({ row }) => {
// 自定义操作逻辑
},
},
},
}
列配置:
columns: {
name: {
title: '名称',
type: 'input', // 字段类型
search: { show: true }, // 是否显示在搜索区域
form: { // 表单配置
rules: [{ required: true, message: '名称必填' }],
component: { placeholder: '请输入名称' },
},
column: { minWidth: 120 }, // 列配置
},
status: {
title: '状态',
type: 'dict-select', // 字典选择器
search: { show: true },
dict: dict({
data: [
{ value: 1, label: '启用' },
{ value: 0, label: '禁用' },
]
}),
},
}
Fast-Crud 支持多种字段类型:
input: 文本输入框textarea: 多行文本number: 数字输入框password: 密码输入框select: 下拉选择dict-select: 字典选择器date: 日期选择器datetime: 日期时间选择器switch: 开关radio: 单选框checkbox: 复选框upload: 文件上传editor: 富文本编辑器参考 src/views/system/company/crud.tsx 查看完整的 CRUD 配置示例。
使用 Pinia 进行状态管理,store 文件位于 src/stores/ 目录。
// src/stores/userInfo.ts 示例
import { defineStore } from 'pinia';
import { Session } from '/@/utils/storage';
export const useUserInfo = defineStore('userInfo', {
state: (): UserInfosState => ({
userInfos: {
username: '',
avatar: '',
roles: [],
// ...其他用户信息
},
}),
actions: {
// 设置用户信息
setUserInfos(data: any) {
this.userInfos = data;
},
// 清除用户信息
clearUserInfos() {
this.userInfos = {
username: '',
avatar: '',
roles: [],
};
},
},
persist: {
key: 'userInfo',
storage: Session, // 使用 SessionStorage
},
});
import { useUserInfo } from '/@/stores/userInfo';
import { storeToRefs } from 'pinia';
// 在 setup 中使用
const userInfoStore = useUserInfo();
const { userInfos } = storeToRefs(userInfoStore);
// 调用 actions
userInfoStore.setUserInfos(newData);
// 直接访问 state
console.log(userInfoStore.userInfos);
userInfo.ts - 用户信息
routesList.ts - 路由列表
btnPermission.ts - 按钮权限
auth() 函数使用themeConfig.ts - 主题配置
项目使用 pinia-plugin-persist 实现 Store 持久化:
persist: {
key: 'storeKey', // 存储的 key
storage: Session, // 存储方式:Session 或 Local
paths: ['userInfos'], // 需要持久化的字段
}
src/assets/style/ 和 src/theme/项目实现了完整的权限控制系统,包括路由权限、按钮权限和字段权限。
使用 auth() 函数进行按钮权限验证:
import { auth } from '/@/utils/authFunction';
// 单个权限验证
if (auth('company:Create')) {
// 有权限,显示按钮
}
// 多个权限验证(满足一个即可)
import { auths } from '/@/utils/authFunction';
if (auths(['company:Create', 'company:Edit'])) {
// 有任一权限即可
}
// 多个权限验证(全部满足)
import { authAll } from '/@/utils/authFunction';
if (authAll(['company:Create', 'company:Edit'])) {
// 必须全部有权限
}
在模板中使用:
<template>
<el-button v-if="auth('company:Create')" @click="handleAdd">
新增
</el-button>
</template>
<script setup>
import { auth } from '/@/utils/authFunction';
</script>
路由权限在路由守卫中自动处理(src/router/index.ts):
字段权限通过 columnPermission Store 管理,可以控制表格列的显示。
项目支持多语言,配置文件位于 src/i18n/ 目录。
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
const message = t('common.save'); // 获取翻译文本
src/i18n/ 目录下创建语言文件src/i18n/index.ts 中注册新语言useI18n().locale.value = 'en' 切换语言# 启动开发服务器
npm run dev
# 构建生产版本
npm run build
# 构建本地生产版本(使用 local_prod 环境变量)
npm run build:local
# 代码检查和自动修复
npm run lint-fix
路径别名:
/@/ 指向 src/ 目录@views 指向 src/views 目录环境变量:
VITE_ 开头才能在代码中访问import.meta.env.VITE_XXX 访问环境变量API 请求:
src/utils/service.ts版本管理:
public/version-build浏览器兼容性:
UserProfile.vue<user-profile />user-profile/<template>
<!-- 模板内容 -->
</template>
<script setup lang="ts">
// 1. 导入依赖
import { ref, computed, onMounted } from 'vue';
import { useRouter } from 'vue-router';
// 2. 定义 Props
interface Props {
title: string;
count?: number;
}
const props = withDefaults(defineProps<Props>(), {
count: 0,
});
// 3. 定义 Emits
const emit = defineEmits<{
change: [value: number];
update: [value: string];
}>();
// 4. 响应式数据
const loading = ref(false);
const data = ref([]);
// 5. 计算属性
const total = computed(() => props.count * 2);
// 6. 方法
const handleClick = () => {
emit('change', 1);
};
// 7. 生命周期
onMounted(() => {
// 初始化逻辑
});
</script>
<style scoped lang="scss">
/* 样式 */
</style>
<script setup>)main/master: 主分支,生产环境代码develop: 开发分支feature/xxx: 功能分支bugfix/xxx: 修复分支hotfix/xxx: 紧急修复分支使用约定式提交格式:
<type>(<scope>): <subject>
<body>
<footer>
type 类型:
feat: 新功能fix: 修复 bugdocs: 文档更新style: 代码格式调整refactor: 代码重构perf: 性能优化test: 测试相关chore: 构建/工具相关示例:
git commit -m "feat(company): 添加公司管理功能"
git commit -m "fix(api): 修复接口请求超时问题"
git commit -m "docs(readme): 更新开发文档"
npm run lint-fix 检查代码安装 Vue DevTools 浏览器扩展:
功能:
Network 面板:
Console 面板:
Vue 面板 (需要 Vue DevTools):
在代码中使用 debugger 语句:
const handleClick = () => {
debugger; // 浏览器会在此处暂停
// 后续代码
};
使用 console 方法进行调试:
console.log('普通日志', data);
console.warn('警告信息', warning);
console.error('错误信息', error);
console.table(arrayData); // 表格形式显示数组
console.group('分组'); // 分组日志
console.groupEnd();
使用浏览器 Performance 面板:
代理配置 (vite.config.ts):
proxy: {
'/api': {
target: 'http://localhost:8000',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ''),
},
}
Mock 数据: 可以使用 Mock.js 或 MSW 进行接口模拟
问题: npm install 失败或速度慢
解决方案:
npm install --registry=https://registry.npm.taobao.orgnpm cache clean --forcenode_modules 和 package-lock.json 后重新安装问题: 启动开发服务器时提示端口被占用
解决方案:
.env.development 中的 VITE_PORT 配置问题: 开发环境 API 请求出现跨域错误
解决方案:
vite.config.ts 中配置代理(已配置 /gitee 代理示例)问题: TypeScript 编译报错
解决方案:
tsconfig.json 配置// @ts-ignore 临时忽略(不推荐).d.ts)问题: 路由跳转后页面不更新或出现 404
解决方案:
问题: 有权限但按钮不显示或接口返回 403
解决方案:
auth() 函数调用问题: 修改样式后页面没有变化
解决方案:
问题: 修改环境变量后不生效
解决方案:
VITE_ 开头import.meta.env.VITE_XXX 访问问题: npm run build 失败
解决方案:
node_modules 和 dist 目录package-lock.json 重新安装问题: 安装依赖时出现版本冲突警告
解决方案:
npm install --legacy-peer-deps 安装npm audit fix 修复安全漏洞git checkout -b feature/AmazingFeature)git commit -m 'Add some AmazingFeature')git push origin feature/AmazingFeature)MIT License