mirror of
https://github.com/cool-team-official/cool-admin-vue.git
synced 2025-12-10 11:52:53 +00:00
465 lines
7.8 KiB
Plaintext
465 lines
7.8 KiB
Plaintext
---
|
||
description: module | plugins 模块、插件
|
||
globs:
|
||
---
|
||
# 模块/插件开发
|
||
|
||
## 目录结构
|
||
|
||
在 `src/modules` 或 `src/plugins` 下添加一个目录 `demo`:
|
||
|
||
```js
|
||
demo
|
||
├──pages // 页面路由
|
||
├──views // 视图路由
|
||
├──hooks // 常用函数
|
||
├──components // 常用组件
|
||
├──directives // 指令
|
||
├──static // 静态文件目录
|
||
├──store // 状态管理
|
||
├──... // 其他自定义文件
|
||
├──config.ts // 配置文件
|
||
└──index.ts // 入口文件
|
||
```
|
||
|
||
::: warning
|
||
约定的目录名称不可修改,但可自行添加或者删除。
|
||
:::
|
||
|
||
## pages、views
|
||
|
||
1. 页面参与权限控制,所以不主动注册目录下的路由,通过 `菜单列表` 中配置注册。或者在 `config.ts` 中手动配置:
|
||
|
||
```js
|
||
import { type ModuleConfig } from "/@/cool";
|
||
|
||
export default (): ModuleConfig => {
|
||
return {
|
||
views: [
|
||
{
|
||
path: "/demo",
|
||
meta: {
|
||
label: "测试",
|
||
},
|
||
component: () => import("./views/demo.vue"),
|
||
},
|
||
],
|
||
pages: [
|
||
{
|
||
path: "/demo2",
|
||
meta: {
|
||
label: "测试",
|
||
},
|
||
component: () => import("./pages/demo.vue"),
|
||
},
|
||
],
|
||
};
|
||
};
|
||
```
|
||
|
||
2. 使页面参与路由缓存,配置 `name` 参数
|
||
|
||
:::warning
|
||
|
||
`path` 与 `name` 的匹配规则:
|
||
|
||
- /demo/t1 = demo-t1
|
||
- /demo/t1-det = demo-t1-det
|
||
|
||
:::
|
||
|
||
方式 1:
|
||
|
||
```html
|
||
<script lang="ts" setup>
|
||
defineOptions({
|
||
name: "demo",
|
||
});
|
||
</script>
|
||
```
|
||
|
||
方式 2:
|
||
|
||
```html
|
||
<script lang="ts">
|
||
export default defineComponent({
|
||
name: "demo",
|
||
});
|
||
</script>
|
||
```
|
||
|
||
## components
|
||
|
||
目录下的组件,全局注册配置方法如下:
|
||
|
||
```js
|
||
import { ModuleConfig } from "/@/cool";
|
||
|
||
export default (): ModuleConfig => {
|
||
return {
|
||
components: [
|
||
import("./components/demo.vue"),
|
||
import("./components/demo1.vue"),
|
||
],
|
||
};
|
||
};
|
||
```
|
||
|
||
## directives
|
||
|
||
`directives` 会以目录下的文件名分别注册指令
|
||
|
||
```ts
|
||
// demo/directives/test.ts
|
||
export default {
|
||
created(el, binding) {},
|
||
mounted() {},
|
||
...
|
||
};
|
||
```
|
||
|
||
使用
|
||
|
||
```html
|
||
<div v-test></div>
|
||
```
|
||
|
||
## store
|
||
|
||
使用 `pinia` 的推荐写法:
|
||
|
||
```ts
|
||
import { defineStore } from "pinia";
|
||
import { ref } from "vue";
|
||
|
||
export const useTestStore = defineStore("test", function () {
|
||
const count = ref(0);
|
||
|
||
function add() {
|
||
count.value += 1;
|
||
}
|
||
|
||
return {
|
||
count,
|
||
add,
|
||
};
|
||
});
|
||
```
|
||
|
||
使用
|
||
|
||
```ts
|
||
import { useTestStore } from "/$/demo/store";
|
||
|
||
const test = useTestStore();
|
||
|
||
test.add();
|
||
|
||
console.log(test.count); // 1
|
||
```
|
||
|
||
::: tip
|
||
参考 `base` 模块下 `store` 的导出方式
|
||
:::
|
||
|
||
## config.ts
|
||
|
||
模块的配置,程序运行时会读取该文件。
|
||
|
||
- 全局组件、路由的导入
|
||
|
||
- 事件钩子
|
||
|
||
输入 `module-config` 关键字,`vscode` 中会自动生成:
|
||
|
||
```ts
|
||
import { ModuleConfig } from "/@/cool";
|
||
import { Vue } from "vue";
|
||
|
||
export default (): ModuleConfig => {
|
||
return {
|
||
// 是否启用
|
||
enable: true,
|
||
|
||
// 插件名称
|
||
label: "插件名称",
|
||
|
||
// 插件描述
|
||
description: "插件描述",
|
||
|
||
// 作者
|
||
author: "作者",
|
||
version: "1.0.0",
|
||
updateTime: "2024-02-02",
|
||
logo: "",
|
||
|
||
// 忽略
|
||
ignore: {
|
||
// 忽略进度条的请求
|
||
NProgress: [
|
||
"/base/open/eps",
|
||
"/base/comm/person",
|
||
"/base/comm/permmenu",
|
||
"/base/comm/upload",
|
||
"/base/comm/uploadMode",
|
||
],
|
||
|
||
// 忽略 token 的路由
|
||
token: ["/login", "/401", "/403", "/404", "/500", "/502"],
|
||
},
|
||
|
||
// 排序
|
||
order: 0,
|
||
|
||
// 配置参数
|
||
options: {
|
||
name: "神仙",
|
||
},
|
||
|
||
// 示例页面
|
||
demo: [
|
||
{
|
||
name: "基础用法",
|
||
component: () => import("..."),
|
||
},
|
||
],
|
||
|
||
// 注册全局组件
|
||
components: [],
|
||
|
||
// 视图路由
|
||
views: [],
|
||
|
||
// 页面路由
|
||
pages: [],
|
||
|
||
// 顶部工具栏
|
||
toolbar: {
|
||
order: 1,
|
||
pc: true, // 是否在 pc 端显示
|
||
h5: true, // 是否在 h5 端显示
|
||
component: import("./components/index.vue"),
|
||
},
|
||
|
||
// 注入全局组件
|
||
index: {
|
||
component: import("./components/index.vue"),
|
||
},
|
||
|
||
// 安装时触发
|
||
install(app: Vue) {},
|
||
|
||
// 加载时触发
|
||
onLoad(events) {},
|
||
};
|
||
};
|
||
```
|
||
|
||
- order 模块加载顺序,值越大越先
|
||
|
||
- options 提供给外部使用的参数配置:
|
||
|
||
```ts
|
||
import { ModuleConfig } from "/@/cool";
|
||
|
||
export default (): ModuleConfig => {
|
||
return {
|
||
options: {
|
||
// 尺寸
|
||
size: 120,
|
||
// 显示文案
|
||
text: "选择文件",
|
||
// 限制
|
||
limit: {
|
||
// 上传最大数量
|
||
upload: 9,
|
||
// 文件空间选择数
|
||
select: 9,
|
||
// 上传大小限制
|
||
size: 100,
|
||
},
|
||
},
|
||
};
|
||
};
|
||
```
|
||
|
||
获取方式:
|
||
|
||
```ts
|
||
import { module } from "/@/cool";
|
||
|
||
const config = module.config("模块名");
|
||
```
|
||
|
||
- components 提供全局的组件:
|
||
|
||
```ts
|
||
import type { ModuleConfig } from "/@/cool";
|
||
|
||
export default (): ModuleConfig => {
|
||
return {
|
||
components: [import("./components/test.vue")],
|
||
};
|
||
};
|
||
```
|
||
|
||
批量导入可以使用 [import.meta.glob](mdc:https:/vitejs.dev/guide/features.html#glob-import) 方法:
|
||
|
||
```ts
|
||
import { ModuleConfig } from "/@/cool";
|
||
|
||
export default (): ModuleConfig => {
|
||
return {
|
||
components: Object.values(import.meta.glob("./components/**/*")),
|
||
};
|
||
};
|
||
```
|
||
|
||
- views 全局注册的视图路由,存放在 `/` 中的子路由 `children`:
|
||
|
||
```ts
|
||
import { ModuleConfig } from "/@/cool";
|
||
|
||
export default (): ModuleConfig => {
|
||
return {
|
||
views: [
|
||
{
|
||
path: "/test",
|
||
meta: {
|
||
label: "测试中心",
|
||
},
|
||
component: () => import("./views/test.vue"),
|
||
},
|
||
],
|
||
};
|
||
};
|
||
```
|
||
|
||
- pages 全局注册的页面路由:
|
||
|
||
```ts
|
||
import { ModuleConfig } from "/@/cool";
|
||
|
||
export default (): ModuleConfig => {
|
||
return {
|
||
pages: [
|
||
{
|
||
path: "/test",
|
||
meta: {
|
||
label: "测试中心",
|
||
},
|
||
component: () => import("./views/test.vue"),
|
||
},
|
||
],
|
||
};
|
||
};
|
||
```
|
||
|
||
- install 模块安装时触发。用于预先处理:
|
||
|
||
```ts
|
||
import { ModuleConfig } from "/@/cool";
|
||
import { Vue } from "vue";
|
||
|
||
export default (): ModuleConfig => {
|
||
return {
|
||
install(app: Vue) {
|
||
// 注册组件
|
||
app.component("test", Test);
|
||
|
||
// 注册指令
|
||
app.directive("focus", {
|
||
created(el, bind) {},
|
||
});
|
||
},
|
||
};
|
||
};
|
||
```
|
||
|
||
- onLoad 模块安装时触发,预先加载数据,如菜单配置、用户信息:
|
||
|
||
1. 使用 `await` 等待加载完成后往下执行
|
||
|
||
2. 可往下模块导出某个方法和变量,如 `hasToken` 验证是否有登陆
|
||
|
||
```ts
|
||
import { ModuleConfig } from "/@/cool";
|
||
import { Vue } from "vue";
|
||
|
||
export default (): ModuleConfig => {
|
||
return {
|
||
async onLoad() {
|
||
const { user, menu } = useStore();
|
||
|
||
if (user.token) {
|
||
// 获取用户信息
|
||
user.get();
|
||
// 获取菜单权限
|
||
await menu.get();
|
||
}
|
||
|
||
return {
|
||
async hasToken(cb: () => Promise<any> | void) {
|
||
if (user.token) {
|
||
if (cb) await cb();
|
||
}
|
||
},
|
||
};
|
||
},
|
||
};
|
||
};
|
||
```
|
||
|
||
其他模块中接收 `hasToken` 方法:
|
||
|
||
```ts
|
||
import { ModuleConfig } from "/@/cool";
|
||
import { useDict } from "./index";
|
||
|
||
export default (): ModuleConfig => {
|
||
return {
|
||
onLoad({ hasToken }) {
|
||
const { dict } = useDict();
|
||
|
||
hasToken(() => {
|
||
dict.refresh();
|
||
});
|
||
},
|
||
};
|
||
};
|
||
```
|
||
|
||
## index.ts
|
||
|
||
该模块需要对外开放的变量及方法,方便于别人直接使用:
|
||
|
||
```ts
|
||
// modules/test/index.ts
|
||
import { useStore } from "./store";
|
||
|
||
export function useTest() {
|
||
return {
|
||
// 导出 pinia
|
||
...useStore(),
|
||
|
||
// 自定义方法
|
||
test() {},
|
||
|
||
// 自定义变量
|
||
data: {
|
||
description: "数据描述",
|
||
},
|
||
};
|
||
}
|
||
```
|
||
|
||
导出命名规则 `useBase` `useDemo` `useDict` use + 模块名
|
||
|
||
使用:
|
||
|
||
```ts
|
||
import { useTest } from "/$/test";
|
||
|
||
const { data, test } = useTest();
|
||
```
|