# JeecgBoot Vue3 前端框架全局开发规范与最佳实践
> 分析日期:2026-06-03
> 框架版本:JeecgBoot 3.9.2(基于 Vben-Admin Vue3 深度定制)
> 分析范围:JeecgBoot 原框架(排除 `views/recruitment` 和 `views/spbb` 业务目录)
---
## 一、框架概述
### 1.1 技术栈
| 层级 | 技术 |
|-------|-----------------------------|
| 框架基础 | Vue3 + TypeScript + Vite |
| UI组件库 | Ant Design Vue 3.x |
| 状态管理 | Pinia |
| 路由 | Vue Router 4.x |
| 表格核心 | Vben BasicTable + VXE Table |
| HTTP | Axios(VAxios 封装) |
| 图标 | Ant Design Icons + Iconify |
| 国际化 | vue-i18n |
| 富文本 | Tinymce |
| 图表 | ECharts |
| 工具库 | lodash-es + dayjs + big.js |
### 1.2 目录结构(核心)
```
jeecgboot-vue3/src/
├── api/ # 全局公共 API(系统接口)
├── assets/ # 静态资源
├── components/ # 通用组件
│ ├── Form/ # BasicForm + 46种表单组件
│ ├── Table/ # BasicTable
│ ├── Modal/ # BasicModal / JModal
│ ├── Drawer/ # BasicDrawer
│ ├── jeecg/ # JeecgBoot 业务组件(JVxeTable/JPrompt/OnLine等)
│ └── registerGlobComp.ts # 全局组件注册
├── directives/ # 自定义指令(v-auth/v-loading等)
├── enums/ # 枚举定义
├── hooks/ # 自定义 Hooks
│ ├── system/ # useListPage/useMethods/useJvxeMethods
│ ├── web/ # usePermission/useMessage/useWebSocket/useECharts
│ ├── core/ # useAttrs/useContext/useLockFn/useRefs
│ ├── event/ # useBreakpoint/useEventListener/useScroll
│ ├── setting/ # useGlobSetting/useRootSetting/useMenuSetting
│ ├── jeecg/ # useAdaptiveWidth
│ └── component/ # useFormItem/usePageContext
├── layouts/ # 布局组件(default/iframe/page)
├── router/ # 路由配置 + 守卫
├── store/ # Pinia Store(8个模块)
├── utils/ # 工具类
│ ├── http/axios/ # HTTP 封装(VAxios + defHttp)
│ ├── auth/ # 认证工具
│ ├── cache/ # 缓存体系
│ ├── common/ # 通用工具(compUtils/renderUtils/vxeUtils)
│ └── dict/ # 字典工具
├── settings/ # 全局配置
└── views/ # 业务页面
├── system/ # 系统管理模块(17+子模块)
├── demo/ # 各种示例
└── super/online/ # Online 表单
```
---
## 二、页面文件结构规范
### 2.1 单表 CRUD 模块(标准4件套)
```
模块名/
index.vue # 列表主页(使用 useListPage + BasicTable)
xxx.data.ts # columns + searchFormSchema + formSchema
xxx.api.ts # 所有接口定义(enum Api + 导出函数)
XxxModal.vue # 新增/编辑弹窗(使用 BasicModal + BasicForm)
```
**典型代表**:`system/notice/`、`system/fillRule/`、`system/checkRule/`、`system/position/`、`system/examples/demo/`
### 2.2 主子表(一对多)模块
```
模块名/
index.vue # 主表列表+子表Tab区域
xxx.data.ts # 主表 + 所有子表的 columns/formSchema
xxx.api.ts # 主表 + 所有子表的 CRUD 接口
MainModal.vue # 主表编辑弹窗
SubTableList.vue # 子表列表组件(每个子表一个)
components/
SubModal.vue # 子表编辑弹窗(每个子表一个)
```
**典型代表**:`demo/jeecg/erplist/`
### 2.3 树形页面模块
```
模块名/
index.vue # 左树右表主页面
xxx.data.ts # 表格 columns + 表单 schema
xxx.api.ts # 树接口 + 列表接口 + CRUD接口
components/
XxxModal.vue # 编辑弹窗
LeftTree.vue # 左侧树组件(可选)
```
**典型代表**:`system/category/`(纯树形)、`system/depart/`(左树右表)
---
## 三、API 文件编写规范
### 3.1 最优写法
```typescript
import { defHttp } from '/@/utils/http/axios';
import { Modal } from 'ant-design-vue';
enum Api {
list = '/模块/实体/list',
save = '/模块/实体/add',
edit = '/模块/实体/edit',
get = '/模块/实体/queryById',
delete = '/模块/实体/delete',
deleteBatch = '/模块/实体/deleteBatch',
exportXls = '/模块/实体/exportXls',
importExcel = '/模块/实体/importExcel',
}
/** 导出 url(供导入导出组件使用) */
export const getExportUrl = Api.exportXls;
/** 导入 url */
export const getImportUrl = Api.importExcel;
/** 列表查询 */
export const list = (params) => defHttp.get({ url: Api.list, params });
/** 通过ID查询 */
export const getById = (params) => defHttp.get({ url: Api.get, params });
/** 保存或更新 */
export const saveOrUpdate = (params, isUpdate) => {
let url = isUpdate ? Api.edit : Api.save;
return defHttp.post({ url: url, params });
};
/** 单条删除 */
export const deleteOne = (params, handleSuccess) => {
return defHttp.delete({ url: Api.delete, params }, { joinParamsToUrl: true }).then(() => {
handleSuccess();
});
};
/** 批量删除 */
export const batchDelete = (params, handleSuccess) => {
Modal.confirm({
title: '确认删除',
content: '是否删除选中数据',
okText: '确认',
cancelText: '取消',
onOk: () => {
return defHttp.delete({ url: Api.deleteBatch, data: params }, { joinParamsToUrl: true }).then(() => {
handleSuccess();
});
},
});
};
```
### 3.2 API 编写要点
| 要点 | 规范 |
|----------|-------------------------------------------------------------------|
| URL定义 | 使用 `enum Api` 集中管理,不要散落 |
| GET请求 | `defHttp.get({ url, params })` |
| POST请求 | `defHttp.post({ url, params })` |
| DELETE请求 | `defHttp.delete({ url, params/data }, { joinParamsToUrl: true })` |
| 导出URL | 单独 `export const getExportUrl = Api.exportXls` |
| 导入URL | 单独 `export const getImportUrl = Api.importExcel` |
| 保存/更新合并 | `saveOrUpdate(params, isUpdate)` 通过判断URL区分新增/编辑 |
| 删除回调 | 第二个参数 `handleSuccess` 通常传入 `reload` |
---
## 四、Data 文件编写规范
### 4.1 columns 定义
```typescript
import { BasicColumn } from '/@/components/Table';
import { render } from '/@/utils/common/renderUtils';
export const columns: BasicColumn[] = [
{
title: '姓名',
dataIndex: 'name',
width: 170,
align: 'left',
resizable: true, // 允许拖拽调整列宽
sorter: { multiple: 1 }, // 支持多字段排序
},
{
title: '性别',
dataIndex: 'sex',
width: 120,
resizable: true,
sorter: { multiple: 2 },
customRender: ({ text }) => {
return render.renderDict(text, 'sex'); // 字典翻译渲染
},
},
{
title: '生日',
dataIndex: 'birthday',
width: 120,
resizable: true,
},
{
title: '订单类型', // 非字典的固定选项翻译
dataIndex: 'ctype',
width: 160,
customRender: ({ text }) => {
return text == '1' ? '国内订单' : text == '2' ? '国际订单' : '';
},
},
];
```
### 4.2 searchFormSchema 定义
```typescript
import { FormSchema } from '/@/components/Table';
export const searchFormSchema: FormSchema[] = [
{
field: 'name',
label: '姓名',
component: 'Input',
componentProps: { trim: true }, // 自动去首尾空格
colProps: { span: 6 },
},
{
field: 'birthday',
label: '生日',
component: 'RangePicker', // 日期范围查询
componentProps: { valueType: 'Date' },
colProps: { span: 8 },
},
{
field: 'age',
label: '年龄',
component: 'Input', // 区间查询通过 slot 自定义
slot: 'age',
colProps: { span: 8 },
},
{
field: 'sex',
label: '性别',
component: 'JDictSelectTag', // 字典下拉
componentProps: {
dictCode: 'sex',
placeholder: '请选择性别',
},
colProps: { span: 8 },
},
{
field: 'departId',
label: '部门',
component: 'JSelectDept', // 部门选择
colProps: { span: 6 },
},
{
field: 'status',
label: '状态',
component: 'JDictSelectTag',
componentProps: {
dictCode: 'valid_status',
placeholder: '请选择状态',
},
colProps: { span: 6 },
},
];
```
### 4.3 formSchema 定义(弹窗表单)
```typescript
export const formSchema: FormSchema[] = [
{
field: 'id',
label: 'id',
component: 'Input',
show: false, // 隐藏字段(主键等)
},
{
field: 'name',
label: '名称',
component: 'Input',
required: true, // 必填校验
componentProps: { placeholder: '请输入名称' },
},
{
field: 'sex',
label: '性别',
component: 'JDictSelectTag',
defaultValue: '1', // 默认值
componentProps: {
type: 'radio', // 字典渲染为单选按钮组
dictCode: 'sex',
},
},
{
field: 'birthday',
label: '生日',
component: 'DatePicker',
componentProps: {
valueFormat: 'YYYY-MM-DD', // 日期格式化
placeholder: '请选择生日',
},
},
{
field: 'email',
label: '邮箱',
component: 'Input',
rules: [{ required: false, type: 'email', message: '邮箱格式不正确', trigger: 'blur' }],
componentProps: { placeholder: '请输入邮箱' },
},
{
field: 'orderId', // 主子表外键字段
label: 'orderId',
component: 'Input',
show: false, // 隐藏
},
];
```
### 4.4 表单组件类型速查(componentMap 46种)
**Ant Design Vue 基础组件(22种)**:
| component值 | 说明 | 常用componentProps |
|-----------------|------|----------------------------------------|
| `Input` | 输入框 | `trim`, `placeholder` |
| `InputTextArea` | 多行文本 | `rows`, `placeholder` |
| `InputNumber` | 数字输入 | `min`, `max`, `step` |
| `InputPassword` | 密码框 | `placeholder` |
| `Select` | 下拉选择 | `options: [{label, value}]` |
| `TreeSelect` | 树选择 | `treeData`, `fieldNames` |
| `Switch` | 开关 | `checkedChildren`, `unCheckedChildren` |
| `RadioGroup` | 单选组 | `options: [{label, value}]` |
| `CheckboxGroup` | 复选组 | `options` |
| `Cascader` | 级联选择 | `options` |
| `DatePicker` | 日期选择 | `valueFormat: 'YYYY-MM-DD'` |
| `MonthPicker` | 月份选择 | `valueFormat` |
| `RangePicker` | 日期范围 | `valueType: 'Date'` |
| `TimePicker` | 时间选择 | `valueFormat` |
| `Slider` | 滑动条 | `min`, `max` |
| `Rate` | 评分 | `count` |
| `AutoComplete` | 自动完成 | `options` |
| `Divider` | 分隔线 | — |
**JeecgBoot 业务组件(32种,J开头为主)**:
| component值 | 说明 | 常用场景 |
|--------------------------------|----------------------|------------|
| `JDictSelectTag` | 字典下拉/单选/多选 | 所有字典字段 |
| `JInput` | 增强输入框(支持模糊/不等于等查询模式) | 查询条件 |
| `JImageUpload` | 图片上传 | 图片字段 |
| `JUpload` | 文件上传 | 附件字段 |
| `JEditor` | 富文本编辑器 | 富文本内容 |
| `JMarkdownEditor` | Markdown编辑器 | Markdown内容 |
| `JCodeEditor` | 代码编辑器 | 代码/SQL/JS |
| `JPopup` | Popup弹出选择 | 弹窗选择关联数据 |
| `JPopupDict` | 字典Popup弹框 | 表字典选择 |
| `JSelectDept` | 部门选择 | 部门字段 |
| `JSelectUser` / `UserSelect` | 用户选择 | 用户字段 |
| `JSelectRole` / `RoleSelect` | 角色选择 | 角色字段 |
| `JSelectPosition` | 岗位选择 | 岗位字段 |
| `JAreaLinkage` / `JAreaSelect` | 省市区联动 | 地区字段 |
| `JCategorySelect` | 分类选择 | 分类字典 |
| `JTreeDict` | 字典树 | 树形字典 |
| `JTreeSelect` | 自定义树选择 | 树形数据选择 |
| `JSwitch` | 自定义开关 | 开关字段 |
| `JSelectInput` | 下拉+输入组合 | 灵活输入 |
| `JSelectMultiple` | 多选下拉 | 多选字段 |
| `JSearchSelect` | 搜索选择 | 异步搜索选择 |
| `JEasyCron` | Cron表达式 | 定时任务配置 |
| `JCheckbox` | 自定义复选框 | 多选字段 |
| `JInputPop` | 弹出输入框 | 大文本输入 |
| `JLinkTableCard` | 关联记录卡片 | 关联表展示 |
| `JAddInput` | 动态添加输入框 | 多值输入 |
| `JRangeNumber` | 数字范围输入 | 区间查询 |
| `JInputSelect` | 输入选择 | 输入+下拉切换 |
| `RangeDate` | 日期范围 | 日期区间 |
| `RangeTime` | 时间范围 | 时间区间 |
| `ApiSelect` | API远程下拉 | 接口数据下拉 |
| `ApiTreeSelect` | API远程树选择 | 接口树数据 |
| `IconPicker` | 图标选择器 | 菜单图标 |
---
## 五、单表 CRUD 页面最优写法
### 5.1 列表页 index.vue(useListPage 模式 — 推荐)
```vue
```
### 5.2 弹窗 XxxModal.vue
```vue
```
### 5.3 useListPage Hook 详解
`useListPage` 是列表页开发的核心 Hook,封装了表格注册、导入导出、选择行、删除确认等通用逻辑。
**接口定义**:
```typescript
interface ListPageOptions {
designScope?: string; // 样式作用域
tableProps: TableProps; // 表格配置(必填)
pagination?: boolean; // 是否分页
exportConfig?: { // 导出配置
url: string | (() => string);
name?: string | (() => string);
params?: object | (() => object);
};
importConfig?: { // 导入配置
url: string | (() => string);
success?: (fileInfo?: any) => void;
};
}
```
**返回值**:
| 返回值 | 说明 |
|----------------------------|-----------------------------------------------------------------------------|
| `tableContext` | `[registerTable, methods, { rowSelection, selectedRowKeys, selectedRows }]` |
| `onExportXls()` | 导出 Excel(自动获取查询条件+选中行+列设置) |
| `onImportXls(file)` | 导入 Excel |
| `doRequest(api, options?)` | 通用请求(自动确认+刷新+清空选择) |
| `doDeleteRecord(api)` | 单条删除(无确认弹窗) |
| `prefixCls` | CSS 类名前缀 |
| `createMessage` | 消息提示 |
| `createConfirm` | 确认弹窗 |
**useListTable 默认配置**(自动应用,无需手动设置):
| 配置项 | 默认值 | 说明 |
|--------------------|------------------------|-----------|
| `rowKey` | `'id'` | 主键 |
| `useSearchForm` | `true` | 启用搜索表单 |
| `canResize` | `true` | 自适应高度 |
| `minHeight` | `300` | 最小高度 |
| `bordered` | `true` | 边框 |
| `striped` | `false` | 斑马纹 |
| `showTableSetting` | `true` | 表格设置 |
| `beforeFetch` | 默认排序 `createTime desc` | 请求前自动注入排序 |
---
## 六、主子表(一对多)页面最优写法
### 6.1 核心架构
- **主表列表** 使用 `useListPage` + `BasicTable`
- **子表** 使用 `a-tabs` + 独立的子表列表组件
- **主子表通信** 通过 `provide/inject` 传递主表选中 ID
- **主表单弹窗** 内含子表 Tab(新增/编辑时同时操作主表+子表)
### 6.2 主表列表页 index.vue
```vue
```
### 6.3 子表列表组件
```vue
新增
```
### 6.4 主子表 data.ts 规范
在同一个 data.ts 中定义主表和所有子表的配置:
```typescript
// ---- 主表 ----
export const columns: BasicColumn[] = [ /* 主表列 */ ];
export const searchFormSchema: FormSchema[] = [ /* 主表搜索 */ ];
export const formSchema: FormSchema[] = [ /* 主表表单 */ ];
// ---- 子表1 ----
export const sub1Columns: BasicColumn[] = [ /* 子表1列 */ ];
export const sub1FormSchema: FormSchema[] = [ /* 子表1表单 */ ];
// ---- 子表2 ----
export const sub2Columns: BasicColumn[] = [ /* 子表2列 */ ];
export const sub2FormSchema: FormSchema[] = [ /* 子表2表单 */ ];
```
### 6.5 主子表 api.ts 规范
在同一个 api.ts 中定义主表和所有子表的接口:
```typescript
enum Api {
// 主表
list = '/test/order/orderList',
save = '/test/order/add',
edit = '/test/order/edit',
deleteOne = '/test/order/delete',
deleteBatch = '/test/order/deleteBatch',
// 子表1
sub1List = '/test/order/listSub1ByMainId',
saveSub1 = '/test/order/addSub1',
editSub1 = '/test/order/editSub1',
deleteSub1 = '/test/order/deleteSub1',
// 子表2
sub2List = '/test/order/listSub2ByMainId',
saveSub2 = '/test/order/addSub2',
editSub2 = '/test/order/editSub2',
deleteSub2 = '/test/order/deleteSub2',
}
```
---
## 七、树形页面最优写法
### 7.1 纯树形列表(如分类字典)
关键差异:`isTreeTable: true` + 异步加载子节点
```vue
```
### 7.2 左树右表(如部门管理)
- 左侧:独立的树组件(`DepartLeftTree.vue`)
- 右侧:标准 BasicTable
- 通信:树选中 → 触发表格 `reload({ searchInfo: { departId: selectedKey } })`
---
## 八、BasicTable / BasicModal / BasicDrawer 使用规范
### 8.1 BasicTable 核心 API
**注册方式**:
```typescript
// 方式一:useListPage(推荐,自动处理导入导出)
const { tableContext } = useListPage({ tableProps: { ... } });
const [registerTable, { reload, setProps }, { rowSelection, selectedRowKeys }] = tableContext;
// 方式二:useTable(手动管理)
const [registerTable, { reload, setProps, getDataSource, updateTableDataRecord }] = useTable({
api: list,
columns,
formConfig: { schemas: searchFormSchema },
...
});
```
**模板使用**:
```vue
```
**常用方法**:
| 方法 | 说明 |
|-----------------------------------------|--------------|
| `reload(params?)` | 刷新表格(可传搜索参数) |
| `setProps(props)` | 动态修改表格属性 |
| `getDataSource()` | 获取当前数据源 |
| `updateTableDataRecord(rowKey, record)` | 更新指定行数据 |
| `findTableDataRecord(rowKey)` | 查找指定行 |
| `getColumns()` | 获取列配置 |
| `setColumns(columns)` | 设置列配置 |
| `setLoading(loading)` | 设置加载状态 |
| `getForm()` | 获取搜索表单实例 |
### 8.2 BasicModal 核心 API
**注册方式**:
```typescript
// 外部调用方
const [registerModal, { openModal, closeModal, setModalProps }] = useModal();
// Modal 内部
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
// data = openModal 传入的参数
await resetFields();
// 回填表单数据
await setFieldsValue({ ...data.record });
});
```
**常用方法**:
| 方法 | 说明 |
|----------------------------|-------------------------------------------|
| `openModal(visible, data)` | 打开弹窗并传参 |
| `closeModal()` | 关闭弹窗 |
| `setModalProps(props)` | 修改弹窗属性(confirmLoading, showOkBtn, title等) |
### 8.3 BasicDrawer 核心 API
**注册方式**:
```typescript
// 外部调用方
const [registerDrawer, { openDrawer, closeDrawer }] = useDrawer();
// Drawer 内部
const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => {
// data = openDrawer 传入的参数
});
```
---
## 九、Excel 导入导出规范
### 9.1 使用 useListPage 模式(推荐,最少代码)
```typescript
const { onExportXls, onImportXls } = useListPage({
tableProps: { ... },
exportConfig: {
name: '导出文件名',
url: getExportUrl,
params: { customParam: 'value' }, // 自定义导出参数(可选)
},
importConfig: {
url: getImportUrl,
success: () => { /* 导入成功回调 */ },
},
});
```
模板中直接调用:
```vue
导出
导入
```
### 9.2 使用 useMethods 模式(更多控制)
```typescript
import { useMethods } from '/@/hooks/system/useMethods';
const { handleExportXls, handleImportXls } = useMethods();
// 导出
handleExportXls('文件名', exportUrl, filterParams);
// 导入(配合 a-upload)
```
### 9.3 弹窗导入模式(JImportModal)
```vue
```
---
## 十、字典使用规范
### 10.1 字典翻译渲染(列表列)
```typescript
import { render } from '/@/utils/common/renderUtils';
// 方式一:普通字典翻译
{
title: '性别',
dataIndex: 'sex',
customRender: ({ text }) => render.renderDict(text, 'sex'),
}
// 方式二:表字典翻译(从其他表翻译)
{
title: '部门',
dataIndex: 'departId',
customRender: ({ text }) => render.renderDict(text, 'sys_depart,depart_name,id'),
}
```
### 10.2 字典下拉选择(表单/搜索)
```typescript
// 搜索条件中
{
field: 'sex',
label: '性别',
component: 'JDictSelectTag',
componentProps: {
dictCode: 'sex',
placeholder: '请选择性别',
},
}
// 表单中 - 下拉模式
{
field: 'sex',
label: '性别',
component: 'JDictSelectTag',
componentProps: {
dictCode: 'sex',
},
}
// 表单中 - 单选按钮模式
{
field: 'sex',
label: '性别',
component: 'JDictSelectTag',
componentProps: {
type: 'radio',
dictCode: 'sex',
},
}
```
### 10.3 字典工具函数
```typescript
import { initDictOptions } from '/@/utils/dict';
// 在组件中获取字典选项
const dictOptions = await initDictOptions('sex');
// dictOptions = [{ value: '1', text: '男' }, { value: '2', text: '女' }]
```
---
## 十一、权限控制规范
### 11.1 功能权限(按钮级)
**方式一:v-auth 指令**(控制 DOM 显隐)
```vue
新增
编辑
删除
```
**方式二:usePermission Hook**(逻辑判断)
```typescript
import { usePermission } from '/@/hooks/web/usePermission';
const { hasPermission } = usePermission();
if (hasPermission('user:add')) {
// 有权限才执行的逻辑
}
```
**方式三:TableAction 权限控制**
```typescript
function getTableAction(record) {
return [
{
label: '编辑',
onClick: handleEdit.bind(null, record),
auth: 'user:edit', // 权限码
},
{
label: '删除',
popConfirm: { title: '确定删除?', confirm: handleDelete.bind(null, record) },
auth: 'user:delete',
},
];
}
```
### 11.2 数据权限
由后端 `@PermissionData` 注解 + `QueryGenerator` 自动处理,前端无需额外编码。
### 11.3 免认证配置
```typescript
// 方式一:路由元信息
{
path: '/public-page',
meta: { ignoreAuth: true },
}
// 方式二:将 URL 加入白名单(router/guard/permissionGuard.ts)
```
---
## 十二、HTTP 请求封装
### 12.1 defHttp 使用
```typescript
import { defHttp } from '/@/utils/http/axios';
// GET 请求
export const list = (params) => defHttp.get({ url: '/api/list', params });
// POST 请求
export const save = (params) => defHttp.post({ url: '/api/save', params });
// PUT 请求
export const update = (params) => defHttp.put({ url: '/api/update', params });
// DELETE 请求(参数拼接到URL)
export const remove = (params) => defHttp.delete({ url: '/api/delete', params }, { joinParamsToUrl: true });
// DELETE 请求(参数在body中)
export const batchRemove = (data) => defHttp.delete({ url: '/api/batchDelete', data });
// 文件上传
export const upload = (params) => defHttp.uploadFile({ url: '/api/upload', params });
```
### 12.2 自动注入的请求头
| Header | 说明 |
|------------------|--------------------|
| `X-Access-Token` | JWT Token(自动从缓存获取) |
| `X-Tenant-Id` | 租户ID(自动注入) |
| `X-Sign` | 请求签名(MD5) |
| `X-TIMESTAMP` | 请求时间戳 |
| `X-Version` | 版本号 |
| `X-Low-App-ID` | 低代码应用ID |
### 12.3 响应处理
- `code === 0` → 成功,返回 `result` 数据
- `code === 401` → Token 失效,自动跳转登录页
- 其他 → 错误提示
---
## 十三、常用 Hooks 速查
### 13.1 系统 Hooks
| Hook | 用途 | 核心导出 |
|------------------|-------------|-----------------------------------------------------------|
| `useListPage` | 列表页标准开发 | `tableContext`, `onExportXls`, `onImportXls`, `doRequest` |
| `useMethods` | 导入导出方法 | `handleExportXls`, `handleImportXls` |
| `useJvxeMethods` | JVxeTable方法 | 行编辑表格操作 |
### 13.2 Web Hooks
| Hook | 用途 | 核心导出 |
|-----------------|-----------|-------------------------------------------------------|
| `usePermission` | 权限判断 | `hasPermission(value)`, `isDisabledAuth` |
| `useMessage` | 消息弹窗 | `createMessage`, `createConfirm`, `createConfirmSync` |
| `useWebSocket` | WebSocket | `connectWebSocket(url)`, `onWebSocket(cb)` |
| `useECharts` | ECharts图表 | `setOptions`, `resize`, `getInstance` |
| `useTabs` | 多标签操作 | `refreshPage`, `closeAll`, `closeLeft` |
| `useDesign` | CSS命名空间 | `prefixCls` = `'jeecg'` |
| `usePage` | 页面跳转 | `useGo()`, `useRedo()` |
### 13.3 核心 Hooks
| Hook | 用途 |
|------------------------|------------------------|
| `useAttrs` | 透传属性 |
| `useContext` | 上下文 |
| `useLockFn` | 防重复提交 |
| `useRefs` | 模板 Refs 批量管理 |
| `onMountedOrActivated` | mounted/activated 统一入口 |
---
## 十四、常用工具函数速查
### 14.1 compUtils(最常用)
```typescript
import { getFileAccessHttpUrl, listToTree, filterObj, triggerWindowResizeEvent, getHeaders } from '/@/utils/common/compUtils';
```
| 函数 | 说明 |
|---------------------------------------|--------------------------|
| `getFileAccessHttpUrl(url)` | 文件 URL 拼接(自动加域名前缀) |
| `listToTree(data, pid, key)` | 扁平列表转树形结构 |
| `filterObj(obj)` | 过滤空属性对象 |
| `triggerWindowResizeEvent()` | 触发窗口 resize 事件 |
| `getHeaders()` | 获取上传请求头(含Token+TenantId) |
| `mapTableTotalSummary(data, columns)` | 表格合计行(big.js精度计算) |
| `simpleDebounce(fn, delay)` | 防抖 |
| `dateFormat(date, fmt)` | 日期格式化 |
| `bindMapFormSchema(schemas, span)` | 表单 span 响应式映射 |
### 14.2 renderUtils
```typescript
import { render } from '/@/utils/common/renderUtils';
render.renderDict(text, dictCode) // 字典翻译
render.renderTag(text, color) // 标签渲染
render.renderSwitch(text, colorMap) // 开关渲染
render.renderDate(text) // 日期格式化
```
### 14.3 dict 工具
```typescript
import { initDictOptions, getDictItemsByCode, ajaxGetDictItems } from '/@/utils/dict';
const options = await initDictOptions('sex'); // 获取字典选项(优先缓存)
```
### 14.4 auth 工具
```typescript
import { getToken, getTenantId, setAuthCache, getAuthCache, clearAuthCache } from '/@/utils/auth';
```
---
## 十五、自定义指令
| 指令 | 用途 | 示例 |
|-------------------|-----------|----------------------------------------|
| `v-auth` | 权限控制DOM显隐 | `v-auth="'user:add'"` |
| `v-loading` | 加载遮罩 | `v-loading="loading"` |
| `v-click-outside` | 点击外部触发 | `v-click-outside="handleClickOutside"` |
| `v-repeat-click` | 长按重复触发 | `v-repeat-click="handleRepeat"` |
| `v-ripple` | 水波纹效果 | `v-ripple` |
---
## 十六、全局配置文件
### 16.1 projectSetting.ts(核心配置)
| 配置项 | 默认值 | 说明 |
|-----------------------|-----------|-------------------------------------------|
| `permissionMode` | `'BACK'` | 权限模式(BACK=后端动态路由) |
| `permissionCacheType` | `'LOCAL'` | 权限缓存方式 |
| `themeMode` | `'LIGHT'` | 主题模式 |
| `showBreadCrumb` | `true` | 面包屑 |
| `openKeepAlive` | `true` | 页面缓存 |
| `headerSetting` | — | 头部配置(fixed/showDoc/showNotice/showSearch) |
| `menuSetting` | — | 菜单配置(type/mode/collapsed/accordion) |
| `multiTabsSetting` | — | 多标签配置(cache/show/canDrag) |
### 16.2 componentSetting.ts(组件默认配置)
| 配置项 | 默认值 |
|-------------------|----------------|
| `table.pageNo` | `'pageNo'` |
| `table.pageSize` | `'pageSize'` |
| `table.records` | `'records'` |
| `table.total` | `'total'` |
| `form.labelCol` | `{ span: 4 }` |
| `form.wrapperCol` | `{ span: 18 }` |
---
## 十七、Pinia Store 模块
| Store ID | 功能 | 核心状态 |
|--------------------|-------|-------------------------------|
| `app` | 应用全局 | 暗黑模式、页面加载、项目配置 |
| `app-user` | 用户 | token、用户信息、角色列表、**字典缓存**、租户ID |
| `app-permission` | 权限/路由 | permCodeList、authList、动态路由 |
| `app-multiple-tab` | 多标签页 | tab列表、KeepAlive列表 |
| `app-lock` | 锁屏 | 锁屏密码 |
| `app-locale` | 国际化 | 当前语言、路径标题映射 |
| `app-error-log` | 错误日志 | AJAX错误信息 |
| `defIndex` | 默认首页 | url和component |
---
## 十八、路由体系
### 18.1 路由模式
| 模式 | 说明 | 配置 |
|---------------|-----------------|-----------------------------------|
| **BACK**(默认) | 后端动态菜单 → 自动生成路由 | `permissionMode: 'BACK'` |
| ROLE | 后端角色 → 前端路由 | `permissionMode: 'ROLE'` |
| ROUTE_MAPPING | 前端静态路由 + 权限过滤 | `permissionMode: 'ROUTE_MAPPING'` |
### 18.2 路由守卫执行顺序
```
1. PageGuard — 状态检查
2. PageLoadingGuard — 页面加载进度条
3. HttpGuard — 清除pending请求
4. ScrollGuard — 滚动重置
5. MessageGuard — 消息清理
6. ProgressGuard — NProgress
7. PermissionGuard — 权限核心(白名单/登录判断/动态路由构建)
8. ParamMenuGuard — 参数菜单处理
9. StateGuard — 登录页状态清理
```
### 18.3 免登录路由
框架内置以下免登录路由(在 `routes/index.ts` 定义):
| 路由 | 说明 |
|---------------------|-----------------|
| `/login` | 登录页 |
| `/oauth2-app/login` | OAuth2免登(钉钉/企微) |
| `/tokenLogin` | Token静默登录 |
| `/ssoLogin` | 智慧人社SSO |
| `/file/share` | 文件分享 |
---
## 十九、JVxeTable(可编辑行表格)
用于需要行内编辑的场景(如主子表子表、批量录入等)。
### 19.1 基本使用
```vue
```
### 19.2 单元格类型(14种)
| 类型 | 说明 | 对应组件 |
|---------------------|-------|------------------------|
| `input` | 输入框 | JVxeInputCell |
| `inputNumber` | 数字输入 | JVxeInputCell |
| `select` | 下拉选择 | JVxeSelectCell |
| `selectSearch` | 搜索选择 | JVxeSelectCell |
| `selectMultiple` | 多选 | JVxeSelectCell |
| `date` / `datetime` | 日期 | JVxeDateCell |
| `time` | 时间 | JVxeTimeCell |
| `checkbox` | 复选框 | JVxeCheckboxCell |
| `radio` | 单选 | JVxeRadioCell |
| `textarea` | 多行文本 | JVxeTextareaCell |
| `upload` | 文件上传 | JVxeUploadCell |
| `treeSelect` | 树选择 | JVxeTreeSelectCell |
| `catTreeSelect` | 分类字典树 | JVxeCategorySelectCell |
| `progress` | 进度条 | JVxeProgressCell |
| `rowDragSort` | 拖拽排序 | JVxeDragSortCell |
| `slot` | 插槽自定义 | JVxeSlotCell |
---
## 二十、WebSocket 实时推送
```typescript
import { useWebSocket } from '/@/hooks/web/useWebSocket';
// 建立连接
connectWebSocket('ws://localhost:8080/websocket');
// 添加监听
onWebSocket((data) => {
console.log('收到消息:', data);
});
// 移除监听
offWebSocket(callback);
```
特性:自动重连(10次/5s间隔)、心跳(55s)、全局单例。
---
## 二十一、关键源码索引
### 21.1 核心 Hooks
| 组件 | 文件 |
|---------------|--------------------------------------------------|
| useListPage | `jeecgboot-vue3/src/hooks/system/useListPage.ts` |
| useMethods | `jeecgboot-vue3/src/hooks/system/useMethods.ts` |
| usePermission | `jeecgboot-vue3/src/hooks/web/usePermission.ts` |
| useMessage | `jeecgboot-vue3/src/hooks/web/useMessage.ts` |
| useWebSocket | `jeecgboot-vue3/src/hooks/web/useWebSocket.ts` |
| useECharts | `jeecgboot-vue3/src/hooks/web/useECharts.ts` |
### 21.2 核心组件
| 组件 | 文件 |
|--------------|------------------------------------------------------------------|
| BasicTable | `jeecgboot-vue3/src/components/Table/src/BasicTable.vue` |
| BasicModal | `jeecgboot-vue3/src/components/Modal/src/BasicModal.vue` |
| BasicDrawer | `jeecgboot-vue3/src/components/Drawer/src/BasicDrawer.vue` |
| BasicForm | `jeecgboot-vue3/src/components/Form/src/BasicForm.vue` |
| JVxeTable | `jeecgboot-vue3/src/components/jeecg/JVxeTable/src/JVxeTable.ts` |
| componentMap | `jeecgboot-vue3/src/components/Form/src/componentMap.ts` |
### 21.3 工具类
| 工具 | 文件 |
|-------------|--------------------------------------------------|
| defHttp | `jeecgboot-vue3/src/utils/http/axios/index.ts` |
| compUtils | `jeecgboot-vue3/src/utils/common/compUtils.ts` |
| renderUtils | `jeecgboot-vue3/src/utils/common/renderUtils.ts` |
| dict | `jeecgboot-vue3/src/utils/dict/index.ts` |
| auth | `jeecgboot-vue3/src/utils/auth/index.ts` |
| cache | `jeecgboot-vue3/src/utils/cache/persistent.ts` |
### 21.4 示例页面
| 类型 | 文件 |
|-----------|------------------------------------------------------|
| 单表CRUD | `jeecgboot-vue3/src/views/system/examples/demo/` |
| 主子表ERP | `jeecgboot-vue3/src/views/demo/jeecg/erplist/` |
| 树形列表 | `jeecgboot-vue3/src/views/system/category/` |
| 树形左树右表 | `jeecgboot-vue3/src/views/system/depart/` |
| JVxeTable | `jeecgboot-vue3/src/views/demo/jeecg/JVxeTableDemo/` |
---
## 二十二、涉及的文件清单
| 文件 | 操作 | 原因 |
|--------------------------------------------|----|---------------------|
| `.docs/260603-JeecgBoot前端框架全局开发规范与最佳实践.md` | 新增 | 重新分析前端框架,撰写全面开发规范文档 |