# cool-admin-class **Repository Path**: CRESCENT007/cool-admin-class ## Basic Information - **Project Name**: cool-admin-class - **Description**: 学习使用 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: 8 - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-01-27 - **Last Updated**: 2026-01-27 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Cool Admin 插件开发指南 注意如果拉取https://gitee.com/CRESCENT007/cool-admin-class.git后子模块目录下没有代码的话,则先在根目录下执行git submodule update --init --recursive进行子模块的初始化和更新 ## 1. 数据库配置 修改后端数据库配置 `server\src\config\config.local.ts`,更改为自建数据库相关配置(需要先建好一个数据库): ```typescript type: 'mysql', host: '127.0.0.1', port: 3306, username: 'root', password: '123456', database: 'cool', ``` **注意:** 如果使用的是 PostgreSQL 的话,需要在 server 的终端下执行 `pnpm install pg --save` 来安装数据库相关依赖。MySQL、SQLite 则不用。 ## 2. 后端服务启动 ### 安装依赖并启动服务 ```bash pnpm i # 安装依赖 pnpm dev # 启动后端 ``` ### 自动建表配置 在 `server\src\config\config.local.ts` 中有一个配置项: ```typescript // 自动建表 注意:线上部署的时候不要使用,有可能导致数据丢失 synchronize: true, ``` 当该项为 `true` 时,首次执行 `pnpm dev` 会自动初始化数据库,将架构的初始数据库表和数据添加到你的数据库中。建议开发状态下,首次执行 `pnpm dev` 时将该配置打开,后续根据需要选择是否打开。 ## 3. 前端服务启动 ### 安装依赖并启动服务 ```bash pnpm i # 安装依赖 pnpm dev # 启动前端 ``` **注意:** 后端必须在前端之前启动,否则无法运行。 ## 4. 前端插件开发 前端插件应放置于 `client\src\plugins` 下。 ### 目录结构 ``` plugin-name/ ├── components/ # 全局组件(可选) │ └── component-name.vue ├── directives/ # 全局指令(可选) │ └── directive-name.ts ├── locales/ # 国际化文件(可选) │ ├── zh-cn.json │ ├── zh-tw.json │ └── en.json ├── hooks/ # 常用函数/Hooks(可选) │ └── index.ts ├── utils/ # 工具函数(可选) │ └── index.ts ├── static/ # 静态资源(可选) │ ├── css/ │ ├── svg/ │ └── images/ ├── demo/ # 示例页面(可选) │ └── base.vue ├── types/ # TypeScript 类型定义(可选) │ └── index.d.ts ├── config.ts # 配置文件(必需) └── index.ts # 入口文件(必需) ``` ### 必需文件 #### 1. config.ts 插件配置文件,必须导出 `ModuleConfig` 类型的配置对象。 **基本结构:** ```typescript import { type ModuleConfig } from '/@/cool'; export default (): ModuleConfig => { return { // 是否启用插件 enable: true, // 插件加载顺序,值越大越先加载 order: 0, // 插件名称 label: '插件名称', // 插件描述 description: '插件功能描述', // 作者 author: 'COOL', // 版本号 version: '1.0.0', // 更新时间 updateTime: '2024-01-01', // Logo 地址(可选) logo: '', // 文档地址(可选) doc: 'https://example.com/docs', // 示例页面路径(可选) demo: '/demo/plugin-name', // 配置参数 options: { // 自定义配置项 }, // 全局组件注册 components: [], // 视图路由 views: [], // 页面路由 pages: [], // 顶部工具栏组件(可选) toolbar: { order: 1, pc: true, // PC 端是否显示 h5: false, // H5 端是否显示 component: import('./components/toolbar.vue') }, // 注入全局组件(可选) index: { component: import('./components/index.vue') }, // 安装时触发 install(app, options) { // 插件初始化逻辑 }, // 加载时触发 async onLoad(events) { // 异步加载逻辑 // 可以返回供其他模块使用的方法 return { customMethod() { // 自定义方法 } }; }, // 忽略配置(可选) ignore: { // 忽略进度条的请求 NProgress: ['/api/path1', '/api/path2'], // 忽略 token 的路由 token: ['/public/path1', '/public/path2'] } }; }; ``` **配置项说明:** | 配置项 | 类型 | 必填 | 说明 | |--------|------|------|------| | `enable` | `boolean` | 否 | 是否启用插件,默认 `true` | | `order` | `number` | 否 | 加载顺序,值越大越先加载,默认 `0` | | `label` | `string` | 是 | 插件显示名称 | | `description` | `string` | 是 | 插件功能描述 | | `author` | `string` | 是 | 作者信息 | | `version` | `string` | 是 | 版本号 | | `updateTime` | `string` | 是 | 更新时间 | | `logo` | `string` | 否 | Logo 图片地址 | | `doc` | `string` | 否 | 文档地址 | | `demo` | `string \| Array` | 否 | 示例页面路径或示例列表 | | `options` | `object` | 否 | 插件配置参数 | | `components` | `Array` | 否 | 全局组件列表 | | `views` | `Array` | 否 | 视图路由配置 | | `pages` | `Array` | 否 | 页面路由配置 | | `toolbar` | `object` | 否 | 顶部工具栏配置 | | `index` | `object` | 否 | 全局注入组件配置 | | `install` | `function` | 否 | 安装时执行的函数 | | `onLoad` | `function` | 否 | 加载时执行的异步函数 | | `ignore` | `object` | 否 | 忽略配置 | #### 2. index.ts 插件入口文件,导出插件需要对外暴露的变量和方法。 ```typescript // 导出工具函数 export * from './utils'; // 导出 Hooks export * from './hooks'; // 导出类型定义 export * from './types'; // 导出自定义方法 export function usePluginName() { return { // 自定义方法或变量 customMethod() { // 实现逻辑 } }; } ``` 其他目录根据需要进行创建开发。 在 `client\src\plugins\demoplugin` 中有一套示例代码以供学习使用。 ### 如何使用前端插件 通常是在模块中去调用插件导出的功能或者组件。 **示例:** 在示例 `client\src\plugins\demoplugin\index.ts` 中有如下一段代码: ```typescript /** * 插件信息 */ export const demoInfo = { name: 'demo', label: '前端插件测试', version: '1.0.0', author: '作者', description: '插件描述' }; ``` 这里导出了一个常量对象,包含该插件的信息,供其他模块导入使用(同理,其他由插件在 `index.ts` 中导出的变量、常量、功能函数、组件等都能被其他模块导入使用)。 现在想在测试视图 `client\src\modules\demo\views\plugintest.vue` 中导入使用这个插件提供的此常量,则过程如下: **Step 1:在插件中导出常量 `demoInfo`** ```typescript export const demoInfo = { name: 'demo', label: '前端插件测试', version: '1.0.0', author: '作者', description: '插件描述' }; ``` **Step 2:在前端(需要使用该插件导出的所需功能的地方)导入该常量** 在 Vue 组件的 ` ``` ##### 2. 组件自动注册(插件配置) 在 `config.ts` 中通过 `import.meta.glob` 扫描 `components` 目录下的所有组件文件,自动收集到 `components` 数组。 ```typescript // 组件全注册 components: Object.values(import.meta.glob('./components/**/*.{vue,tsx}')), ``` ##### 3. 模块系统注册(应用启动) 应用启动时,模块系统会: - 遍历所有模块的 `components` 数组 - 动态加载组件模块 - 使用 `app.component()` 全局注册组件 ```typescript // 注册组件 e.components?.forEach(async (c: any) => { const v = await (isFunction(c) ? c() : c); const n = v.default || v; if (n.name) { app.component(n.name, n); } }); ``` ##### 4. 组件使用(在表单中) **方式一:在 `cl-form` 中使用** ```typescript Form.value?.open({ title: '选择成员', items: [ { label: '单选', prop: 'userId', component: { name: 'cl-user-select', props: { multiple: false, onChange(val) { console.log(val); } } }, required: true }, { label: '多选', prop: 'userIds', component: { name: 'cl-user-select', props: { multiple: true, onChange(val) { console.log(val); } } }, required: true }, { label: '回显', prop: 'testId', component: { name: 'cl-user-select', props: { // 【很重要】立即刷新 immediate: true } } } ], form: { // 【很重要】手动设置值,实际根据接口返回 testId: 2 } }); ``` **方式二:直接在模板中使用** ```vue ``` ##### 5. 组件功能特性 组件支持的功能: - 单选/多选:通过 `multiple` 属性控制 - 按部门/角色分组:通过标签页切换 - 搜索过滤:支持关键字搜索 - 数据回显:通过 `v-model` 绑定值,支持 `immediate` 立即加载 - 表单验证:集成 CRUD 表单验证系统 ##### 6. 完整流程图 ``` ┌─────────────────────────────────────┐ │ 1. 组件定义 │ │ select.vue (cl-user-select) │ └──────────────┬──────────────────────┘ │ ▼ ┌─────────────────────────────────────┐ │ 2. 插件配置 │ │ config.ts │ │ components: glob('./components/**')│ └──────────────┬──────────────────────┘ │ ▼ ┌─────────────────────────────────────┐ │ 3. 模块系统加载 │ │ module.ts │ │ app.component(name, component) │ └──────────────┬──────────────────────┘ │ ▼ ┌─────────────────────────────────────┐ │ 4. 全局可用 │ │ 可在任何 Vue 组件中使用 │ │ │ └─────────────────────────────────────┘ ``` ##### 7. 关键点总结 1. **自动注册:** 通过 `import.meta.glob` 自动扫描组件,无需手动导入 2. **全局可用:** 注册后可在任何组件中直接使用,无需导入 3. **配置灵活:** 支持通过 `component.name` 和 `component.props` 配置 4. **表单集成:** 与 CRUD 表单系统深度集成,支持验证和回显 5. **数据绑定:** 支持 `v-model` 双向绑定和 `@change` 事件 这就是 `cl-user-select` 组件从定义到使用的完整流程。 ## 5. 后端插件开发 ### Step 1:拉取官方提供的后端插件开发脚手架 这里已经作为子模块添加在了 `/plugin` 目录中。 **Git 地址:** ```bash # GitHub git clone https://github.com/cool-team-official/cool-admin-midway-plugin.git # Gitee(如果你的网络不好,可以使用) git clone https://gitee.com/cool-team-official/cool-admin-midway-plugin.git ``` ### Step 2:认识脚手架的目录结构 ``` ├── .vscode # VSCode 的一些配置 ├── assets # 资源文件,如图片等 ├── dist # 运行编译后的时候自动生成 ├── release # 打包发布的时候自动生成 ├── src │ ├── index.ts # 入口文件,所有插件的功能统一集中到这个文件,不允许重命名 │ └── other.ts # 其他文件,可自定义,不是必须的 ├── test │ └── index.ts # 开发时的测试文件 ├── .gitattributes # Git 的一些配置 ├── .gitignore # Git 忽略文件 ├── LICENSE # 开源协议 ├── package.json # 依赖管理,项目信息 ├── plugin.json # 插件的配置信息 ├── README.md # 插件的介绍,会展示在插件的详情中 └── tsconfig.json # TypeScript 的配置文件 ``` ### Step 3:插件功能开发 #### 安装依赖 脚手架中提供了一些依赖,执行 `pnpm i` 进行安装,也可以自己再在 `plugin\package.json` 中进行增删,但不建议脚手架中有过多的依赖。 #### 开发示例 这里以一个简单的控制台输出语句功能为例: **1. 创建功能文件** 在 `plugin\src\other.ts`(允许重命名)中写一个简单的功能如下: ```typescript export function other() { console.log('这是另外一个文件'); } ``` **2. 在入口文件中导入** 在 `plugin\src\index.ts` 中导入 `other.ts` 提供的该功能函数: ```typescript import * as other from "./other"; ``` **3. 在方法中调用** 在 `show()` 中调用(当然可以在其他地方使用,也可以删除 `show()` 函数,`index.ts` 中的功能函数非固定): ```typescript /** * 展示插件信息 * @param a 参数a * @param b 参数b * @returns 插件信息 */ async show(a, b) { console.log("传参", a, b); other.other(); return this.pluginInfo; } ``` ### Step 4:测试功能是否可用 在 `plugin\test\index.ts` 中实例化插件,调用你要测试的功能,这里我想调用 `show()` 函数验证 `plugin\src\index.ts` 和 `plugin\src\other.ts` 中的功能可用性,则代码如下: ```typescript (async () => { // 调用插件方法 const res = await instance.show(1, 2); console.log(res); })(); ``` 然后在 plugin 的终端执行 `pnpm test`,如果功能正常,则会输出你想要的结果,这里应该输出三句话和插件信息: ``` 插件就绪 传参 1 2 这是另外一个文件 { name: '测试', key: 'test', hook: '', singleton: false, version: '1.0.0', description: '插件描述', author: '作者', logo: 'assets/logo.png', readme: 'README.md', config: { appId: 'E:/workspace/cool-admin-class/cool-admin-class/plugin/1.md', appSecret: 'xxxxx', filePath: 'E:/workspace/cool-admin-class/cool-admin-class/plugin/xxxxx' } } ``` ### Step 5:插件打包 在 `plugin\package.json` 中提供了三个命令: - `test`:测试 - `build`:编译 - `release`:打包 在 plugin 的终端中执行 `pnpm release` 进行打包,会生成一个 `release` 目录,其中会生成一个以 `.cool` 为后缀的文件,这就是插件包。 **打包说明:** - 只打包 `plugin\src` 目录下的代码 - 以 `plugin\src\index.ts` 作为入口点 - 包含所有被 `plugin\src\index.ts` 导入的模块 - `plugin\test` 目录不会被打包 ### Step 6:使用插件包 #### 安装插件 在前端的扩展管理-插件列表中进行选择安装,然后根据插件的文档进行插件的安装。 #### 后端调用 这是后端插件,故而通常在后端使用,这里的示例插件包提供了一个 `show()` 方法,调用示例如下: ```typescript @Inject() pluginService: PluginService; // 获取插件实例 const instance = await this.pluginService.getInstance('test'); // 调用show await instance.show(1, 2); ``` #### 前端调用 如果想从前端进行调用,则需要在后端为前端提供接口来使用。 **后端接口示例:** 在 `server\src\modules\demo\controller\open\plugintest.ts` 中写了一个调用示例。 **前端调用示例:** 在示例文件 `client\src\modules\demo\views\plugintest.vue` 中,相关代码如下: **控件:** ```vue 调用测试接口 ``` **调用处理:** ```typescript async function handleTest() { loading.value = true; result.value = ''; try { const data = await service.request({ url: '/open/demo/plugintest/test', method: 'GET' }); result.value = JSON.stringify(data, null, 2); ElMessage.success('调用成功'); console.log('接口返回数据:', data); } catch (error: any) { const errorMsg = error.message || error.code || '调用失败'; ElMessage.error(errorMsg); result.value = `错误: ${errorMsg}`; console.error('调用接口失败:', error); } finally { loading.value = false; } } ``` **预期输出:** 点击前端页面显示的调用按钮后即会调用该插件的 `show()` 方法,正确结果应该是在 server 的终端输出: ``` 插件就绪 传参 1 2 这是另外一个文件 { name: '测试', key: 'test', hook: '', singleton: false, version: '1.0.0', description: '插件描述', author: '作者', logo: 'assets/logo.png', readme: 'README.md', config: { appId: 'E:/workspace/cool-admin-class/cool-admin-class/plugin/1.md', appSecret: 'xxxxx', filePath: 'E:/workspace/cool-admin-class/cool-admin-class/plugin/xxxxx' } } ``` ### 总结 所有的插件开发与使用的流程基本如上,基于脚手架进行自定义功能开发,然后打包成 cool 包,再安装后使用。 ## 6. 模块开发 ## 添加前后端模块的步骤 ### 一、后端模块(cool-admin-midway) #### 1. 创建模块目录结构 在 `cool-admin-midway/src/modules/` 下创建模块目录,例如 `my-module/`: ``` my-module/ ├── config.ts # 模块配置文件(必需) ├── entity/ # 实体类目录 │ └── info.ts # 实体类 ├── service/ # 服务类目录 │ └── info.ts # 服务类 ├── controller/ # 控制器目录 │ └── admin/ # 后台管理接口 │ └── info.ts # 控制器 └── db.json # 数据库初始化数据(可选) ``` #### 2. 创建模块配置文件 `config.ts` ```typescript import { ModuleConfig } from '@cool-midway/core'; export default () => { return { name: '我的模块', description: '模块描述', middlewares: [], // 模块级中间件 globalMiddlewares: [], // 全局中间件 order: 0, // 加载顺序,值越大越优先 } as ModuleConfig; }; ``` #### 3. 创建实体类 `entity/info.ts` ```typescript import { BaseEntity } from '../../base/entity/base'; import { Column, Entity } from 'typeorm'; @Entity('my_module_info') export class MyModuleInfoEntity extends BaseEntity { @Column({ comment: '名称' }) name: string; @Column({ comment: '描述', nullable: true }) description: string; } ``` #### 4. 创建服务类 `service/info.ts` ```typescript import { Provide } from '@midwayjs/core'; import { BaseService } from '@cool-midway/core'; import { InjectEntityModel } from '@midwayjs/typeorm'; import { Repository } from 'typeorm'; import { MyModuleInfoEntity } from '../entity/info'; @Provide() export class MyModuleInfoService extends BaseService { @InjectEntityModel(MyModuleInfoEntity) myModuleInfoEntity: Repository; // 可以在这里添加自定义业务逻辑方法 } ``` #### 5. 创建控制器 `controller/admin/info.ts` ```typescript import { Provide } from '@midwayjs/core'; import { CoolController, BaseController } from '@cool-midway/core'; import { MyModuleInfoEntity } from '../../entity/info'; import { MyModuleInfoService } from '../../service/info'; @Provide() @CoolController({ api: ['add', 'delete', 'update', 'info', 'list', 'page'], // 自动生成CRUD接口 entity: MyModuleInfoEntity, service: MyModuleInfoService, listQueryOp: { keyWordLikeFields: ['name'], // 关键字搜索字段 }, }) export class AdminMyModuleInfoController extends BaseController { // 可以在这里添加自定义接口 } ``` #### 6. 数据库初始化(可选) 创建 `db.json` 文件,用于初始化菜单等数据: ```json { "menus": [ { "name": "我的模块", "router": "/my-module/list", "perms": ["my-module:info:page", "my-module:info:list"], "type": 1, "icon": "icon-list", "orderNum": 100, "viewPath": "my-module/views/list" } ] } ``` --- ### 二、前端模块(cool-admin-vue) #### 1. 创建模块目录结构 在 `cool-admin-vue/src/modules/` 下创建模块目录,例如 `my-module/`: ``` my-module/ ├── config.ts # 模块配置文件(必需) ├── views/ # 页面视图目录 │ └── list.vue # 列表页面 ├── components/ # 组件目录(可选) ├── store/ # 状态管理(可选) ├── locales/ # 国际化文件(可选) │ ├── zh-cn.json │ ├── zh-tw.json │ └── en.json └── index.ts # 模块导出(可选) ``` #### 2. 创建模块配置文件 `config.ts` ```typescript import { type ModuleConfig } from '/@/cool'; export default (): ModuleConfig => { return { // 忽略 NProgress 的路径 ignore: { NProgress: ['/my-module/info/add'] }, // 注册组件 components: [ () => import('./components/my-component.vue') ], // 注册路由视图 views: [ { meta: { label: '我的模块' }, path: '/my-module/list', component: () => import('./views/list.vue') } ], // 模块加载时的回调 onLoad({ hasToken }) { // 可以在这里做一些初始化操作 } }; }; ``` #### 3. 创建列表页面 `views/list.vue` ```vue ``` #### 4. 国际化文件(可选) 创建 `locales/zh-cn.json`: ```json { "我的模块": "我的模块", "搜索名称": "搜索名称", "名称": "名称", "描述": "描述" } ``` --- ### 三、关键说明 1. 后端控制器自动注册: - 使用 `@CoolController` 装饰器的控制器会被自动扫描和注册 - 通过 `api` 参数可自动生成 CRUD 接口(add, delete, update, info, list, page) 2. 前端服务自动生成: - 前端服务通过访问后端的 `/app/eps` 接口自动生成 - 服务路径格式:`service.模块名.控制器名` - 例如:`service.myModule.info` 对应后端的 `AdminMyModuleInfoController` 3. 路由自动注册: - 前端在 `config.ts` 中定义的 `views` 会自动注册到路由 - 路径需要与后端菜单配置的 `router` 字段对应 4. 模块加载顺序: - 通过 `order` 字段控制,值越大越优先加载 - 默认值为 0 5. 权限控制: - 后端控制器会自动生成权限标识,格式:`模块名:控制器名:操作` - 例如:`my-module:info:add`、`my-module:info:delete` --- ### 四、参考示例 可以参考现有模块: - 简单模块:`dict`(字典管理) - 复杂模块:`user`(用户管理) - 带组件的模块:`space`(文件空间) 按照以上步骤创建文件后,模块会自动被系统识别和加载。