初始提交:项目迁移,前端(管理端)
This commit is contained in:
305
cool-admin-vue/.cursor/rules/adv-search.mdc
Normal file
305
cool-admin-vue/.cursor/rules/adv-search.mdc
Normal file
@@ -0,0 +1,305 @@
|
||||
---
|
||||
description: cl-adv-search 组件示例
|
||||
globs: *.tsx, *.ts, *.vue
|
||||
---
|
||||
## 起步 示例
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div class="scope">
|
||||
<div class="h">
|
||||
<el-tag size="small" effect="dark" disable-transitions>base</el-tag>
|
||||
<span>起步</span>
|
||||
</div>
|
||||
|
||||
<div class="c">
|
||||
<el-button @click="open">预览</el-button>
|
||||
<demo-code :files="['adv-search/base.vue']" />
|
||||
|
||||
<!-- 自定义表格组件 -->
|
||||
<cl-dialog v-model="visible" title="起步" width="80%">
|
||||
<cl-crud ref="Crud">
|
||||
<cl-row>
|
||||
<!--【很重要】高级搜索组件按钮 -->
|
||||
<cl-adv-btn />
|
||||
</cl-row>
|
||||
|
||||
<cl-row>
|
||||
<cl-table ref="Table" />
|
||||
</cl-row>
|
||||
|
||||
<cl-row>
|
||||
<cl-flex1 />
|
||||
<cl-pagination />
|
||||
</cl-row>
|
||||
|
||||
<!--【很重要】高级搜索组件 -->
|
||||
<cl-adv-search ref="AdvSearch" />
|
||||
</cl-crud>
|
||||
</cl-dialog>
|
||||
</div>
|
||||
|
||||
<div class="f">
|
||||
<span class="date">2024-01-01</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useCrud, useAdvSearch, useTable } from '@cool-vue/crud';
|
||||
import { ref } from 'vue';
|
||||
import { useDict } from '/$/dict';
|
||||
|
||||
const { dict } = useDict();
|
||||
|
||||
// cl-crud 配置
|
||||
const Crud = useCrud(
|
||||
{
|
||||
service: 'test'
|
||||
},
|
||||
app => {
|
||||
app.refresh();
|
||||
}
|
||||
);
|
||||
|
||||
// cl-table 配置
|
||||
const Table = useTable({
|
||||
autoHeight: false,
|
||||
contextMenu: ['refresh'],
|
||||
|
||||
columns: [
|
||||
{
|
||||
label: '姓名',
|
||||
prop: 'name',
|
||||
minWidth: 140
|
||||
},
|
||||
{
|
||||
label: '手机号',
|
||||
prop: 'phone',
|
||||
minWidth: 140
|
||||
},
|
||||
{
|
||||
label: '工作',
|
||||
prop: 'occupation',
|
||||
dict: dict.get('occupation'),
|
||||
minWidth: 140
|
||||
},
|
||||
{
|
||||
label: '创建时间',
|
||||
prop: 'createTime',
|
||||
minWidth: 170,
|
||||
sortable: 'desc'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
// cl-adv-search 配置
|
||||
//【很重要】该组件基于 cl-form 故很多示例都可复用
|
||||
const AdvSearch = useAdvSearch({
|
||||
// 配置如 cl-form 一样
|
||||
items: [
|
||||
{
|
||||
label: '姓名',
|
||||
prop: 'name',
|
||||
component: {
|
||||
name: 'el-input',
|
||||
props: {
|
||||
clearable: true
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '手机号',
|
||||
prop: 'phone',
|
||||
component: {
|
||||
name: 'el-input',
|
||||
props: {
|
||||
clearable: true
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '工作',
|
||||
prop: 'occupation',
|
||||
component: {
|
||||
name: 'cl-select',
|
||||
props: {
|
||||
tree: true,
|
||||
checkStrictly: true,
|
||||
options: dict.get('occupation')
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
function refresh(params?: any) {
|
||||
Crud.value?.refresh(params);
|
||||
}
|
||||
|
||||
const visible = ref(false);
|
||||
|
||||
function open() {
|
||||
visible.value = true;
|
||||
}
|
||||
</script>
|
||||
|
||||
```
|
||||
|
||||
## 自定义 示例
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div class="scope">
|
||||
<div class="h">
|
||||
<el-tag size="small" effect="dark" disable-transitions>custom</el-tag>
|
||||
<span>自定义</span>
|
||||
</div>
|
||||
|
||||
<div class="c">
|
||||
<el-button @click="open">预览</el-button>
|
||||
<demo-code :files="['adv-search/custom.vue']" />
|
||||
|
||||
<!-- 自定义表格组件 -->
|
||||
<cl-dialog v-model="visible" title="自定义" width="80%">
|
||||
<cl-crud ref="Crud">
|
||||
<cl-row>
|
||||
<!--【很重要】高级搜索组件按钮 -->
|
||||
<cl-adv-btn>更多搜索</cl-adv-btn>
|
||||
</cl-row>
|
||||
|
||||
<cl-row>
|
||||
<cl-table ref="Table" />
|
||||
</cl-row>
|
||||
|
||||
<cl-row>
|
||||
<cl-flex1 />
|
||||
<cl-pagination />
|
||||
</cl-row>
|
||||
|
||||
<!--【很重要】高级搜索组件 -->
|
||||
<cl-adv-search ref="AdvSearch">
|
||||
<!-- 自定义按钮 -->
|
||||
<template #slot-btn>
|
||||
<el-button @click="toSearch">自定义</el-button>
|
||||
</template>
|
||||
</cl-adv-search>
|
||||
</cl-crud>
|
||||
</cl-dialog>
|
||||
</div>
|
||||
|
||||
<div class="f">
|
||||
<span class="date">2024-01-01</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useCrud, useAdvSearch, useTable } from '@cool-vue/crud';
|
||||
import { ref } from 'vue';
|
||||
import { useDict } from '/$/dict';
|
||||
|
||||
const { dict } = useDict();
|
||||
|
||||
// cl-crud 配置
|
||||
const Crud = useCrud(
|
||||
{
|
||||
service: 'test'
|
||||
},
|
||||
app => {
|
||||
app.refresh();
|
||||
}
|
||||
);
|
||||
|
||||
// cl-table 配置
|
||||
const Table = useTable({
|
||||
autoHeight: false,
|
||||
contextMenu: ['refresh'],
|
||||
|
||||
columns: [
|
||||
{
|
||||
label: '姓名',
|
||||
prop: 'name',
|
||||
minWidth: 140
|
||||
},
|
||||
{
|
||||
label: '手机号',
|
||||
prop: 'phone',
|
||||
minWidth: 140
|
||||
},
|
||||
{
|
||||
label: '工作',
|
||||
prop: 'occupation',
|
||||
dict: dict.get('occupation'),
|
||||
minWidth: 140
|
||||
},
|
||||
{
|
||||
label: '创建时间',
|
||||
prop: 'createTime',
|
||||
minWidth: 170,
|
||||
sortable: 'desc'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
// cl-adv-search 配置
|
||||
//【很重要】该组件基于 cl-form 故很多示例都可复用
|
||||
const AdvSearch = useAdvSearch({
|
||||
// 配置如 cl-form 一样
|
||||
items: [
|
||||
{
|
||||
label: '姓名',
|
||||
prop: 'name',
|
||||
component: {
|
||||
name: 'el-input',
|
||||
props: {
|
||||
clearable: true
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '手机号',
|
||||
prop: 'phone',
|
||||
component: {
|
||||
name: 'el-input',
|
||||
props: {
|
||||
clearable: true
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '工作',
|
||||
prop: 'occupation',
|
||||
component: {
|
||||
name: 'cl-select',
|
||||
props: {
|
||||
tree: true,
|
||||
checkStrictly: true,
|
||||
options: dict.get('occupation')
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
title: '更多搜索',
|
||||
size: '50%',
|
||||
op: ['close', 'search', 'slot-btn']
|
||||
});
|
||||
|
||||
function refresh(params?: any) {
|
||||
Crud.value?.refresh(params);
|
||||
}
|
||||
|
||||
// 自定义搜索
|
||||
function toSearch() {
|
||||
refresh({ page: 1 });
|
||||
}
|
||||
|
||||
const visible = ref(false);
|
||||
|
||||
function open() {
|
||||
visible.value = true;
|
||||
}
|
||||
</script>
|
||||
|
||||
```
|
||||
1480
cool-admin-vue/.cursor/rules/crud.mdc
Normal file
1480
cool-admin-vue/.cursor/rules/crud.mdc
Normal file
File diff suppressed because it is too large
Load Diff
1820
cool-admin-vue/.cursor/rules/form.mdc
Normal file
1820
cool-admin-vue/.cursor/rules/form.mdc
Normal file
File diff suppressed because it is too large
Load Diff
464
cool-admin-vue/.cursor/rules/module.mdc
Normal file
464
cool-admin-vue/.cursor/rules/module.mdc
Normal file
@@ -0,0 +1,464 @@
|
||||
---
|
||||
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();
|
||||
```
|
||||
743
cool-admin-vue/.cursor/rules/search.mdc
Normal file
743
cool-admin-vue/.cursor/rules/search.mdc
Normal file
@@ -0,0 +1,743 @@
|
||||
---
|
||||
description: cl-search 组件示例
|
||||
globs: *.tsx, *.ts, *.vue
|
||||
---
|
||||
## 起步 示例
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div class="scope">
|
||||
<div class="h">
|
||||
<el-tag size="small" effect="dark" disable-transitions>base</el-tag>
|
||||
<span>起步</span>
|
||||
</div>
|
||||
|
||||
<div class="c">
|
||||
<el-button @click="open">预览</el-button>
|
||||
<demo-code :files="['search/base.vue']" />
|
||||
|
||||
<!-- 自定义表格组件 -->
|
||||
<cl-dialog v-model="visible" title="起步" width="80%">
|
||||
<cl-crud ref="Crud">
|
||||
<cl-row>
|
||||
<!--【很重要】搜索组件 -->
|
||||
<cl-search ref="Search" />
|
||||
</cl-row>
|
||||
|
||||
<cl-row>
|
||||
<cl-table ref="Table" />
|
||||
</cl-row>
|
||||
|
||||
<cl-row>
|
||||
<cl-flex1 />
|
||||
<cl-pagination />
|
||||
</cl-row>
|
||||
</cl-crud>
|
||||
</cl-dialog>
|
||||
</div>
|
||||
|
||||
<div class="f">
|
||||
<span class="date">2024-01-01</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useCrud, useSearch, useTable } from '@cool-vue/crud';
|
||||
import { ref } from 'vue';
|
||||
import { useDict } from '/$/dict';
|
||||
|
||||
const { dict } = useDict();
|
||||
|
||||
// cl-crud 配置
|
||||
const Crud = useCrud(
|
||||
{
|
||||
service: 'test'
|
||||
},
|
||||
app => {
|
||||
app.refresh();
|
||||
}
|
||||
);
|
||||
|
||||
// cl-table 配置
|
||||
const Table = useTable({
|
||||
autoHeight: false,
|
||||
contextMenu: ['refresh'],
|
||||
|
||||
columns: [
|
||||
{
|
||||
label: '姓名',
|
||||
prop: 'name',
|
||||
minWidth: 140
|
||||
},
|
||||
{
|
||||
label: '手机号',
|
||||
prop: 'phone',
|
||||
minWidth: 140
|
||||
},
|
||||
{
|
||||
label: '工作',
|
||||
prop: 'occupation',
|
||||
dict: dict.get('occupation'),
|
||||
minWidth: 140
|
||||
},
|
||||
{
|
||||
label: '创建时间',
|
||||
prop: 'createTime',
|
||||
minWidth: 170,
|
||||
sortable: 'desc'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
// cl-search 配置
|
||||
//【很重要】该组件基于 cl-form 故很多示例都可复用
|
||||
const Search = useSearch({
|
||||
// 配置如 cl-form 一样
|
||||
items: [
|
||||
{
|
||||
label: '姓名',
|
||||
prop: 'name',
|
||||
component: {
|
||||
name: 'el-input',
|
||||
props: {
|
||||
clearable: true,
|
||||
|
||||
// 值改变的时候刷新列表
|
||||
onChange(val: string) {
|
||||
refresh({
|
||||
name: val,
|
||||
page: 1
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '手机号',
|
||||
prop: 'phone',
|
||||
component: {
|
||||
name: 'el-input',
|
||||
props: {
|
||||
clearable: true
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '工作',
|
||||
prop: 'occupation',
|
||||
component: {
|
||||
name: 'cl-select',
|
||||
props: {
|
||||
tree: true,
|
||||
checkStrictly: true,
|
||||
options: dict.get('occupation')
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
onChange(data, prop) {
|
||||
console.log(data, prop);
|
||||
}
|
||||
});
|
||||
|
||||
function refresh(params?: any) {
|
||||
Crud.value?.refresh(params);
|
||||
}
|
||||
|
||||
const visible = ref(false);
|
||||
|
||||
function open() {
|
||||
visible.value = true;
|
||||
}
|
||||
</script>
|
||||
|
||||
```
|
||||
|
||||
## 折叠 示例
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div class="scope">
|
||||
<div class="h">
|
||||
<el-tag size="small" effect="dark" disable-transitions>collapse</el-tag>
|
||||
<span>折叠</span>
|
||||
</div>
|
||||
|
||||
<div class="c">
|
||||
<el-button @click="open">预览</el-button>
|
||||
<demo-code :files="['search/collapse.vue']" />
|
||||
|
||||
<!-- 折叠表格组件 -->
|
||||
<cl-dialog v-model="visible" title="折叠" width="80%">
|
||||
<cl-crud ref="Crud">
|
||||
<!--【collapse】折叠参数,【inline】是否行内 -->
|
||||
<cl-search ref="Search" reset-btn collapse :inline="false" />
|
||||
|
||||
<cl-row>
|
||||
<cl-table ref="Table" />
|
||||
</cl-row>
|
||||
|
||||
<cl-row>
|
||||
<cl-flex1 />
|
||||
<cl-pagination />
|
||||
</cl-row>
|
||||
</cl-crud>
|
||||
</cl-dialog>
|
||||
</div>
|
||||
|
||||
<div class="f">
|
||||
<span class="date">2024-12-26</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useCrud, useSearch, useTable } from '@cool-vue/crud';
|
||||
import { ref } from 'vue';
|
||||
import { useDict } from '/$/dict';
|
||||
import { range } from 'lodash-es';
|
||||
|
||||
const { dict } = useDict();
|
||||
|
||||
// cl-crud 配置
|
||||
const Crud = useCrud(
|
||||
{
|
||||
service: 'test'
|
||||
},
|
||||
app => {
|
||||
app.refresh();
|
||||
}
|
||||
);
|
||||
|
||||
// cl-table 配置
|
||||
const Table = useTable({
|
||||
autoHeight: false,
|
||||
contextMenu: ['refresh'],
|
||||
|
||||
columns: [
|
||||
{
|
||||
label: '姓名',
|
||||
prop: 'name',
|
||||
minWidth: 140
|
||||
},
|
||||
{
|
||||
label: '手机号',
|
||||
prop: 'phone',
|
||||
minWidth: 140
|
||||
},
|
||||
{
|
||||
label: '工作',
|
||||
prop: 'occupation',
|
||||
dict: dict.get('occupation'),
|
||||
minWidth: 140
|
||||
},
|
||||
{
|
||||
label: '创建时间',
|
||||
prop: 'createTime',
|
||||
minWidth: 170,
|
||||
sortable: 'desc'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
// cl-search 配置
|
||||
const Search = useSearch({
|
||||
items: [
|
||||
...range(20).map(i => {
|
||||
return {
|
||||
label: '输入框',
|
||||
prop: `T${i + 1}`,
|
||||
component: {
|
||||
name: 'el-input'
|
||||
}
|
||||
};
|
||||
})
|
||||
]
|
||||
});
|
||||
|
||||
function refresh(params?: any) {
|
||||
Crud.value?.refresh(params);
|
||||
}
|
||||
|
||||
const visible = ref(false);
|
||||
|
||||
function open() {
|
||||
visible.value = true;
|
||||
}
|
||||
</script>
|
||||
x
|
||||
|
||||
```
|
||||
|
||||
## 自定义 示例
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div class="scope">
|
||||
<div class="h">
|
||||
<el-tag size="small" effect="dark" disable-transitions>custom</el-tag>
|
||||
<span>自定义</span>
|
||||
</div>
|
||||
|
||||
<div class="c">
|
||||
<el-button @click="open">预览</el-button>
|
||||
<demo-code :files="['search/custom.vue']" />
|
||||
|
||||
<!-- 自定义表格组件 -->
|
||||
<cl-dialog v-model="visible" title="自定义" width="80%">
|
||||
<cl-crud ref="Crud">
|
||||
<cl-row>
|
||||
<!--【很重要】搜索组件 -->
|
||||
<cl-search
|
||||
ref="Search"
|
||||
:reset-btn="true"
|
||||
:on-load="onLoad"
|
||||
:on-search="onSearch"
|
||||
>
|
||||
<!-- 自定义按钮 -->
|
||||
<template #buttons="scope">
|
||||
<el-button @click="toSearch(scope)">自定义按钮</el-button>
|
||||
</template>
|
||||
</cl-search>
|
||||
</cl-row>
|
||||
|
||||
<cl-row>
|
||||
<cl-table ref="Table" />
|
||||
</cl-row>
|
||||
|
||||
<cl-row>
|
||||
<cl-flex1 />
|
||||
<cl-pagination />
|
||||
</cl-row>
|
||||
</cl-crud>
|
||||
</cl-dialog>
|
||||
</div>
|
||||
|
||||
<div class="f">
|
||||
<span class="date">2024-01-01</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useCrud, useSearch, useTable } from '@cool-vue/crud';
|
||||
import { ref } from 'vue';
|
||||
import { useDict } from '/$/dict';
|
||||
import { ElMessage } from 'element-plus';
|
||||
|
||||
const { dict } = useDict();
|
||||
|
||||
// cl-crud 配置
|
||||
const Crud = useCrud(
|
||||
{
|
||||
service: 'test'
|
||||
},
|
||||
app => {
|
||||
app.refresh();
|
||||
}
|
||||
);
|
||||
|
||||
// cl-table 配置
|
||||
const Table = useTable({
|
||||
autoHeight: false,
|
||||
contextMenu: ['refresh'],
|
||||
|
||||
columns: [
|
||||
{
|
||||
label: '姓名',
|
||||
prop: 'name',
|
||||
minWidth: 140
|
||||
},
|
||||
{
|
||||
label: '手机号',
|
||||
prop: 'phone',
|
||||
minWidth: 140
|
||||
},
|
||||
{
|
||||
label: '工作',
|
||||
prop: 'occupation',
|
||||
dict: dict.get('occupation'),
|
||||
minWidth: 140
|
||||
},
|
||||
{
|
||||
label: '创建时间',
|
||||
prop: 'createTime',
|
||||
minWidth: 170,
|
||||
sortable: 'desc'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
// cl-search 配置
|
||||
//【很重要】该组件基于 cl-form 故很多示例都可复用
|
||||
const Search = useSearch({
|
||||
// 配置如 cl-form 一样
|
||||
items: [
|
||||
{
|
||||
label: '姓名',
|
||||
prop: 'name',
|
||||
component: {
|
||||
name: 'el-input',
|
||||
props: {
|
||||
clearable: true,
|
||||
|
||||
// 值改变的时候刷新列表
|
||||
onChange(val: string) {
|
||||
refresh({
|
||||
name: val,
|
||||
page: 1
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '手机号',
|
||||
prop: 'phone',
|
||||
component: {
|
||||
name: 'el-input',
|
||||
props: {
|
||||
clearable: true
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '工作',
|
||||
prop: 'occupation',
|
||||
component: {
|
||||
name: 'cl-select',
|
||||
props: {
|
||||
tree: true,
|
||||
checkStrictly: true,
|
||||
options: dict.get('occupation')
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
function refresh(params?: any) {
|
||||
Crud.value?.refresh(params);
|
||||
}
|
||||
|
||||
// cl-search 初始化
|
||||
function onLoad(data: any) {
|
||||
data.name = '白小纯';
|
||||
}
|
||||
|
||||
// cl-search 配置 onSearch 后,必须使用 next 方法继续请求
|
||||
function onSearch(data: any, { next }: { next: (data: any) => void }) {
|
||||
ElMessage.info('开始搜索');
|
||||
// 这边可以处理其他事务
|
||||
next(data);
|
||||
}
|
||||
|
||||
// 自定义搜索,data 为表单数据
|
||||
function toSearch(data: any) {
|
||||
ElMessage.info('自定义搜索');
|
||||
|
||||
refresh({
|
||||
page: 1,
|
||||
...data
|
||||
});
|
||||
}
|
||||
|
||||
const visible = ref(false);
|
||||
|
||||
function open() {
|
||||
visible.value = true;
|
||||
}
|
||||
</script>
|
||||
|
||||
```
|
||||
|
||||
## 布局 示例
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div class="scope">
|
||||
<div class="h">
|
||||
<el-tag size="small" effect="dark" disable-transitions>layout</el-tag>
|
||||
<span>布局</span>
|
||||
</div>
|
||||
|
||||
<div class="c">
|
||||
<el-button @click="open">预览</el-button>
|
||||
<demo-code :files="['search/layout.vue']" />
|
||||
|
||||
<!-- 自定义表格组件 -->
|
||||
<cl-dialog v-model="visible" title="布局" width="80%">
|
||||
<cl-crud ref="Crud">
|
||||
<!--【很重要】搜索组件 -->
|
||||
<cl-search ref="Search" :reset-btn="true" />
|
||||
|
||||
<cl-row>
|
||||
<cl-table ref="Table" />
|
||||
</cl-row>
|
||||
|
||||
<cl-row>
|
||||
<cl-flex1 />
|
||||
<cl-pagination />
|
||||
</cl-row>
|
||||
</cl-crud>
|
||||
</cl-dialog>
|
||||
</div>
|
||||
|
||||
<div class="f">
|
||||
<span class="date">2024-01-01</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useCrud, useSearch, useTable } from '@cool-vue/crud';
|
||||
import { ref } from 'vue';
|
||||
import { useDict } from '/$/dict';
|
||||
|
||||
const { dict } = useDict();
|
||||
|
||||
// cl-crud 配置
|
||||
const Crud = useCrud(
|
||||
{
|
||||
service: 'test'
|
||||
},
|
||||
app => {
|
||||
app.refresh();
|
||||
}
|
||||
);
|
||||
|
||||
// cl-table 配置
|
||||
const Table = useTable({
|
||||
autoHeight: false,
|
||||
contextMenu: ['refresh'],
|
||||
|
||||
columns: [
|
||||
{
|
||||
label: '姓名',
|
||||
prop: 'name',
|
||||
minWidth: 140
|
||||
},
|
||||
{
|
||||
label: '手机号',
|
||||
prop: 'phone',
|
||||
minWidth: 140
|
||||
},
|
||||
{
|
||||
label: '工作',
|
||||
prop: 'occupation',
|
||||
dict: dict.get('occupation'),
|
||||
minWidth: 140
|
||||
},
|
||||
{
|
||||
label: '创建时间',
|
||||
prop: 'createTime',
|
||||
minWidth: 170,
|
||||
sortable: 'desc'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
// cl-search 配置
|
||||
//【很重要】该组件基于 cl-form 故很多示例都可复用
|
||||
const Search = useSearch({
|
||||
// 取消行内表单模式
|
||||
inline: false,
|
||||
|
||||
// 表单参数
|
||||
props: {
|
||||
labelPosition: 'top'
|
||||
},
|
||||
|
||||
// 配置如 cl-form 一样
|
||||
items: [
|
||||
{
|
||||
label: '姓名',
|
||||
prop: 'name',
|
||||
component: {
|
||||
name: 'el-input',
|
||||
props: {
|
||||
clearable: true,
|
||||
|
||||
// 值改变的时候刷新列表
|
||||
onChange(val: string) {
|
||||
refresh({
|
||||
name: val,
|
||||
page: 1
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '手机号',
|
||||
prop: 'phone',
|
||||
component: {
|
||||
name: 'el-input',
|
||||
props: {
|
||||
clearable: true
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '工作',
|
||||
prop: 'occupation',
|
||||
component: {
|
||||
name: 'cl-select',
|
||||
props: {
|
||||
tree: true,
|
||||
checkStrictly: true,
|
||||
options: dict.get('occupation')
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
function refresh(params?: any) {
|
||||
Crud.value?.refresh(params);
|
||||
}
|
||||
|
||||
const visible = ref(false);
|
||||
|
||||
function open() {
|
||||
visible.value = true;
|
||||
}
|
||||
</script>
|
||||
|
||||
```
|
||||
|
||||
## 使用插件 示例
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div class="scope">
|
||||
<div class="h">
|
||||
<el-tag size="small" effect="dark" disable-transitions>plugin</el-tag>
|
||||
<span>使用插件</span>
|
||||
</div>
|
||||
|
||||
<div class="c">
|
||||
<el-button @click="open">预览</el-button>
|
||||
<demo-code :files="['search/layout.vue']" />
|
||||
|
||||
<!-- 自定义表格组件 -->
|
||||
<cl-dialog v-model="visible" title="使用插件" width="80%">
|
||||
<cl-crud ref="Crud">
|
||||
<cl-row>
|
||||
<cl-flex1 />
|
||||
<!--【很重要】搜索组件 -->
|
||||
<cl-search ref="Search" />
|
||||
</cl-row>
|
||||
|
||||
<cl-row>
|
||||
<cl-table ref="Table" />
|
||||
</cl-row>
|
||||
|
||||
<cl-row>
|
||||
<cl-flex1 />
|
||||
<cl-pagination />
|
||||
</cl-row>
|
||||
</cl-crud>
|
||||
</cl-dialog>
|
||||
</div>
|
||||
|
||||
<div class="f">
|
||||
<span class="date">2024-01-01</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useCrud, useSearch, useTable } from '@cool-vue/crud';
|
||||
import { ref } from 'vue';
|
||||
import { useDict } from '/$/dict';
|
||||
import { Plugins } from '/#/crud';
|
||||
|
||||
const { dict } = useDict();
|
||||
|
||||
// cl-crud 配置
|
||||
const Crud = useCrud(
|
||||
{
|
||||
service: 'test'
|
||||
},
|
||||
app => {
|
||||
app.refresh();
|
||||
}
|
||||
);
|
||||
|
||||
// cl-table 配置
|
||||
const Table = useTable({
|
||||
autoHeight: false,
|
||||
contextMenu: ['refresh'],
|
||||
|
||||
columns: [
|
||||
{
|
||||
label: '姓名',
|
||||
prop: 'name',
|
||||
minWidth: 140
|
||||
},
|
||||
{
|
||||
label: '手机号',
|
||||
prop: 'phone',
|
||||
minWidth: 140
|
||||
},
|
||||
{
|
||||
label: '工作',
|
||||
prop: 'occupation',
|
||||
dict: dict.get('occupation'),
|
||||
minWidth: 140
|
||||
},
|
||||
{
|
||||
label: '创建时间',
|
||||
prop: 'createTime',
|
||||
minWidth: 170,
|
||||
sortable: 'desc'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
// cl-search 配置
|
||||
const Search = useSearch({
|
||||
// 【很重要】自动读取 service 下的 search 数据
|
||||
plugins: [
|
||||
Plugins.Search.setAuto({
|
||||
customComponent(field) {
|
||||
if (field.propertyName == 'name') {
|
||||
return {
|
||||
name: 'cl-select',
|
||||
props: {
|
||||
options: [
|
||||
{
|
||||
label: '张三',
|
||||
value: '1'
|
||||
},
|
||||
{
|
||||
label: '李四',
|
||||
value: '2'
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// null 则不操作,按系统默认操作
|
||||
return null;
|
||||
}
|
||||
})
|
||||
]
|
||||
});
|
||||
|
||||
function refresh(params?: any) {
|
||||
Crud.value?.refresh(params);
|
||||
}
|
||||
|
||||
const visible = ref(false);
|
||||
|
||||
function open() {
|
||||
visible.value = true;
|
||||
}
|
||||
</script>
|
||||
|
||||
```
|
||||
2117
cool-admin-vue/.cursor/rules/table.mdc
Normal file
2117
cool-admin-vue/.cursor/rules/table.mdc
Normal file
File diff suppressed because it is too large
Load Diff
716
cool-admin-vue/.cursor/rules/upsert.mdc
Normal file
716
cool-admin-vue/.cursor/rules/upsert.mdc
Normal file
@@ -0,0 +1,716 @@
|
||||
---
|
||||
description: cl-upsert 组件示例
|
||||
globs: *.tsx, *.ts, *.vue
|
||||
---
|
||||
## 起步 示例
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div class="scope">
|
||||
<div class="h">
|
||||
<el-tag size="small" effect="dark" disable-transitions>base</el-tag>
|
||||
<span>起步</span>
|
||||
</div>
|
||||
|
||||
<div class="c">
|
||||
<el-button @click="open">预览</el-button>
|
||||
<demo-code :files="['upsert/base.vue']" />
|
||||
|
||||
<!-- 自定义表格组件 -->
|
||||
<cl-dialog v-model="visible" title="起步" width="80%">
|
||||
<cl-crud ref="Crud">
|
||||
<cl-row>
|
||||
<!-- 打开新增表单的按钮 -->
|
||||
<cl-add-btn />
|
||||
</cl-row>
|
||||
|
||||
<cl-row>
|
||||
<cl-table ref="Table" />
|
||||
</cl-row>
|
||||
|
||||
<cl-row>
|
||||
<cl-flex1 />
|
||||
<cl-pagination />
|
||||
</cl-row>
|
||||
|
||||
<!--【很重要】新增、编辑的表单组件 -->
|
||||
<cl-upsert ref="Upsert" />
|
||||
</cl-crud>
|
||||
</cl-dialog>
|
||||
</div>
|
||||
|
||||
<div class="f">
|
||||
<span class="date">2024-01-01</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useCrud, useTable, useUpsert } from '@cool-vue/crud';
|
||||
import { ref } from 'vue';
|
||||
import { useDict } from '/$/dict';
|
||||
|
||||
const { dict } = useDict();
|
||||
|
||||
// cl-crud 配置
|
||||
const Crud = useCrud(
|
||||
{
|
||||
service: 'test'
|
||||
},
|
||||
app => {
|
||||
app.refresh();
|
||||
}
|
||||
);
|
||||
|
||||
// cl-table 配置
|
||||
const Table = useTable({
|
||||
autoHeight: false,
|
||||
contextMenu: ['refresh'],
|
||||
|
||||
columns: [
|
||||
{
|
||||
label: '姓名',
|
||||
prop: 'name',
|
||||
minWidth: 140
|
||||
},
|
||||
{
|
||||
label: '手机号',
|
||||
prop: 'phone',
|
||||
minWidth: 140
|
||||
},
|
||||
{
|
||||
label: '工作',
|
||||
prop: 'occupation',
|
||||
dict: dict.get('occupation'),
|
||||
minWidth: 140
|
||||
},
|
||||
{
|
||||
label: '创建时间',
|
||||
prop: 'createTime',
|
||||
minWidth: 170,
|
||||
sortable: 'desc'
|
||||
},
|
||||
{
|
||||
type: 'op',
|
||||
// edit 打开编辑表单
|
||||
buttons: ['edit', 'delete']
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
// cl-upsert 配置
|
||||
//【很重要】该组件基于 cl-form 故很多示例都可复用
|
||||
const Upsert = useUpsert({
|
||||
// 配置如 cl-form 一样
|
||||
items: [
|
||||
{
|
||||
label: '姓名',
|
||||
prop: 'name',
|
||||
component: {
|
||||
name: 'el-input'
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '手机号',
|
||||
prop: 'phone',
|
||||
component: {
|
||||
name: 'el-input'
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '工作',
|
||||
prop: 'occupation',
|
||||
component: {
|
||||
name: 'cl-select',
|
||||
props: {
|
||||
tree: true,
|
||||
checkStrictly: true,
|
||||
options: dict.get('occupation')
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
const visible = ref(false);
|
||||
|
||||
function open() {
|
||||
visible.value = true;
|
||||
}
|
||||
</script>
|
||||
|
||||
```
|
||||
|
||||
## 打开、关闭、提交等事件 示例
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div class="scope">
|
||||
<div class="h">
|
||||
<el-tag size="small" effect="dark" disable-transitions>event</el-tag>
|
||||
<span>打开、关闭、提交等事件</span>
|
||||
</div>
|
||||
|
||||
<div class="c">
|
||||
<el-button @click="open">预览</el-button>
|
||||
<demo-code :files="['upsert/event.vue']" />
|
||||
|
||||
<!-- 自定义表格组件 -->
|
||||
<cl-dialog v-model="visible" title="事件" width="80%">
|
||||
<cl-crud ref="Crud">
|
||||
<cl-row>
|
||||
<!-- 打开新增表单的按钮 -->
|
||||
<cl-add-btn />
|
||||
</cl-row>
|
||||
|
||||
<cl-row>
|
||||
<cl-table ref="Table" />
|
||||
</cl-row>
|
||||
|
||||
<cl-row>
|
||||
<cl-flex1 />
|
||||
<cl-pagination />
|
||||
</cl-row>
|
||||
|
||||
<!--【很重要】新增、编辑的表单组件 -->
|
||||
<cl-upsert ref="Upsert" />
|
||||
</cl-crud>
|
||||
</cl-dialog>
|
||||
</div>
|
||||
|
||||
<div class="f">
|
||||
<span class="date">2024-01-01</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useCrud, useTable, useUpsert } from '@cool-vue/crud';
|
||||
import { ref } from 'vue';
|
||||
import { useDict } from '/$/dict';
|
||||
import { useCool } from '/@/cool';
|
||||
|
||||
const { service } = useCool();
|
||||
const { dict } = useDict();
|
||||
|
||||
// cl-crud 配置
|
||||
const Crud = useCrud(
|
||||
{
|
||||
service: 'test'
|
||||
},
|
||||
app => {
|
||||
app.refresh();
|
||||
}
|
||||
);
|
||||
|
||||
// cl-table 配置
|
||||
const Table = useTable({
|
||||
autoHeight: false,
|
||||
contextMenu: ['refresh'],
|
||||
|
||||
columns: [
|
||||
{
|
||||
label: '姓名',
|
||||
prop: 'name',
|
||||
minWidth: 140
|
||||
},
|
||||
{
|
||||
label: '手机号',
|
||||
prop: 'phone',
|
||||
minWidth: 140
|
||||
},
|
||||
{
|
||||
label: '工作',
|
||||
prop: 'occupation',
|
||||
dict: dict.get('occupation'),
|
||||
minWidth: 140
|
||||
},
|
||||
{
|
||||
label: '创建时间',
|
||||
prop: 'createTime',
|
||||
minWidth: 170,
|
||||
sortable: 'desc'
|
||||
},
|
||||
{
|
||||
type: 'op',
|
||||
// edit 打开编辑表单
|
||||
buttons: ['edit', 'delete']
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
// cl-upsert 配置
|
||||
const Upsert = useUpsert({
|
||||
items: [
|
||||
{
|
||||
label: '姓名',
|
||||
prop: 'name',
|
||||
component: {
|
||||
name: 'el-input'
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '手机号',
|
||||
prop: 'phone',
|
||||
component: {
|
||||
name: 'el-input'
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '工作',
|
||||
prop: 'occupation',
|
||||
component: {
|
||||
name: 'cl-select',
|
||||
props: {
|
||||
tree: true,
|
||||
checkStrictly: true,
|
||||
options: dict.get('occupation')
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
// 以下事件按顺序触发
|
||||
|
||||
// 弹窗打开的事件,这个时候还未有表单数据
|
||||
onOpen() {
|
||||
console.log('onOpen');
|
||||
},
|
||||
|
||||
// 获取详情,编辑的时候会触发
|
||||
async onInfo(data, { next, done }) {
|
||||
// 不配置 onInfo 的时候默认执行 next(data),调用 service 的 info 接口获取详情
|
||||
// next(data);
|
||||
|
||||
// 自定义,需要对请求数据进行处理或者返回处理后的数据
|
||||
const res = await next({
|
||||
id: data.id
|
||||
});
|
||||
|
||||
done({
|
||||
...res,
|
||||
name: `[${res.name}]`
|
||||
});
|
||||
},
|
||||
|
||||
// 弹窗打开后,已经得到了表单数据
|
||||
onOpened(data) {
|
||||
// 判定是否编辑模式
|
||||
if (Upsert.value?.mode == 'update') {
|
||||
// 对数据处理
|
||||
data.phone += '000';
|
||||
}
|
||||
},
|
||||
|
||||
// 提交事件的钩子
|
||||
// data 表单提交数据
|
||||
// next 继续往下执行
|
||||
// done 关闭加载
|
||||
// close 关闭弹窗
|
||||
async onSubmit(data, { next, done, close }) {
|
||||
// 不配置 onSubmit 的时候默认执行 next(data),提交后会去请求 service 的 update/add 接口
|
||||
// next(data);
|
||||
|
||||
// 自定义如下
|
||||
// 场景1:提交时对参数额外的处理
|
||||
// next({
|
||||
// ...data,
|
||||
// status: 1,
|
||||
// createTime: dayjs().format("YYYY-MM-DD")
|
||||
// });
|
||||
|
||||
// 场景2:提交前、后的操作
|
||||
// 之前,模拟获取 userId
|
||||
const userId = await service.base.sys.user.info({ id: 1 });
|
||||
|
||||
// 返回值
|
||||
const res = await next({
|
||||
userId,
|
||||
data
|
||||
});
|
||||
|
||||
// 之后
|
||||
// console.log(res);
|
||||
},
|
||||
|
||||
// 关闭时触发
|
||||
onClose(action, done) {
|
||||
// action 关闭的类型
|
||||
console.log('action,', action);
|
||||
|
||||
// 使用 done 关闭窗口
|
||||
done();
|
||||
},
|
||||
|
||||
// 关闭后触发
|
||||
onClosed() {
|
||||
console.log('onClosed');
|
||||
}
|
||||
});
|
||||
|
||||
const visible = ref(false);
|
||||
|
||||
function open() {
|
||||
visible.value = true;
|
||||
}
|
||||
</script>
|
||||
|
||||
```
|
||||
|
||||
## Hook的使用 示例
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div class="scope">
|
||||
<div class="h">
|
||||
<el-tag size="small" effect="dark" disable-transitions>hook</el-tag>
|
||||
<span>Hook的使用</span>
|
||||
</div>
|
||||
|
||||
<div class="c">
|
||||
<el-button @click="open">预览</el-button>
|
||||
<demo-code :files="['upsert/hook/index.vue', 'upsert/hook/reg-pca2.ts']" />
|
||||
|
||||
<!-- 自定义表格组件 -->
|
||||
<cl-dialog v-model="visible" title="Hook的使用" width="80%">
|
||||
<cl-crud ref="Crud">
|
||||
<cl-row>
|
||||
<!-- 打开新增表单的按钮 -->
|
||||
<cl-add-btn />
|
||||
</cl-row>
|
||||
|
||||
<cl-row>
|
||||
<cl-table ref="Table" />
|
||||
</cl-row>
|
||||
|
||||
<cl-row>
|
||||
<cl-flex1 />
|
||||
<cl-pagination />
|
||||
</cl-row>
|
||||
|
||||
<!--【很重要】新增、编辑的表单组件 -->
|
||||
<cl-upsert ref="Upsert" />
|
||||
</cl-crud>
|
||||
</cl-dialog>
|
||||
</div>
|
||||
|
||||
<div class="f">
|
||||
<span class="date">2024-01-01</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useCrud, useTable, useUpsert } from '@cool-vue/crud';
|
||||
import { ref } from 'vue';
|
||||
import { useDict } from '/$/dict';
|
||||
|
||||
const { dict } = useDict();
|
||||
|
||||
// cl-crud 配置
|
||||
const Crud = useCrud(
|
||||
{
|
||||
service: 'test'
|
||||
},
|
||||
app => {
|
||||
app.refresh();
|
||||
}
|
||||
);
|
||||
|
||||
// cl-table 配置
|
||||
const Table = useTable({
|
||||
autoHeight: false,
|
||||
contextMenu: ['refresh'],
|
||||
|
||||
columns: [
|
||||
{
|
||||
label: '姓名',
|
||||
prop: 'name',
|
||||
minWidth: 140
|
||||
},
|
||||
{
|
||||
label: '手机号',
|
||||
prop: 'phone',
|
||||
minWidth: 140
|
||||
},
|
||||
{
|
||||
label: '省市区',
|
||||
prop: 'pca',
|
||||
formatter(row) {
|
||||
return row.province ? row.province + '-' + row.city + '-' + row.district : '-';
|
||||
},
|
||||
minWidth: 140
|
||||
},
|
||||
{
|
||||
label: '工作',
|
||||
prop: 'occupation',
|
||||
dict: dict.get('occupation'),
|
||||
minWidth: 140
|
||||
},
|
||||
{
|
||||
label: '创建时间',
|
||||
prop: 'createTime',
|
||||
minWidth: 170,
|
||||
sortable: 'desc'
|
||||
},
|
||||
{
|
||||
type: 'op',
|
||||
buttons: ['edit', 'delete']
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
// cl-upsert 配置
|
||||
const Upsert = useUpsert({
|
||||
items: [
|
||||
{
|
||||
label: '姓名',
|
||||
prop: 'name',
|
||||
component: {
|
||||
name: 'el-input'
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '手机号',
|
||||
prop: 'phone',
|
||||
component: {
|
||||
name: 'el-input'
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '省市区',
|
||||
prop: 'pca2',
|
||||
|
||||
//【很重要】hook 参数配置
|
||||
hook: {
|
||||
bind(value, { form }) {
|
||||
// 将3个参数合并成一个数组,带入级联选择器
|
||||
return [form.province, form.city, form.district];
|
||||
},
|
||||
submit(value, { form, prop }) {
|
||||
// 提交的时候将数组拆分成3个字段提交
|
||||
const [province, city, district] = value || [];
|
||||
form.province = province;
|
||||
form.city = city;
|
||||
form.district = district;
|
||||
|
||||
// 删除 prop 绑定值
|
||||
form[prop] = undefined;
|
||||
}
|
||||
},
|
||||
// 注册到全局后可直接使用,注册代码看 ./reg-pca2.ts
|
||||
// hook: "pca2",
|
||||
|
||||
component: {
|
||||
name: 'cl-distpicker'
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '标签',
|
||||
prop: 'labels',
|
||||
//【很重要】使用内置方法,避免一些辣鸡后端要你这么传给他
|
||||
hook: {
|
||||
// labels 的数据为 1,2,3
|
||||
|
||||
// 绑定的时候将 labels 按 , 分割成数组
|
||||
bind: ['split', 'number'],
|
||||
|
||||
// 提交的时候将 labels 拼接成字符串
|
||||
submit: ['join']
|
||||
},
|
||||
component: {
|
||||
name: 'el-select',
|
||||
props: {
|
||||
multiple: true
|
||||
},
|
||||
options: [
|
||||
{
|
||||
label: '帅气',
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
label: '多金',
|
||||
value: 2
|
||||
},
|
||||
{
|
||||
label: '有才华',
|
||||
value: 3
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '工作',
|
||||
prop: 'occupation',
|
||||
component: {
|
||||
name: 'cl-select',
|
||||
props: {
|
||||
tree: true,
|
||||
checkStrictly: true,
|
||||
options: dict.get('occupation')
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
const visible = ref(false);
|
||||
|
||||
function open() {
|
||||
visible.value = true;
|
||||
}
|
||||
</script>
|
||||
|
||||
```
|
||||
|
||||
## 新增、编辑、详情模式 示例
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div class="scope">
|
||||
<div class="h">
|
||||
<el-tag size="small" effect="dark" disable-transitions>mode</el-tag>
|
||||
<span>新增、编辑、详情模式</span>
|
||||
</div>
|
||||
|
||||
<div class="c">
|
||||
<el-button @click="open">预览</el-button>
|
||||
<demo-code :files="['upsert/mode.vue']" />
|
||||
|
||||
<!-- 自定义表格组件 -->
|
||||
<cl-dialog v-model="visible" title="不同模式" width="80%">
|
||||
<cl-crud ref="Crud">
|
||||
<cl-row>
|
||||
<!-- 打开新增表单的按钮 -->
|
||||
<cl-add-btn />
|
||||
</cl-row>
|
||||
|
||||
<cl-row>
|
||||
<cl-table ref="Table" />
|
||||
</cl-row>
|
||||
|
||||
<cl-row>
|
||||
<cl-flex1 />
|
||||
<cl-pagination />
|
||||
</cl-row>
|
||||
|
||||
<!--【很重要】新增、编辑的表单组件 -->
|
||||
<cl-upsert ref="Upsert" />
|
||||
</cl-crud>
|
||||
</cl-dialog>
|
||||
</div>
|
||||
|
||||
<div class="f">
|
||||
<span class="date">2024-01-01</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useCrud, useTable, useUpsert } from '@cool-vue/crud';
|
||||
import { ref } from 'vue';
|
||||
import { useDict } from '/$/dict';
|
||||
import { ElMessage } from 'element-plus';
|
||||
|
||||
const { dict } = useDict();
|
||||
|
||||
// cl-crud 配置
|
||||
const Crud = useCrud(
|
||||
{
|
||||
service: 'test'
|
||||
},
|
||||
app => {
|
||||
app.refresh();
|
||||
}
|
||||
);
|
||||
|
||||
// cl-table 配置
|
||||
const Table = useTable({
|
||||
autoHeight: false,
|
||||
contextMenu: ['refresh'],
|
||||
|
||||
columns: [
|
||||
{
|
||||
label: '姓名',
|
||||
prop: 'name',
|
||||
minWidth: 140
|
||||
},
|
||||
{
|
||||
label: '手机号',
|
||||
prop: 'phone',
|
||||
minWidth: 140
|
||||
},
|
||||
{
|
||||
label: '工作',
|
||||
prop: 'occupation',
|
||||
dict: dict.get('occupation'),
|
||||
minWidth: 140
|
||||
},
|
||||
{
|
||||
label: '创建时间',
|
||||
prop: 'createTime',
|
||||
minWidth: 170,
|
||||
sortable: 'desc'
|
||||
},
|
||||
{
|
||||
type: 'op',
|
||||
width: 240,
|
||||
buttons: ['info', 'edit', 'delete']
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
// cl-upsert 配置
|
||||
const Upsert = useUpsert({
|
||||
items: [
|
||||
{
|
||||
label: '姓名',
|
||||
prop: 'name',
|
||||
component: {
|
||||
name: 'el-input'
|
||||
}
|
||||
},
|
||||
//【很重要】只有返回方法的时候才能使用 Upsert
|
||||
() => {
|
||||
return {
|
||||
label: '手机号',
|
||||
prop: 'phone',
|
||||
|
||||
// 新增的时候隐藏
|
||||
// hidden: Upsert.value?.mode == "add",
|
||||
|
||||
component: {
|
||||
name: 'el-input',
|
||||
props: {
|
||||
// 编辑的时候禁用
|
||||
disabled: Upsert.value?.mode == 'update'
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
{
|
||||
label: '工作',
|
||||
prop: 'occupation',
|
||||
component: {
|
||||
name: 'cl-select',
|
||||
props: {
|
||||
tree: true,
|
||||
checkStrictly: true,
|
||||
options: dict.get('occupation')
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
onOpen() {
|
||||
ElMessage.info(`当前模式:` + Upsert.value?.mode);
|
||||
}
|
||||
});
|
||||
|
||||
const visible = ref(false);
|
||||
|
||||
function open() {
|
||||
visible.value = true;
|
||||
}
|
||||
</script>
|
||||
|
||||
```
|
||||
Reference in New Issue
Block a user