# 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` | 新增 | 重新分析前端框架,撰写全面开发规范文档 |