mirror of
https://github.com/cool-team-official/cool-admin-vue.git
synced 2026-03-17 19:23:28 +00:00
发布 7.1.0
This commit is contained in:
parent
fe9c4b2040
commit
897571c7ad
46
build/cool/demo.ts
Normal file
46
build/cool/demo.ts
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import type { Plugin } from "vite";
|
||||||
|
import { glob } from "glob";
|
||||||
|
import path from "path";
|
||||||
|
import { readFileSync } from "fs";
|
||||||
|
|
||||||
|
export function demo(enable?: boolean): Plugin {
|
||||||
|
const virtualModuleIds = ["virtual:demo"];
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: "vite-cool-demo",
|
||||||
|
enforce: "pre",
|
||||||
|
resolveId(id) {
|
||||||
|
if (virtualModuleIds.includes(id)) {
|
||||||
|
return "\0" + id;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async load(id) {
|
||||||
|
if (id === "\0virtual:demo") {
|
||||||
|
const demo = {};
|
||||||
|
|
||||||
|
if (enable) {
|
||||||
|
const files = await glob("./src/modules/demo/views/crud/components/**", {
|
||||||
|
stat: true,
|
||||||
|
withFileTypes: true
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const file of files) {
|
||||||
|
if (file.isFile()) {
|
||||||
|
const p = path.join(file.path, file.name);
|
||||||
|
|
||||||
|
demo[
|
||||||
|
p
|
||||||
|
.replace(/\\/g, "/")
|
||||||
|
.split("src/modules/demo/views/crud/components/")[1]
|
||||||
|
] = readFileSync(p, "utf-8");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return `
|
||||||
|
export const demo = ${JSON.stringify(demo)};
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -1,6 +1,14 @@
|
|||||||
import { base } from "./base";
|
import { base } from "./base";
|
||||||
import { virtual } from "./virtual";
|
import { virtual } from "./virtual";
|
||||||
|
import { demo } from "./demo";
|
||||||
|
|
||||||
export function cool() {
|
export function cool() {
|
||||||
return [base(), virtual()];
|
return [
|
||||||
|
// 基础
|
||||||
|
base(),
|
||||||
|
// 虚拟模块
|
||||||
|
virtual(),
|
||||||
|
// demo 官方示例,代码片段
|
||||||
|
demo(true)
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -42,7 +42,7 @@ function findFiles(dir: string): string[] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function createSvg(html: string) {
|
export function createSvg(html: string) {
|
||||||
const res = findFiles("./src/modules/");
|
const res = findFiles("./src/");
|
||||||
|
|
||||||
return html.replace(
|
return html.replace(
|
||||||
"<body>",
|
"<body>",
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "cool-admin",
|
"name": "cool-admin",
|
||||||
"version": "7.0.0",
|
"version": "7.1.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite --host",
|
"dev": "vite --host",
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
@ -9,7 +9,7 @@
|
|||||||
"lint:eslint": "eslint \"./src/**/*.{vue,ts,tsx}\" --fix"
|
"lint:eslint": "eslint \"./src/**/*.{vue,ts,tsx}\" --fix"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@cool-vue/crud": "^7.1.3",
|
"@cool-vue/crud": "^7.1.10",
|
||||||
"@element-plus/icons-vue": "^2.1.0",
|
"@element-plus/icons-vue": "^2.1.0",
|
||||||
"@vueuse/core": "^10.4.0",
|
"@vueuse/core": "^10.4.0",
|
||||||
"@wangeditor/editor": "^5.1.23",
|
"@wangeditor/editor": "^5.1.23",
|
||||||
@ -22,6 +22,7 @@
|
|||||||
"element-plus": "^2.4.3",
|
"element-plus": "^2.4.3",
|
||||||
"file-saver": "^2.0.5",
|
"file-saver": "^2.0.5",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
|
"marked": "^11.1.1",
|
||||||
"mitt": "^3.0.1",
|
"mitt": "^3.0.1",
|
||||||
"mockjs": "^1.1.0",
|
"mockjs": "^1.1.0",
|
||||||
"monaco-editor": "0.36.0",
|
"monaco-editor": "0.36.0",
|
||||||
@ -53,6 +54,7 @@
|
|||||||
"eslint-config-prettier": "^9.0.0",
|
"eslint-config-prettier": "^9.0.0",
|
||||||
"eslint-plugin-prettier": "^5.0.0",
|
"eslint-plugin-prettier": "^5.0.0",
|
||||||
"eslint-plugin-vue": "^9.17.0",
|
"eslint-plugin-vue": "^9.17.0",
|
||||||
|
"glob": "^10.3.10",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"magic-string": "^0.30.3",
|
"magic-string": "^0.30.3",
|
||||||
"prettier": "^3.1.0",
|
"prettier": "^3.1.0",
|
||||||
|
|||||||
73
packages/crud/index.d.ts
vendored
73
packages/crud/index.d.ts
vendored
@ -82,39 +82,6 @@ declare type Browser = {
|
|||||||
isMini: boolean;
|
isMini: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
// hook
|
|
||||||
declare namespace Hook {
|
|
||||||
interface Options {
|
|
||||||
form: obj;
|
|
||||||
prop: string;
|
|
||||||
method: "submit" | "bind";
|
|
||||||
}
|
|
||||||
|
|
||||||
type fn = (value: any, options: Options) => any;
|
|
||||||
|
|
||||||
type FormPipe =
|
|
||||||
| "number"
|
|
||||||
| "string"
|
|
||||||
| "split"
|
|
||||||
| "join"
|
|
||||||
| "boolean"
|
|
||||||
| "booleanNumber"
|
|
||||||
| "datetimeRange"
|
|
||||||
| "splitJoin"
|
|
||||||
| "json"
|
|
||||||
| "empty"
|
|
||||||
| fn;
|
|
||||||
|
|
||||||
type FormPipes = FormPipe | FormPipe[];
|
|
||||||
|
|
||||||
type Form =
|
|
||||||
| string
|
|
||||||
| {
|
|
||||||
bind?: FormPipes;
|
|
||||||
submit?: FormPipes;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// render
|
// render
|
||||||
declare namespace Render {
|
declare namespace Render {
|
||||||
type OpButton =
|
type OpButton =
|
||||||
@ -473,6 +440,26 @@ declare namespace ClForm {
|
|||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type HookFn = (
|
||||||
|
value: any,
|
||||||
|
options: { form: obj; prop: string; method: "submit" | "bind" }
|
||||||
|
) => any;
|
||||||
|
|
||||||
|
type HookKey =
|
||||||
|
| "number"
|
||||||
|
| "string"
|
||||||
|
| "split"
|
||||||
|
| "join"
|
||||||
|
| "boolean"
|
||||||
|
| "booleanNumber"
|
||||||
|
| "datetimeRange"
|
||||||
|
| "splitJoin"
|
||||||
|
| "json"
|
||||||
|
| "empty"
|
||||||
|
| (string & {});
|
||||||
|
|
||||||
|
type HookPipe = HookKey | HookFn;
|
||||||
|
|
||||||
interface Item<T = any> {
|
interface Item<T = any> {
|
||||||
type?: "tabs";
|
type?: "tabs";
|
||||||
prop?: PropKey<T>;
|
prop?: PropKey<T>;
|
||||||
@ -501,14 +488,19 @@ declare namespace ClForm {
|
|||||||
xl: any;
|
xl: any;
|
||||||
tag: string;
|
tag: string;
|
||||||
};
|
};
|
||||||
hook?: Hook.Form;
|
|
||||||
group?: string;
|
group?: string;
|
||||||
collapse?: boolean;
|
collapse?: boolean;
|
||||||
value?: any;
|
value?: any;
|
||||||
label?: string;
|
label?: string;
|
||||||
renderLabel?: any;
|
renderLabel?: any;
|
||||||
flex?: boolean;
|
flex?: boolean;
|
||||||
hidden?: (options: { scope: obj }) => boolean;
|
hook?:
|
||||||
|
| HookKey
|
||||||
|
| {
|
||||||
|
bind?: HookPipe | HookPipe[];
|
||||||
|
submit?: HookPipe | HookPipe[];
|
||||||
|
};
|
||||||
|
hidden?: boolean | ((options: { scope: obj }) => boolean);
|
||||||
prepend?: Render.Component;
|
prepend?: Render.Component;
|
||||||
component?: Render.Component;
|
component?: Render.Component;
|
||||||
append?: Render.Component;
|
append?: Render.Component;
|
||||||
@ -632,16 +624,12 @@ declare namespace ClUpsert {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface UpsertOptions {
|
|
||||||
items: ClForm.Items;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare namespace ClAdvSearch {
|
declare namespace ClAdvSearch {
|
||||||
interface Config<T = any> {
|
interface Config<T = any> {
|
||||||
items?: ClForm.Item[];
|
items?: ClForm.Item[];
|
||||||
title?: string;
|
title?: string;
|
||||||
size?: string | number;
|
size?: string | number;
|
||||||
op?: Array<"clear" | "reset" | "close" | "search">;
|
op?: ("clear" | "reset" | "close" | "search" | `slot-${string}`)[];
|
||||||
onSearch?(data: T, options: { next: ClCrud.Service["api"]["page"]; close(): void }): void;
|
onSearch?(data: T, options: { next: ClCrud.Service["api"]["page"]; close(): void }): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -674,9 +662,8 @@ declare namespace ClSearch {
|
|||||||
declare namespace ClContextMenu {
|
declare namespace ClContextMenu {
|
||||||
interface Item {
|
interface Item {
|
||||||
label: string;
|
label: string;
|
||||||
icon?: string;
|
prefixIcon?: any;
|
||||||
prefixIcon?: string;
|
suffixIcon?: any;
|
||||||
suffixIcon?: string;
|
|
||||||
ellipsis?: boolean;
|
ellipsis?: boolean;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
hidden?: boolean;
|
hidden?: boolean;
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@cool-vue/crud",
|
"name": "@cool-vue/crud",
|
||||||
"version": "7.1.3",
|
"version": "7.1.10",
|
||||||
"private": false,
|
"private": false,
|
||||||
"main": "./dist/index.umd.min.js",
|
"main": "./dist/index.umd.min.js",
|
||||||
"typings": "types/index.d.ts",
|
"typings": "types/index.d.ts",
|
||||||
|
|||||||
@ -1,16 +1,36 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div>CRUD DEMO v7.0.0</div>
|
<div class="title">CRUD DEMO v7.0.0</div>
|
||||||
|
|
||||||
|
<cl-crud ref="Crud">
|
||||||
|
<cl-row>
|
||||||
|
<cl-add-btn />
|
||||||
|
<cl-adv-btn />
|
||||||
|
</cl-row>
|
||||||
|
|
||||||
|
<cl-row>
|
||||||
|
<cl-table ref="Table" :auto-height="false"></cl-table>
|
||||||
|
</cl-row>
|
||||||
|
|
||||||
|
<cl-row>
|
||||||
|
<cl-flex1 />
|
||||||
|
<cl-pagination />
|
||||||
|
</cl-row>
|
||||||
|
|
||||||
<cl-crud>
|
|
||||||
<cl-add-btn />
|
|
||||||
<cl-upsert ref="Upsert"></cl-upsert>
|
<cl-upsert ref="Upsert"></cl-upsert>
|
||||||
|
<cl-adv-search ref="AdvSearch"></cl-adv-search>
|
||||||
</cl-crud>
|
</cl-crud>
|
||||||
|
|
||||||
|
<cl-dialog v-model="visible" height="20vh">
|
||||||
|
<div style="height: 50px" v-for="d in 100" :key="d">{{ d }}</div>
|
||||||
|
</cl-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="tsx">
|
<script setup lang="tsx">
|
||||||
import { useTable, useForm, useSearch, useUpsert, useAdvSearch } from "./hooks";
|
import { useTable, useForm, useUpsert, useCrud } from "./hooks";
|
||||||
|
import { EditPen } from "@element-plus/icons-vue";
|
||||||
|
import { ref } from "vue";
|
||||||
|
|
||||||
interface Data {
|
interface Data {
|
||||||
name?: string;
|
name?: string;
|
||||||
@ -18,39 +38,119 @@ interface Data {
|
|||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const visible = ref(true);
|
||||||
|
|
||||||
const Upsert = useUpsert<Data>({
|
const Upsert = useUpsert<Data>({
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
label: "xx",
|
type: "tabs",
|
||||||
|
props: {
|
||||||
|
labels: [
|
||||||
|
{
|
||||||
|
label: "A",
|
||||||
|
value: "A",
|
||||||
|
icon: EditPen
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "B",
|
||||||
|
value: "B"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
group: "B",
|
||||||
prop: "age",
|
prop: "age",
|
||||||
component: {
|
component: {
|
||||||
name: "el-input"
|
name: "el-input"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
group: "B",
|
||||||
|
prop: "证书",
|
||||||
|
component: {
|
||||||
|
name: "el-input"
|
||||||
|
},
|
||||||
|
hidden({ scope }) {
|
||||||
|
return scope.age < 18;
|
||||||
|
}
|
||||||
|
},
|
||||||
() => {
|
() => {
|
||||||
return {
|
return {
|
||||||
|
group: "A",
|
||||||
hidden: Upsert.value?.mode == "add",
|
hidden: Upsert.value?.mode == "add",
|
||||||
label: "x"
|
hook: {
|
||||||
|
bind(value, { form }) {
|
||||||
|
return "";
|
||||||
|
},
|
||||||
|
submit(value, { form }) {}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
onOpened(data) {}
|
onOpened(data) {
|
||||||
|
Upsert.value?.setForm("age", "18");
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const Table = useTable<Data>({
|
const Table = useTable<Data>({
|
||||||
|
contextMenu: [
|
||||||
|
{
|
||||||
|
label: "带图标",
|
||||||
|
prefixIcon: EditPen
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "多层级",
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
label: "A",
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
label: "A-1"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "B"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
columns: [
|
columns: [
|
||||||
{
|
{
|
||||||
label: "xx",
|
label: "姓名",
|
||||||
prop: "a",
|
prop: "name",
|
||||||
search: {
|
search: {
|
||||||
component: {
|
component: {
|
||||||
name: "el-date-picker"
|
name: "el-date-picker"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "手机号",
|
||||||
|
prop: "phone",
|
||||||
|
search: {
|
||||||
|
component: {
|
||||||
|
name: "el-date-picker"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "op"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const Crud = useCrud(
|
||||||
|
{
|
||||||
|
service: "test"
|
||||||
|
},
|
||||||
|
(app) => {
|
||||||
|
app.refresh();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
const Form = useForm<Data>();
|
const Form = useForm<Data>();
|
||||||
|
|
||||||
Form.value?.open({
|
Form.value?.open({
|
||||||
@ -61,22 +161,12 @@ Form.value?.open({
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
const Search = useSearch<Data>({
|
|
||||||
items: [
|
|
||||||
{
|
|
||||||
label: "xx",
|
|
||||||
prop: "age"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
});
|
|
||||||
|
|
||||||
const AdvSearch = useAdvSearch<Data>({
|
|
||||||
items: [
|
|
||||||
{
|
|
||||||
label: "xx",
|
|
||||||
prop: "age"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.title {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@ -78,6 +78,7 @@ export default defineComponent({
|
|||||||
function reset() {
|
function reset() {
|
||||||
Form.value?.reset();
|
Form.value?.reset();
|
||||||
emit("reset");
|
emit("reset");
|
||||||
|
search();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 清空数据
|
// 清空数据
|
||||||
@ -160,9 +161,9 @@ export default defineComponent({
|
|||||||
v-model={visible.value}
|
v-model={visible.value}
|
||||||
direction="rtl"
|
direction="rtl"
|
||||||
with-header={false}
|
with-header={false}
|
||||||
size={browser.isMini ? "100%" : props.size}>
|
size={browser.isMini ? "100%" : config.size}>
|
||||||
<div class="cl-adv-search__header">
|
<div class="cl-adv-search__header">
|
||||||
<span class="text">{props.title || crud.dict.label.advSearch}</span>
|
<span class="text">{config.title || crud.dict.label.advSearch}</span>
|
||||||
<el-icon size={20} onClick={close}>
|
<el-icon size={20} onClick={close}>
|
||||||
<Close />
|
<Close />
|
||||||
</el-icon>
|
</el-icon>
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
import { defineComponent, nextTick, onMounted, reactive, ref, h, render } from "vue";
|
import { defineComponent, nextTick, onMounted, reactive, ref, h, render, toRaw } from "vue";
|
||||||
import { isString } from "lodash-es";
|
import { isString } from "lodash-es";
|
||||||
import { addClass, contains, removeClass } from "../../utils";
|
import { addClass, contains, removeClass } from "../../utils";
|
||||||
import { useRefs } from "../../hooks";
|
import { useRefs } from "../../hooks";
|
||||||
|
import { ElIcon } from "element-plus";
|
||||||
|
import { ArrowRight } from "@element-plus/icons-vue";
|
||||||
|
|
||||||
const ClContextMenu = defineComponent({
|
const ClContextMenu = defineComponent({
|
||||||
name: "cl-context-menu",
|
name: "cl-context-menu",
|
||||||
@ -89,7 +91,7 @@ const ClContextMenu = defineComponent({
|
|||||||
|
|
||||||
// 点击样式
|
// 点击样式
|
||||||
if (options.hover) {
|
if (options.hover) {
|
||||||
let d = options.hover === true ? {} : options.hover;
|
const d = options.hover === true ? {} : options.hover;
|
||||||
targetEl = event.target;
|
targetEl = event.target;
|
||||||
|
|
||||||
if (targetEl && isString(targetEl.className)) {
|
if (targetEl && isString(targetEl.className)) {
|
||||||
@ -187,15 +189,22 @@ const ClContextMenu = defineComponent({
|
|||||||
.map((e, i) => {
|
.map((e, i) => {
|
||||||
const id = `${pId}-${i}`;
|
const id = `${pId}-${i}`;
|
||||||
|
|
||||||
|
if (!e.suffixIcon) {
|
||||||
|
// 默认图标
|
||||||
|
if (e.children) {
|
||||||
|
e.suffixIcon = ArrowRight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
class={{
|
class={{
|
||||||
"is-active": ids.value.includes(id),
|
"is-active": ids.value.includes(id),
|
||||||
"is-ellipsis": e.ellipsis,
|
"is-ellipsis": e.ellipsis ?? true,
|
||||||
"is-disabled": e.disabled
|
"is-disabled": e.disabled
|
||||||
}}>
|
}}>
|
||||||
{/* 前缀图标 */}
|
{/* 前缀图标 */}
|
||||||
{e.prefixIcon && <i class={e.prefixIcon}></i>}
|
{e.prefixIcon && <ElIcon>{h(toRaw(e.prefixIcon))}</ElIcon>}
|
||||||
|
|
||||||
{/* 标题 */}
|
{/* 标题 */}
|
||||||
<span
|
<span
|
||||||
@ -206,9 +215,9 @@ const ClContextMenu = defineComponent({
|
|||||||
</span>
|
</span>
|
||||||
|
|
||||||
{/* 后缀图标 */}
|
{/* 后缀图标 */}
|
||||||
{e.suffixIcon && <i class={e.suffixIcon}></i>}
|
{e.suffixIcon && <ElIcon>{h(toRaw(e.suffixIcon))}</ElIcon>}
|
||||||
|
|
||||||
{/* 子集*/}
|
{/* 子集 */}
|
||||||
{e.children &&
|
{e.children &&
|
||||||
e.showChildren &&
|
e.showChildren &&
|
||||||
deep(e.children, id, level + 1)}
|
deep(e.children, id, level + 1)}
|
||||||
|
|||||||
@ -50,7 +50,12 @@ export default defineComponent({
|
|||||||
// 隐藏头部元素
|
// 隐藏头部元素
|
||||||
hideHeader: Boolean,
|
hideHeader: Boolean,
|
||||||
// 关闭前
|
// 关闭前
|
||||||
beforeClose: Function
|
beforeClose: Function,
|
||||||
|
// 是否需要滚动条
|
||||||
|
scrollbar: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
emits: ["update:modelValue", "fullscreen-change"],
|
emits: ["update:modelValue", "fullscreen-change"],
|
||||||
@ -242,16 +247,28 @@ export default defineComponent({
|
|||||||
return renderHeader();
|
return renderHeader();
|
||||||
},
|
},
|
||||||
default() {
|
default() {
|
||||||
return (
|
const height = isFullscreen.value ? "100%" : props.height;
|
||||||
<el-scrollbar
|
|
||||||
class="cl-dialog__container"
|
const style = {
|
||||||
key={cacheKey.value}
|
padding: props.padding,
|
||||||
style={{ height: props.height }}>
|
height
|
||||||
<div class="cl-dialog__default" style={{ padding: props.padding }}>
|
};
|
||||||
|
|
||||||
|
function content() {
|
||||||
|
return (
|
||||||
|
<div class="cl-dialog__default" style={style} key={cacheKey.value}>
|
||||||
{slots.default?.()}
|
{slots.default?.()}
|
||||||
</div>
|
</div>
|
||||||
</el-scrollbar>
|
);
|
||||||
);
|
}
|
||||||
|
|
||||||
|
if (props.scrollbar) {
|
||||||
|
style.height = "auto";
|
||||||
|
|
||||||
|
return <el-scrollbar height={height}>{content()}</el-scrollbar>;
|
||||||
|
} else {
|
||||||
|
return content();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
footer() {
|
footer() {
|
||||||
const d = slots.footer?.();
|
const d = slots.footer?.();
|
||||||
|
|||||||
@ -119,21 +119,32 @@ export default defineComponent({
|
|||||||
// 拷贝表单值
|
// 拷贝表单值
|
||||||
const d = cloneDeep(form);
|
const d = cloneDeep(form);
|
||||||
|
|
||||||
// 过滤隐藏的表单项
|
|
||||||
config.items.forEach((e) => {
|
config.items.forEach((e) => {
|
||||||
if (e._hidden) {
|
function deep(e: ClForm.Item) {
|
||||||
if (e.prop) {
|
if (e.prop) {
|
||||||
delete d[e.prop];
|
// 过滤隐藏的表单项
|
||||||
|
if (e._hidden) {
|
||||||
|
if (e.prop) {
|
||||||
|
delete d[e.prop];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// hook 提交处理
|
||||||
|
if (e.hook) {
|
||||||
|
formHook.submit({
|
||||||
|
...e,
|
||||||
|
value: e.prop ? d[e.prop] : undefined,
|
||||||
|
form: d
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.children) {
|
||||||
|
e.children.forEach(deep);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e.hook) {
|
deep(e);
|
||||||
formHook.submit({
|
|
||||||
...e,
|
|
||||||
value: e.prop ? d[e.prop] : undefined,
|
|
||||||
form: d
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// 处理 "-" 多层级
|
// 处理 "-" 多层级
|
||||||
@ -152,7 +163,7 @@ export default defineComponent({
|
|||||||
let f: any = d[a];
|
let f: any = d[a];
|
||||||
|
|
||||||
// 设置默认值
|
// 设置默认值
|
||||||
arr.forEach((e: any) => {
|
arr.forEach((e) => {
|
||||||
if (!f[e]) {
|
if (!f[e]) {
|
||||||
f[e] = {};
|
f[e] = {};
|
||||||
}
|
}
|
||||||
@ -249,7 +260,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 设置表单数据
|
// 设置表单数据
|
||||||
config.items.map((e) => {
|
config.items.forEach((e) => {
|
||||||
function deep(e: ClForm.Item) {
|
function deep(e: ClForm.Item) {
|
||||||
if (e.prop) {
|
if (e.prop) {
|
||||||
// 解析 prop
|
// 解析 prop
|
||||||
@ -260,7 +271,7 @@ export default defineComponent({
|
|||||||
// prop 合并
|
// prop 合并
|
||||||
Tabs.mergeProp(e);
|
Tabs.mergeProp(e);
|
||||||
|
|
||||||
// 绑定值
|
// hook 绑定值
|
||||||
formHook.bind({
|
formHook.bind({
|
||||||
...e,
|
...e,
|
||||||
value: form[e.prop] !== undefined ? form[e.prop] : cloneDeep(e.value),
|
value: form[e.prop] !== undefined ? form[e.prop] : cloneDeep(e.value),
|
||||||
@ -274,17 +285,17 @@ export default defineComponent({
|
|||||||
message: `${e.label}${dict.label.nonEmpty}`
|
message: `${e.label}${dict.label.nonEmpty}`
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// 子集
|
|
||||||
if (e.children) {
|
|
||||||
e.children.forEach(deep);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置 tabs 默认值
|
// 设置 tabs 默认值
|
||||||
if (e.type == "tabs") {
|
if (e.type == "tabs") {
|
||||||
Tabs.set(e.value);
|
Tabs.set(e.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 子集
|
||||||
|
if (e.children) {
|
||||||
|
e.children.forEach(deep);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
deep(e);
|
deep(e);
|
||||||
@ -312,11 +323,19 @@ export default defineComponent({
|
|||||||
// 绑定表单数据
|
// 绑定表单数据
|
||||||
function bindForm(data: any) {
|
function bindForm(data: any) {
|
||||||
config.items.forEach((e) => {
|
config.items.forEach((e) => {
|
||||||
formHook.bind({
|
function deep(e: ClForm.Item) {
|
||||||
...e,
|
formHook.bind({
|
||||||
value: e.prop ? data[e.prop] : undefined,
|
...e,
|
||||||
form: data
|
value: e.prop ? data[e.prop] : undefined,
|
||||||
});
|
form: data
|
||||||
|
});
|
||||||
|
|
||||||
|
if (e.children) {
|
||||||
|
e.children.forEach(deep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deep(e);
|
||||||
});
|
});
|
||||||
|
|
||||||
Object.assign(form, data);
|
Object.assign(form, data);
|
||||||
@ -344,105 +363,104 @@ export default defineComponent({
|
|||||||
const isLoaded = e.component && Tabs.isLoaded(e.group);
|
const isLoaded = e.component && Tabs.isLoaded(e.group);
|
||||||
|
|
||||||
// 表单项
|
// 表单项
|
||||||
const FormItem = isLoaded
|
const FormItem = h(
|
||||||
? h(
|
<el-form-item
|
||||||
<el-form-item
|
class={{
|
||||||
class={{
|
"no-label": !(e.renderLabel || e.label),
|
||||||
"no-label": !(e.renderLabel || e.label),
|
"has-children": !!e.children
|
||||||
"has-children": !!e.children
|
}}
|
||||||
}}
|
key={e.prop}
|
||||||
data-group={e.group}
|
data-group={e.group || "-"}
|
||||||
data-prop={e.prop}
|
data-prop={e.prop || "-"}
|
||||||
label-width={props.inline ? "auto" : ""}
|
label-width={props.inline ? "auto" : ""}
|
||||||
label={e.label}
|
label={e.label}
|
||||||
prop={e.prop}
|
prop={e.prop}
|
||||||
rules={isDisabled ? null : e.rules}
|
rules={isDisabled ? null : e.rules}
|
||||||
required={e._hidden ? false : e.required}
|
required={e._hidden ? false : e.required}
|
||||||
v-show={inGroup && !e._hidden}
|
v-show={inGroup && !e._hidden}
|
||||||
/>,
|
/>,
|
||||||
e.props,
|
e.props,
|
||||||
{
|
{
|
||||||
label() {
|
label() {
|
||||||
return e.renderLabel
|
return e.renderLabel
|
||||||
? renderNode(e.renderLabel, {
|
? renderNode(e.renderLabel, {
|
||||||
scope: form,
|
scope: form,
|
||||||
render: "slot",
|
render: "slot",
|
||||||
slots
|
slots
|
||||||
})
|
})
|
||||||
: e.label;
|
: e.label;
|
||||||
},
|
},
|
||||||
default() {
|
default() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div class="cl-form-item">
|
<div class="cl-form-item">
|
||||||
{["prepend", "component", "append"]
|
{["prepend", "component", "append"]
|
||||||
.filter((k) => e[k])
|
.filter((k) => e[k])
|
||||||
.map((name) => {
|
.map((name) => {
|
||||||
const children = e.children && (
|
const children = e.children && (
|
||||||
<div class="cl-form-item__children">
|
<div class="cl-form-item__children">
|
||||||
<el-row gutter={10}>
|
<el-row gutter={10}>
|
||||||
{e.children.map(renderFormItem)}
|
{e.children.map(renderFormItem)}
|
||||||
</el-row>
|
</el-row>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
const Item = renderNode(e[name], {
|
const Item = renderNode(e[name], {
|
||||||
item: e,
|
item: e,
|
||||||
prop: e.prop,
|
prop: e.prop,
|
||||||
scope: form,
|
scope: form,
|
||||||
slots,
|
slots,
|
||||||
children,
|
children,
|
||||||
_data: {
|
_data: {
|
||||||
isDisabled
|
isDisabled
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
v-show={!e.collapse}
|
||||||
|
class={[
|
||||||
|
`cl-form-item__${name}`,
|
||||||
|
{
|
||||||
|
flex1: e.flex !== false
|
||||||
}
|
}
|
||||||
});
|
]}
|
||||||
|
style={e[name].style}>
|
||||||
|
{Item}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
|
||||||
return (
|
{isBoolean(e.collapse) && (
|
||||||
<div
|
<div
|
||||||
v-show={!e.collapse}
|
class="cl-form-item__collapse"
|
||||||
class={[
|
onClick={() => {
|
||||||
`cl-form-item__${name}`,
|
Action.collapseItem(e);
|
||||||
{
|
}}>
|
||||||
flex1: e.flex !== false
|
<el-divider content-position="center">
|
||||||
}
|
{e.collapse
|
||||||
]}
|
? dict.label.seeMore
|
||||||
style={e[name].style}>
|
: dict.label.hideContent}
|
||||||
{Item}
|
</el-divider>
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{isBoolean(e.collapse) && (
|
|
||||||
<div
|
|
||||||
class="cl-form-item__collapse"
|
|
||||||
onClick={() => {
|
|
||||||
Action.collapseItem(e);
|
|
||||||
}}>
|
|
||||||
<el-divider content-position="center">
|
|
||||||
{e.collapse
|
|
||||||
? dict.label.seeMore
|
|
||||||
: dict.label.hideContent}
|
|
||||||
</el-divider>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
)}
|
||||||
}
|
</div>
|
||||||
}
|
);
|
||||||
)
|
}
|
||||||
: null;
|
}
|
||||||
|
);
|
||||||
|
|
||||||
// 行内
|
// 是否行内
|
||||||
if (props.inline) {
|
const Item = props.inline ? (
|
||||||
return FormItem;
|
FormItem
|
||||||
}
|
) : (
|
||||||
|
<el-col span={e.span || style.form.span} {...e.col} v-show={inGroup && !e._hidden}>
|
||||||
return (
|
|
||||||
<el-col key={e.prop} span={e.span || style.form.span} {...e.col}>
|
|
||||||
{FormItem}
|
{FormItem}
|
||||||
</el-col>
|
</el-col>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
return isLoaded ? Item : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 渲染表单
|
// 渲染表单
|
||||||
|
|||||||
@ -87,8 +87,20 @@ export default defineComponent({
|
|||||||
|
|
||||||
// 重置
|
// 重置
|
||||||
function reset() {
|
function reset() {
|
||||||
|
const d: any = {};
|
||||||
|
|
||||||
|
config.items?.map((e) => {
|
||||||
|
d[e.prop!] = undefined;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 重置表单
|
||||||
Form.value?.reset();
|
Form.value?.reset();
|
||||||
emit("reset");
|
|
||||||
|
// 列表刷新
|
||||||
|
crud.refresh(d);
|
||||||
|
|
||||||
|
// 重置事件
|
||||||
|
emit("reset", d);
|
||||||
}
|
}
|
||||||
|
|
||||||
expose({
|
expose({
|
||||||
@ -123,6 +135,7 @@ export default defineComponent({
|
|||||||
append() {
|
append() {
|
||||||
return (
|
return (
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
|
{/* 搜索按钮 */}
|
||||||
<el-button
|
<el-button
|
||||||
type="primary"
|
type="primary"
|
||||||
loading={loading.value}
|
loading={loading.value}
|
||||||
@ -132,11 +145,16 @@ export default defineComponent({
|
|||||||
}}>
|
}}>
|
||||||
{crud.dict.label.search}
|
{crud.dict.label.search}
|
||||||
</el-button>
|
</el-button>
|
||||||
|
|
||||||
|
{/* 重置按钮 */}
|
||||||
{config.resetBtn && (
|
{config.resetBtn && (
|
||||||
<el-button size={style.size} onClick={reset}>
|
<el-button size={style.size} onClick={reset}>
|
||||||
{crud.dict.label.reset}
|
{crud.dict.label.reset}
|
||||||
</el-button>
|
</el-button>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/* 自定义按钮 */}
|
||||||
|
{slots?.buttons?.(Form.value?.form)}
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|||||||
@ -371,6 +371,7 @@
|
|||||||
ul {
|
ul {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
margin: 0;
|
||||||
|
|
||||||
li {
|
li {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
@ -397,7 +398,9 @@
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: -1px;
|
bottom: -1px;
|
||||||
left: 0;
|
left: 0;
|
||||||
transition: transform 0.3s ease-in-out, width 0.2s 0.1s cubic-bezier(0.645, 0.045, 0.355, 1);
|
transition:
|
||||||
|
transform 0.3s ease-in-out,
|
||||||
|
width 0.2s 0.1s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||||
background-color: var(--el-color-primary);
|
background-color: var(--el-color-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -514,14 +517,7 @@
|
|||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__container {
|
|
||||||
& > .el-scrollbar__wrap > .el-scrollbar__view {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__default {
|
&__default {
|
||||||
height: 100%;
|
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { isArray, isFunction, isObject, isString } from "lodash-es";
|
import { isArray, isEmpty, isFunction, isObject, isString } from "lodash-es";
|
||||||
|
|
||||||
export const format: { [key: string]: Hook.fn } = {
|
export const format: { [key: string]: ClForm.HookFn } = {
|
||||||
number(value) {
|
number(value) {
|
||||||
return value ? (isArray(value) ? value.map(Number) : Number(value)) : value;
|
return value ? (isArray(value) ? value.map(Number) : Number(value)) : value;
|
||||||
},
|
},
|
||||||
@ -63,6 +63,10 @@ export const format: { [key: string]: Hook.fn } = {
|
|||||||
return value === "" ? undefined : value;
|
return value === "" ? undefined : value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isArray(value)) {
|
||||||
|
return isEmpty(value) ? undefined : value;
|
||||||
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -139,7 +143,7 @@ const formHook = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export function registerFormHook(name: string, fn: Hook.fn) {
|
export function registerFormHook(name: string, fn: ClForm.HookFn) {
|
||||||
format[name] = fn;
|
format[name] = fn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -25,6 +25,10 @@ declare const _default: import("vue").DefineComponent<{
|
|||||||
};
|
};
|
||||||
hideHeader: BooleanConstructor;
|
hideHeader: BooleanConstructor;
|
||||||
beforeClose: FunctionConstructor;
|
beforeClose: FunctionConstructor;
|
||||||
|
scrollbar: {
|
||||||
|
type: BooleanConstructor;
|
||||||
|
default: boolean;
|
||||||
|
};
|
||||||
}, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
}, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
}>, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, ("update:modelValue" | "fullscreen-change")[], "update:modelValue" | "fullscreen-change", import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<{
|
}>, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, ("update:modelValue" | "fullscreen-change")[], "update:modelValue" | "fullscreen-change", import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<{
|
||||||
@ -54,6 +58,10 @@ declare const _default: import("vue").DefineComponent<{
|
|||||||
};
|
};
|
||||||
hideHeader: BooleanConstructor;
|
hideHeader: BooleanConstructor;
|
||||||
beforeClose: FunctionConstructor;
|
beforeClose: FunctionConstructor;
|
||||||
|
scrollbar: {
|
||||||
|
type: BooleanConstructor;
|
||||||
|
default: boolean;
|
||||||
|
};
|
||||||
}>> & {
|
}>> & {
|
||||||
"onUpdate:modelValue"?: ((...args: any[]) => any) | undefined;
|
"onUpdate:modelValue"?: ((...args: any[]) => any) | undefined;
|
||||||
"onFullscreen-change"?: ((...args: any[]) => any) | undefined;
|
"onFullscreen-change"?: ((...args: any[]) => any) | undefined;
|
||||||
@ -66,5 +74,6 @@ declare const _default: import("vue").DefineComponent<{
|
|||||||
controls: unknown[];
|
controls: unknown[];
|
||||||
fullscreen: boolean;
|
fullscreen: boolean;
|
||||||
modelValue: boolean;
|
modelValue: boolean;
|
||||||
|
scrollbar: boolean;
|
||||||
}, {}>;
|
}, {}>;
|
||||||
export default _default;
|
export default _default;
|
||||||
|
|||||||
@ -56,17 +56,17 @@ export declare function useForm(): {
|
|||||||
xl: any;
|
xl: any;
|
||||||
tag: string;
|
tag: string;
|
||||||
} | undefined;
|
} | undefined;
|
||||||
hook?: string | {
|
|
||||||
bind?: Hook.FormPipe | Hook.FormPipe[] | undefined;
|
|
||||||
submit?: Hook.FormPipe | Hook.FormPipe[] | undefined;
|
|
||||||
} | undefined;
|
|
||||||
group?: string | undefined;
|
group?: string | undefined;
|
||||||
collapse?: boolean | undefined;
|
collapse?: boolean | undefined;
|
||||||
value?: any;
|
value?: any;
|
||||||
label?: string | undefined;
|
label?: string | undefined;
|
||||||
renderLabel?: any;
|
renderLabel?: any;
|
||||||
flex?: boolean | undefined;
|
flex?: boolean | undefined;
|
||||||
hidden?: ((options: {
|
hook?: ClForm.HookKey | {
|
||||||
|
bind?: ClForm.HookPipe | ClForm.HookPipe[] | undefined;
|
||||||
|
submit?: ClForm.HookPipe | ClForm.HookPipe[] | undefined;
|
||||||
|
} | undefined;
|
||||||
|
hidden?: boolean | ((options: {
|
||||||
scope: obj;
|
scope: obj;
|
||||||
}) => boolean) | undefined;
|
}) => boolean) | undefined;
|
||||||
prepend?: {
|
prepend?: {
|
||||||
|
|||||||
@ -143,9 +143,8 @@ export declare function useTable(props: any): {
|
|||||||
contextMenu: ("info" | "update" | "delete" | "edit" | "refresh" | {
|
contextMenu: ("info" | "update" | "delete" | "edit" | "refresh" | {
|
||||||
[x: string]: any;
|
[x: string]: any;
|
||||||
label: string;
|
label: string;
|
||||||
icon?: string | undefined;
|
prefixIcon?: any;
|
||||||
prefixIcon?: string | undefined;
|
suffixIcon?: any;
|
||||||
suffixIcon?: string | undefined;
|
|
||||||
ellipsis?: boolean | undefined;
|
ellipsis?: boolean | undefined;
|
||||||
disabled?: boolean | undefined;
|
disabled?: boolean | undefined;
|
||||||
hidden?: boolean | undefined;
|
hidden?: boolean | undefined;
|
||||||
|
|||||||
4
packages/crud/types/utils/form-hook.d.ts
vendored
4
packages/crud/types/utils/form-hook.d.ts
vendored
@ -1,10 +1,10 @@
|
|||||||
/// <reference types="../index" />
|
/// <reference types="../index" />
|
||||||
export declare const format: {
|
export declare const format: {
|
||||||
[key: string]: Hook.fn;
|
[key: string]: ClForm.HookFn;
|
||||||
};
|
};
|
||||||
declare const formHook: {
|
declare const formHook: {
|
||||||
bind(data: any): void;
|
bind(data: any): void;
|
||||||
submit(data: any): void;
|
submit(data: any): void;
|
||||||
};
|
};
|
||||||
export declare function registerFormHook(name: string, fn: Hook.fn): void;
|
export declare function registerFormHook(name: string, fn: ClForm.HookFn): void;
|
||||||
export default formHook;
|
export default formHook;
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
export const proxy = {
|
export const proxy = {
|
||||||
"/dev/": {
|
"/dev/": {
|
||||||
target: "http://127.0.0.1:8001",
|
target: "http://192.168.0.119:8001",
|
||||||
|
// target: "http://127.0.0.1:8004",
|
||||||
|
// target: "https://test-admin.cool-js.cloud",
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
rewrite: (path: string) => path.replace(/^\/dev/, "")
|
rewrite: (path: string) => path.replace(/^\/dev/, "")
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,13 +1,16 @@
|
|||||||
import { App } from "vue";
|
import { App } from "vue";
|
||||||
import { isFunction, orderBy } from "lodash-es";
|
import { isFunction, orderBy, chain } from "lodash-es";
|
||||||
import { filename } from "../utils";
|
import { filename } from "../utils";
|
||||||
import { module } from "../module";
|
import { module } from "../module";
|
||||||
import { hmr } from "../hook";
|
import { hmr } from "../hook";
|
||||||
|
|
||||||
// 扫描文件
|
// 扫描文件
|
||||||
const files: any = import.meta.glob("/src/modules/*/{config.ts,service/**,directives/**}", {
|
const files: any = import.meta.glob(
|
||||||
eager: true
|
"/src/{modules,plugins}/*/{config.ts,service/**,directives/**}",
|
||||||
});
|
{
|
||||||
|
eager: true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
// 模块列表
|
// 模块列表
|
||||||
module.list = hmr.getData("modules", []);
|
module.list = hmr.getData("modules", []);
|
||||||
@ -15,7 +18,7 @@ module.list = hmr.getData("modules", []);
|
|||||||
// 解析
|
// 解析
|
||||||
for (const i in files) {
|
for (const i in files) {
|
||||||
// 分割
|
// 分割
|
||||||
const [, , , name, action] = i.split("/");
|
const [, , type, name, action] = i.split("/");
|
||||||
|
|
||||||
// 文件名
|
// 文件名
|
||||||
const fname = filename(i);
|
const fname = filename(i);
|
||||||
@ -29,6 +32,7 @@ for (const i in files) {
|
|||||||
// 数据
|
// 数据
|
||||||
const d = m || {
|
const d = m || {
|
||||||
name,
|
name,
|
||||||
|
type,
|
||||||
value: null,
|
value: null,
|
||||||
services: [],
|
services: [],
|
||||||
directives: []
|
directives: []
|
||||||
|
|||||||
@ -13,6 +13,9 @@ const module = {
|
|||||||
get(name: string): Module {
|
get(name: string): Module {
|
||||||
return this.list.find((e) => e.name == name)!;
|
return this.list.find((e) => e.name == name)!;
|
||||||
},
|
},
|
||||||
|
config(name: string) {
|
||||||
|
return this.get(name).options || {};
|
||||||
|
},
|
||||||
add(data: Module) {
|
add(data: Module) {
|
||||||
this.list.push(data);
|
this.list.push(data);
|
||||||
},
|
},
|
||||||
|
|||||||
@ -6,6 +6,9 @@ import { useBase } from "/$/base";
|
|||||||
import { Loading } from "../utils";
|
import { Loading } from "../utils";
|
||||||
import { config } from "/@/config";
|
import { config } from "/@/config";
|
||||||
|
|
||||||
|
// 基本路径
|
||||||
|
const baseUrl = import.meta.env.BASE_URL;
|
||||||
|
|
||||||
// 扫描文件
|
// 扫描文件
|
||||||
const files = import.meta.glob(["/src/modules/*/{views,pages}/**/*", "!**/components"]);
|
const files = import.meta.glob(["/src/modules/*/{views,pages}/**/*", "!**/components"]);
|
||||||
|
|
||||||
@ -26,7 +29,10 @@ const routes: RouteRecordRaw[] = [
|
|||||||
|
|
||||||
// 创建路由器
|
// 创建路由器
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
history: config.app.router.mode == "history" ? createWebHistory() : createWebHashHistory(),
|
history:
|
||||||
|
config.app.router.mode == "history"
|
||||||
|
? createWebHistory(baseUrl)
|
||||||
|
: createWebHashHistory(baseUrl),
|
||||||
routes
|
routes
|
||||||
}) as Router;
|
}) as Router;
|
||||||
|
|
||||||
|
|||||||
@ -1,10 +0,0 @@
|
|||||||
.cl-avatar {
|
|
||||||
.el-avatar {
|
|
||||||
display: block;
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,5 +1,5 @@
|
|||||||
import { defineComponent, PropType } from "vue";
|
import { defineComponent, type PropType } from "vue";
|
||||||
import "./index.scss";
|
import { UserFilled } from "@element-plus/icons-vue";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "cl-avatar",
|
name: "cl-avatar",
|
||||||
@ -7,7 +7,10 @@ export default defineComponent({
|
|||||||
props: {
|
props: {
|
||||||
modelValue: String,
|
modelValue: String,
|
||||||
src: String,
|
src: String,
|
||||||
icon: null,
|
icon: {
|
||||||
|
type: null,
|
||||||
|
default: UserFilled
|
||||||
|
},
|
||||||
size: [String, Number] as PropType<"large" | "default" | "small" | number>,
|
size: [String, Number] as PropType<"large" | "default" | "small" | number>,
|
||||||
shape: String as PropType<"circle" | "square">,
|
shape: String as PropType<"circle" | "square">,
|
||||||
fit: {
|
fit: {
|
||||||
@ -19,18 +22,16 @@ export default defineComponent({
|
|||||||
setup(props) {
|
setup(props) {
|
||||||
return () => {
|
return () => {
|
||||||
return (
|
return (
|
||||||
<div class="cl-avatar">
|
<el-avatar
|
||||||
<el-avatar
|
style={{
|
||||||
style={{
|
height: props.size + "px",
|
||||||
height: props.size + "px",
|
width: props.size + "px"
|
||||||
width: props.size + "px"
|
}}
|
||||||
}}
|
{...{
|
||||||
{...{
|
...props,
|
||||||
...props,
|
src: props.modelValue || props.src
|
||||||
src: props.modelValue || props.src
|
}}
|
||||||
}}
|
/>
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -71,13 +71,13 @@ function onCheckChange(_: any, { checkedKeys }: any) {
|
|||||||
|
|
||||||
// 监听过滤
|
// 监听过滤
|
||||||
watch(keyword, (val: string) => {
|
watch(keyword, (val: string) => {
|
||||||
Tree.value.filter(val);
|
Tree.value?.filter(val);
|
||||||
});
|
});
|
||||||
|
|
||||||
useUpsert({
|
useUpsert({
|
||||||
async onOpened() {
|
async onOpened() {
|
||||||
await refresh();
|
await refresh();
|
||||||
Tree.value.setCheckedKeys(props.modelValue || []);
|
Tree.value?.setCheckedKeys(props.modelValue || []);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -18,7 +18,7 @@
|
|||||||
preview-teleported
|
preview-teleported
|
||||||
>
|
>
|
||||||
<template #error>
|
<template #error>
|
||||||
<div class="image-slot">
|
<div class="cl-image__slot">
|
||||||
<el-icon :size="20"><picture-filled /></el-icon>
|
<el-icon :size="20"><picture-filled /></el-icon>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -27,7 +27,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { PropType, computed, defineComponent } from "vue";
|
import { type PropType, computed, defineComponent } from "vue";
|
||||||
import { isArray, isNumber, isString } from "lodash-es";
|
import { isArray, isNumber, isString } from "lodash-es";
|
||||||
import { PictureFilled } from "@element-plus/icons-vue";
|
import { PictureFilled } from "@element-plus/icons-vue";
|
||||||
import { parsePx } from "/@/cool/utils";
|
import { parsePx } from "/@/cool/utils";
|
||||||
@ -91,20 +91,13 @@ export default defineComponent({
|
|||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.cl-image {
|
.cl-image {
|
||||||
display: flex;
|
&__slot {
|
||||||
align-items: center;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
.el-image {
|
justify-content: center;
|
||||||
display: block;
|
height: 100%;
|
||||||
|
background-color: #f7f7f7;
|
||||||
.image-slot {
|
border-radius: 4px;
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
height: 100%;
|
|
||||||
background-color: #f7f7f7;
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -73,7 +73,7 @@ watch(keyword, (val: string) => {
|
|||||||
useUpsert({
|
useUpsert({
|
||||||
async onOpened() {
|
async onOpened() {
|
||||||
await refresh();
|
await refresh();
|
||||||
Tree.value.setCheckedKeys(
|
Tree.value?.setCheckedKeys(
|
||||||
(props.modelValue || []).filter((e) => Tree.value.getNode(e)?.isLeaf)
|
(props.modelValue || []).filter((e) => Tree.value.getNode(e)?.isLeaf)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
import { TreeData } from "element-plus/es/components/tree/src/tree.type";
|
import { TreeData } from "element-plus/es/components/tree/src/tree.type";
|
||||||
import { ClViewGroup, useViewGroup } from "/$/base";
|
|
||||||
import { service } from "/@/cool";
|
import { service } from "/@/cool";
|
||||||
import Node from "element-plus/es/components/tree/src/model/node";
|
import Node from "element-plus/es/components/tree/src/model/node";
|
||||||
import ClAvatar from "../components/avatar/index";
|
import ClAvatar from "../components/avatar/index";
|
||||||
|
import { type ClViewGroup, useViewGroup } from "/@/plugins/view";
|
||||||
|
|
||||||
export function useDeptViewGroup(options: DeepPartial<ClViewGroup.Options>) {
|
export function useDeptViewGroup(options: DeepPartial<ClViewGroup.Options>) {
|
||||||
const { ViewGroup } = useViewGroup({
|
const { ViewGroup } = useViewGroup({
|
||||||
|
|||||||
@ -1,2 +1 @@
|
|||||||
export * from "../components/view/group/hook";
|
|
||||||
export * from "./dept";
|
export * from "./dept";
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
<el-form label-width="100px" :model="form" :disabled="loading">
|
<el-form label-width="100px" :model="form" :disabled="loading">
|
||||||
<el-form-item label="头像">
|
<el-form-item label="头像">
|
||||||
<cl-upload is-space v-model="form.headImg" />
|
<cl-upload v-model="form.headImg" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="昵称">
|
<el-form-item label="昵称">
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
import { useForm } from "@cool-vue/crud";
|
import { useForm } from "@cool-vue/crud";
|
||||||
import { ElMessage } from "element-plus";
|
import { ElMessage } from "element-plus";
|
||||||
import { isEmpty } from "lodash-es";
|
import { isEmpty } from "lodash-es";
|
||||||
import { PropType } from "vue";
|
import { type PropType } from "vue";
|
||||||
import { useCool } from "/@/cool";
|
import { useCool } from "/@/cool";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import { Download } from "@element-plus/icons-vue";
|
import { Download } from "@element-plus/icons-vue";
|
||||||
@ -30,6 +30,9 @@ function open() {
|
|||||||
props: {
|
props: {
|
||||||
labelPosition: "top"
|
labelPosition: "top"
|
||||||
},
|
},
|
||||||
|
op: {
|
||||||
|
saveButtonText: "导出"
|
||||||
|
},
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
label: "选择菜单",
|
label: "选择菜单",
|
||||||
|
|||||||
@ -105,8 +105,8 @@ import { deepTree } from "/@/cool/utils";
|
|||||||
import { useStore } from "/$/base/store";
|
import { useStore } from "/$/base/store";
|
||||||
import MenuImp from "./components/imp.vue";
|
import MenuImp from "./components/imp.vue";
|
||||||
import MenuExp from "./components/exp.vue";
|
import MenuExp from "./components/exp.vue";
|
||||||
import AutoMenu from "/$/magic/components/auto-menu/index.vue";
|
import AutoMenu from "/$/helper/components/auto-menu/index.vue";
|
||||||
import AutoPerms from "/$/magic/components/auto-perms/index.vue";
|
import AutoPerms from "/$/helper/components/auto-perms/index.vue";
|
||||||
|
|
||||||
const { service, mitt } = useCool();
|
const { service, mitt } = useCool();
|
||||||
const { menu } = useStore();
|
const { menu } = useStore();
|
||||||
@ -401,5 +401,5 @@ function addPermission({ id }: any) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
mitt.on("magic.createMenu", refresh);
|
mitt.on("helper.createMenu", refresh);
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -19,19 +19,29 @@
|
|||||||
|
|
||||||
<cl-upsert ref="Upsert">
|
<cl-upsert ref="Upsert">
|
||||||
<template #slot-relevance="{ scope }">
|
<template #slot-relevance="{ scope }">
|
||||||
<el-switch
|
<div>
|
||||||
v-model="scope.relevance"
|
<el-row>
|
||||||
:active-value="1"
|
<el-switch
|
||||||
:inactive-value="0"
|
v-model="scope.relevance"
|
||||||
@change="onRelevanceChange"
|
:active-value="1"
|
||||||
/>
|
:inactive-value="0"
|
||||||
<span
|
/>
|
||||||
:style="{
|
|
||||||
marginLeft: '10px',
|
<span
|
||||||
fontSize: '12px'
|
:style="{
|
||||||
}"
|
marginLeft: '10px',
|
||||||
>是否关联上下级</span
|
fontSize: '12px'
|
||||||
>
|
}"
|
||||||
|
>
|
||||||
|
是否关联上下级
|
||||||
|
</span>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<cl-dept-check
|
||||||
|
v-model="scope.departmentIdList"
|
||||||
|
:check-strictly="scope.relevance == 0"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</cl-upsert>
|
</cl-upsert>
|
||||||
</cl-crud>
|
</cl-crud>
|
||||||
@ -96,30 +106,20 @@ const Upsert = useUpsert({
|
|||||||
{
|
{
|
||||||
label: "数据权限",
|
label: "数据权限",
|
||||||
prop: "relevance",
|
prop: "relevance",
|
||||||
flex: false,
|
|
||||||
component: {
|
component: {
|
||||||
name: "slot-relevance"
|
name: "slot-relevance"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "",
|
|
||||||
prop: "departmentIdList",
|
|
||||||
value: [],
|
|
||||||
component: {
|
|
||||||
name: "cl-dept-check",
|
|
||||||
props: {},
|
|
||||||
style: {
|
|
||||||
marginTop: "-10px"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
||||||
plugins: [setFocus()],
|
onSubmit(data, { next }) {
|
||||||
|
next({
|
||||||
|
...data,
|
||||||
|
departmentIdList: data.departmentIdList || []
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
onOpened(data) {
|
plugins: [setFocus()]
|
||||||
onRelevanceChange(data.relevance || 0);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// cl-table
|
// cl-table
|
||||||
@ -164,11 +164,4 @@ const Table = useTable({
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
// 是否关联上下级
|
|
||||||
function onRelevanceChange(val: number | string | boolean) {
|
|
||||||
Upsert.value?.setProps("departmentIdList", {
|
|
||||||
checkStrictly: val == 0
|
|
||||||
});
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -81,7 +81,8 @@ import { deepTree, revDeepTree } from "/@/cool/utils";
|
|||||||
import { isArray } from "lodash-es";
|
import { isArray } from "lodash-es";
|
||||||
import { ContextMenu, setFocus, useForm } from "@cool-vue/crud";
|
import { ContextMenu, setFocus, useForm } from "@cool-vue/crud";
|
||||||
import { Refresh as RefreshIcon, Operation, MoreFilled } from "@element-plus/icons-vue";
|
import { Refresh as RefreshIcon, Operation, MoreFilled } from "@element-plus/icons-vue";
|
||||||
import { checkPerm, useViewGroup } from "/$/base";
|
import { checkPerm } from "/$/base";
|
||||||
|
import { useViewGroup } from "/@/plugins/view";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
drag: {
|
drag: {
|
||||||
@ -97,9 +98,8 @@ const props = defineProps({
|
|||||||
const emit = defineEmits(["refresh", "user-add"]);
|
const emit = defineEmits(["refresh", "user-add"]);
|
||||||
|
|
||||||
const { service, browser } = useCool();
|
const { service, browser } = useCool();
|
||||||
const { ViewGroup } = useViewGroup();
|
|
||||||
|
|
||||||
const Form = useForm();
|
const Form = useForm();
|
||||||
|
const { ViewGroup } = useViewGroup();
|
||||||
|
|
||||||
// 树形列表
|
// 树形列表
|
||||||
const list = ref<Eps.BaseSysDepartmentEntity[]>([]);
|
const list = ref<Eps.BaseSysDepartmentEntity[]>([]);
|
||||||
|
|||||||
@ -59,9 +59,9 @@
|
|||||||
<script lang="ts" name="sys-user" setup>
|
<script lang="ts" name="sys-user" setup>
|
||||||
import { useTable, useUpsert, useCrud } from "@cool-vue/crud";
|
import { useTable, useUpsert, useCrud } from "@cool-vue/crud";
|
||||||
import { useCool } from "/@/cool";
|
import { useCool } from "/@/cool";
|
||||||
import { useViewGroup } from "../../hooks";
|
|
||||||
import DeptList from "./components/dept-list.vue";
|
import DeptList from "./components/dept-list.vue";
|
||||||
import UserMove from "./components/user-move.vue";
|
import UserMove from "./components/user-move.vue";
|
||||||
|
import { useViewGroup } from "/@/plugins/view";
|
||||||
|
|
||||||
const { service, refs, setRefs } = useCool();
|
const { service, refs, setRefs } = useCool();
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="cl-chat__wrap">
|
<div class="cl-chat__wrap">
|
||||||
<el-badge :value="unCount">
|
<el-badge :value="unCount" :hidden="!unCount">
|
||||||
<div class="cl-chat__icon" @click="open">
|
<div class="cl-chat__icon" @click="open">
|
||||||
<cl-svg name="icon-notice" :size="16" />
|
<cl-svg name="icon-notice" :size="16" />
|
||||||
</div>
|
</div>
|
||||||
@ -14,6 +14,7 @@
|
|||||||
width="1200px"
|
width="1200px"
|
||||||
padding="0"
|
padding="0"
|
||||||
keep-alive
|
keep-alive
|
||||||
|
:scrollbar="false"
|
||||||
:close-on-click-modal="false"
|
:close-on-click-modal="false"
|
||||||
close-on-press-escape
|
close-on-press-escape
|
||||||
:controls="['slot-expand', 'cl-flex1', 'fullscreen', 'close']"
|
:controls="['slot-expand', 'cl-flex1', 'fullscreen', 'close']"
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { ModuleConfig } from "/@/cool";
|
import { ModuleConfig } from "/@/cool";
|
||||||
import { addDeclare } from "/$/extend";
|
|
||||||
import { CodeDeclare } from "./dict";
|
import { CodeDeclare } from "./dict";
|
||||||
|
import { addDeclare } from "/@/plugins/editor-monaco";
|
||||||
|
|
||||||
export default (): ModuleConfig => {
|
export default (): ModuleConfig => {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -54,9 +54,9 @@
|
|||||||
import { useForm } from "@cool-vue/crud";
|
import { useForm } from "@cool-vue/crud";
|
||||||
import { ElMessage, ElMessageBox } from "element-plus";
|
import { ElMessage, ElMessageBox } from "element-plus";
|
||||||
import { reactive, ref } from "vue";
|
import { reactive, ref } from "vue";
|
||||||
import { useViewGroup } from "/$/base";
|
|
||||||
import { useCool } from "/@/cool";
|
import { useCool } from "/@/cool";
|
||||||
import { CodeSnippets, Status } from "../dict";
|
import { CodeSnippets, Status } from "../dict";
|
||||||
|
import { useViewGroup } from "/@/plugins/view";
|
||||||
|
|
||||||
const { service } = useCool();
|
const { service } = useCool();
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="scope">
|
<div class="scope">
|
||||||
<div class="h">
|
<div class="h">
|
||||||
<span>cl-context-menu</span>
|
<el-tag size="small" effect="dark">cl-context-menu</el-tag>
|
||||||
右键菜单
|
右键菜单
|
||||||
</div>
|
</div>
|
||||||
<div class="c">
|
<div class="c">
|
||||||
@ -17,7 +17,7 @@
|
|||||||
import { ContextMenu } from "@cool-vue/crud";
|
import { ContextMenu } from "@cool-vue/crud";
|
||||||
import { ElMessage } from "element-plus";
|
import { ElMessage } from "element-plus";
|
||||||
|
|
||||||
function open(e: any) {
|
function open(e: MouseEvent) {
|
||||||
ContextMenu.open(e, {
|
ContextMenu.open(e, {
|
||||||
list: [
|
list: [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="scope">
|
<div class="scope">
|
||||||
<div class="h">
|
<div class="h">
|
||||||
<span>v-copy</span>
|
<el-tag size="small" effect="dark">v-copy</el-tag>
|
||||||
复制到剪贴板
|
复制到剪贴板
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="scope">
|
<div class="scope">
|
||||||
<div class="h">
|
<div class="h">
|
||||||
<span>cl-crud</span>
|
<el-tag size="small" effect="dark">cl-crud</el-tag>
|
||||||
增删改查,超快的
|
增删改查,超快的
|
||||||
</div>
|
</div>
|
||||||
<div class="c">
|
<div class="c">
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="scope">
|
<div class="scope">
|
||||||
<div class="h">
|
<div class="h">
|
||||||
<span>design-page</span>
|
<el-tag size="small" effect="dark">design-page</el-tag>
|
||||||
页面设计
|
页面设计
|
||||||
</div>
|
</div>
|
||||||
<div class="c">
|
<div class="c">
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="scope">
|
<div class="scope">
|
||||||
<div class="h">
|
<div class="h">
|
||||||
<span>cl-editor</span>
|
<el-tag size="small" effect="dark">cl-editor</el-tag>
|
||||||
编辑器
|
编辑器
|
||||||
</div>
|
</div>
|
||||||
<div class="c">
|
<div class="c">
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="scope">
|
<div class="scope">
|
||||||
<div class="h">
|
<div class="h">
|
||||||
<span>file</span>
|
<el-tag size="small" effect="dark">file</el-tag>
|
||||||
文件管理
|
文件管理
|
||||||
</div>
|
</div>
|
||||||
<div class="c">
|
<div class="c">
|
||||||
|
|||||||
@ -1,18 +1,14 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="scope">
|
<div class="scope">
|
||||||
<div class="h">
|
<div class="h">
|
||||||
<span>cl-form</span>
|
<el-tag size="small" effect="dark">cl-form</el-tag>
|
||||||
很强的表单
|
很强的表单
|
||||||
</div>
|
</div>
|
||||||
<div class="c">
|
<div class="c">
|
||||||
<form-btn />
|
<router-link to="/demo/crud?key=cl-form">传送门</router-link>
|
||||||
</div>
|
</div>
|
||||||
<div class="f">
|
<div class="f">
|
||||||
<span class="date">2019/01/01</span>
|
<span class="date">2019/01/01</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import FormBtn from "./form-btn.vue";
|
|
||||||
</script>
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="scope">
|
<div class="scope">
|
||||||
<div class="h">
|
<div class="h">
|
||||||
<span>cl-svg</span>
|
<el-tag size="small" effect="dark">cl-svg</el-tag>
|
||||||
svg图片库
|
svg图片库
|
||||||
</div>
|
</div>
|
||||||
<div class="c _svg">
|
<div class="c _svg">
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="scope">
|
<div class="scope">
|
||||||
<div class="h">
|
<div class="h">
|
||||||
<span>cl-upload</span>
|
<el-tag size="small" effect="dark">cl-upload</el-tag>
|
||||||
图片上传
|
图片上传
|
||||||
</div>
|
</div>
|
||||||
<div class="c">
|
<div class="c">
|
||||||
|
|||||||
7
src/modules/demo/config.ts
Normal file
7
src/modules/demo/config.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { ModuleConfig } from "/@/cool";
|
||||||
|
|
||||||
|
export default (): ModuleConfig => {
|
||||||
|
return {
|
||||||
|
components: [() => import("./views/crud/components/code.vue")]
|
||||||
|
};
|
||||||
|
};
|
||||||
138
src/modules/demo/views/crud/components/adv-search/base.vue
Normal file
138
src/modules/demo/views/crud/components/adv-search/base.vue
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
<template>
|
||||||
|
<div class="scope">
|
||||||
|
<div class="h">
|
||||||
|
<el-tag size="small" effect="dark">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: 160,
|
||||||
|
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>
|
||||||
152
src/modules/demo/views/crud/components/adv-search/custom.vue
Normal file
152
src/modules/demo/views/crud/components/adv-search/custom.vue
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
<template>
|
||||||
|
<div class="scope">
|
||||||
|
<div class="h">
|
||||||
|
<el-tag size="small" effect="dark">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: 160,
|
||||||
|
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>
|
||||||
41
src/modules/demo/views/crud/components/code.vue
Normal file
41
src/modules/demo/views/crud/components/code.vue
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
<template>
|
||||||
|
<cl-editor-preview name="monaco" :ref="setRefs('preview')" :tabs="tabs" v-if="!isHide">
|
||||||
|
<el-button @click="open">代码</el-button>
|
||||||
|
</cl-editor-preview>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts" name="demo-code">
|
||||||
|
import { useCool } from "/@/cool";
|
||||||
|
import { type PropType, computed } from "vue";
|
||||||
|
import { demo } from "virtual:demo";
|
||||||
|
import { basename } from "/@/cool/utils";
|
||||||
|
import { isEmpty } from "lodash-es";
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
files: {
|
||||||
|
type: Array as PropType<string[]>,
|
||||||
|
default: () => []
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const { refs, setRefs } = useCool();
|
||||||
|
|
||||||
|
// 是否隐藏
|
||||||
|
const isHide = computed(() => isEmpty(demo));
|
||||||
|
|
||||||
|
// 文件列表
|
||||||
|
const tabs = computed(() => {
|
||||||
|
return props.files?.map((e) => {
|
||||||
|
return {
|
||||||
|
name: basename(e),
|
||||||
|
language: e.includes(".vue") ? "html" : "typescript",
|
||||||
|
data: demo[e]
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 打开
|
||||||
|
function open() {
|
||||||
|
refs.preview.open();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@ -1,103 +1,128 @@
|
|||||||
<template>
|
<template>
|
||||||
<cl-crud ref="Crud">
|
<div class="scope">
|
||||||
<cl-row>
|
<div class="h">
|
||||||
<!-- 刷新按钮 -->
|
<el-tag size="small" effect="dark">all</el-tag>
|
||||||
<cl-refresh-btn />
|
<span>完整示例</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- 新增按钮 -->
|
<div class="c">
|
||||||
<cl-add-btn />
|
<el-button @click="open">预览</el-button>
|
||||||
|
<demo-code :files="['crud/all.vue']" />
|
||||||
|
|
||||||
<!-- 批量删除按钮 -->
|
<cl-dialog v-model="visible" title="完整示例" width="80%">
|
||||||
<cl-multi-delete-btn />
|
<cl-crud ref="Crud">
|
||||||
|
<cl-row>
|
||||||
|
<!-- 刷新按钮 -->
|
||||||
|
<cl-refresh-btn />
|
||||||
|
|
||||||
<!-- 自定义表单 -->
|
<!-- 新增按钮 -->
|
||||||
<form-btn />
|
<cl-add-btn />
|
||||||
|
|
||||||
<!-- 筛选 -->
|
<!-- 批量删除按钮 -->
|
||||||
<cl-filter label="状态筛选">
|
<cl-multi-delete-btn />
|
||||||
<!-- 配置props,选择后会自动过滤列表 -->
|
|
||||||
<cl-select :options="options.status" prop="status" :width="120" />
|
|
||||||
</cl-filter>
|
|
||||||
|
|
||||||
<!-- 字典 -->
|
<!-- 筛选 -->
|
||||||
<cl-filter label="工作(字典)">
|
<cl-filter label="状态筛选">
|
||||||
<cl-select :options="dict.get('occupation')" prop="occupation" :width="120" />
|
<!-- 配置props,选择后会自动过滤列表 -->
|
||||||
</cl-filter>
|
<cl-select :options="options.status" prop="status" :width="120" />
|
||||||
|
</cl-filter>
|
||||||
|
|
||||||
<cl-flex1 />
|
<!-- 字典 -->
|
||||||
|
<cl-filter label="工作(字典)">
|
||||||
|
<cl-select
|
||||||
|
:options="dict.get('occupation')"
|
||||||
|
prop="occupation"
|
||||||
|
:width="120"
|
||||||
|
/>
|
||||||
|
</cl-filter>
|
||||||
|
|
||||||
<!-- 导入 -->
|
<cl-flex1 />
|
||||||
<cl-import-btn template="/用户导入模版.xlsx" />
|
|
||||||
|
|
||||||
<!-- 导出 -->
|
<!-- 导入 -->
|
||||||
<cl-export-btn :columns="Table?.columns" />
|
<cl-import-btn template="/用户导入模版.xlsx" />
|
||||||
|
|
||||||
<!-- 自定义列 -->
|
<!-- 导出 -->
|
||||||
<cl-column-custom :columns="Table?.columns" :ref="setRefs('columnCustom')" />
|
<cl-export-btn :columns="Table?.columns" />
|
||||||
|
|
||||||
<!-- 关键字搜索 -->
|
<!-- 自定义列 -->
|
||||||
<cl-search-key placeholder="搜索姓名、手机号" :width="250" />
|
<cl-column-custom
|
||||||
|
:columns="Table?.columns"
|
||||||
|
:ref="setRefs('columnCustom')"
|
||||||
|
/>
|
||||||
|
|
||||||
<!-- 高级搜索按钮 -->
|
<!-- 关键字搜索 -->
|
||||||
<cl-adv-btn />
|
<cl-search-key placeholder="搜索姓名、手机号" :width="250" />
|
||||||
</cl-row>
|
|
||||||
|
|
||||||
<cl-row>
|
<!-- 高级搜索按钮 -->
|
||||||
<!-- 表格 -->
|
<cl-adv-btn />
|
||||||
<cl-table ref="Table" show-summary :summary-method="onSummaryMethod">
|
</cl-row>
|
||||||
<!-- 展开信息 -->
|
|
||||||
<template #column-detail="{ scope }">
|
|
||||||
<div style="padding: 0 10px">
|
|
||||||
<el-descriptions border :column="3">
|
|
||||||
<el-descriptions-item label="ID">
|
|
||||||
{{ scope.row.id }}
|
|
||||||
</el-descriptions-item>
|
|
||||||
|
|
||||||
<el-descriptions-item label="姓名">
|
<cl-row>
|
||||||
{{ scope.row.name }}
|
<!-- 表格 -->
|
||||||
</el-descriptions-item>
|
<cl-table
|
||||||
|
ref="Table"
|
||||||
|
show-summary
|
||||||
|
:summary-method="onSummaryMethod"
|
||||||
|
:auto-height="false"
|
||||||
|
>
|
||||||
|
<!-- 展开信息 -->
|
||||||
|
<template #column-detail="{ scope }">
|
||||||
|
<div style="padding: 0 10px">
|
||||||
|
<el-descriptions border :column="3">
|
||||||
|
<el-descriptions-item label="ID">
|
||||||
|
{{ scope.row.id }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
|
||||||
<el-descriptions-item label="存款">
|
<el-descriptions-item label="姓名">
|
||||||
{{ scope.row.wages }}
|
{{ scope.row.name }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
|
|
||||||
<el-descriptions-item label="出生年月">
|
<el-descriptions-item label="存款">
|
||||||
{{ scope.row.createTime }}
|
{{ scope.row.wages }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
</el-descriptions>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<!-- 自定义列 -->
|
<el-descriptions-item label="出生年月">
|
||||||
<template #column-wages="{ scope }">
|
{{ scope.row.createTime }}
|
||||||
<span>{{ scope.row.wages }}🤑</span>
|
</el-descriptions-item>
|
||||||
</template>
|
</el-descriptions>
|
||||||
</cl-table>
|
</div>
|
||||||
</cl-row>
|
</template>
|
||||||
|
|
||||||
<cl-row>
|
<!-- 自定义列 -->
|
||||||
<cl-flex1 />
|
<template #column-wages="{ scope }">
|
||||||
|
<span>{{ scope.row.wages }}🤑</span>
|
||||||
|
</template>
|
||||||
|
</cl-table>
|
||||||
|
</cl-row>
|
||||||
|
|
||||||
<!-- 分页 -->
|
<cl-row>
|
||||||
<cl-pagination />
|
<cl-flex1 />
|
||||||
</cl-row>
|
|
||||||
|
|
||||||
<!-- 新增、编辑 -->
|
<!-- 分页 -->
|
||||||
<cl-upsert ref="Upsert" />
|
<cl-pagination />
|
||||||
|
</cl-row>
|
||||||
|
|
||||||
<!-- 高级搜索 -->
|
<!-- 新增、编辑 -->
|
||||||
<cl-adv-search ref="AdvSearch" />
|
<cl-upsert ref="Upsert" />
|
||||||
</cl-crud>
|
|
||||||
|
<!-- 高级搜索 -->
|
||||||
|
<cl-adv-search ref="AdvSearch" />
|
||||||
|
</cl-crud>
|
||||||
|
</cl-dialog>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="f">
|
||||||
|
<span class="date">2024-01-01</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="tsx" name="demo-crud" setup>
|
<script lang="tsx" name="demo-crud" setup>
|
||||||
import { useCrud, useUpsert, useTable, useAdvSearch, setFocus, useSearch } from "@cool-vue/crud";
|
import { useCrud, useUpsert, useTable, useAdvSearch, setFocus, useSearch } from "@cool-vue/crud";
|
||||||
import { useDict } from "/$/dict";
|
import { useDict } from "/$/dict";
|
||||||
import { reactive } from "vue";
|
import { reactive, ref } from "vue";
|
||||||
import { ElMessage, ElMessageBox } from "element-plus";
|
import { ElMessage, ElMessageBox } from "element-plus";
|
||||||
import { useCool } from "/@/cool";
|
import { useCool } from "/@/cool";
|
||||||
import FormBtn from "../components/form-btn.vue";
|
|
||||||
import SelectUser from "../components/select-user.vue";
|
|
||||||
|
|
||||||
// 基础
|
// 基础
|
||||||
const { service, refs, setRefs } = useCool();
|
const { service, refs, setRefs } = useCool();
|
||||||
@ -140,6 +165,7 @@ const Crud = useCrud(
|
|||||||
(app) => {
|
(app) => {
|
||||||
// Crud 加载完,默认刷新一次
|
// Crud 加载完,默认刷新一次
|
||||||
app.refresh({
|
app.refresh({
|
||||||
|
size: 10
|
||||||
// status: 1 // 带额外参数的请求
|
// status: 1 // 带额外参数的请求
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -153,11 +179,6 @@ function refresh(params?: any) {
|
|||||||
// 新增、编辑
|
// 新增、编辑
|
||||||
// 插入类型 <Eps.UserInfoEntity>,prop 和 data 会有提示
|
// 插入类型 <Eps.UserInfoEntity>,prop 和 data 会有提示
|
||||||
const Upsert = useUpsert<Eps.UserInfoEntity>({
|
const Upsert = useUpsert<Eps.UserInfoEntity>({
|
||||||
dialog: {
|
|
||||||
height: "600px", // 固定高
|
|
||||||
width: "1000px" // 固定宽
|
|
||||||
},
|
|
||||||
|
|
||||||
items: [
|
items: [
|
||||||
// 分组
|
// 分组
|
||||||
{
|
{
|
||||||
@ -169,10 +190,6 @@ const Upsert = useUpsert<Eps.UserInfoEntity>({
|
|||||||
label: "基础信息",
|
label: "基础信息",
|
||||||
value: "base"
|
value: "base"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
label: "选择用户",
|
|
||||||
value: "select"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
label: "其他配置",
|
label: "其他配置",
|
||||||
value: "other"
|
value: "other"
|
||||||
@ -214,8 +231,8 @@ const Upsert = useUpsert<Eps.UserInfoEntity>({
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: "user",
|
|
||||||
group: "base",
|
group: "base",
|
||||||
|
prop: "user",
|
||||||
component: {
|
component: {
|
||||||
name: "cl-form-card",
|
name: "cl-form-card",
|
||||||
props: {
|
props: {
|
||||||
@ -241,8 +258,8 @@ const Upsert = useUpsert<Eps.UserInfoEntity>({
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: "contact",
|
|
||||||
group: "base",
|
group: "base",
|
||||||
|
prop: "contact",
|
||||||
component: {
|
component: {
|
||||||
name: "cl-form-card",
|
name: "cl-form-card",
|
||||||
props: {
|
props: {
|
||||||
@ -268,24 +285,10 @@ const Upsert = useUpsert<Eps.UserInfoEntity>({
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
|
||||||
label: "",
|
|
||||||
prop: "userIds",
|
|
||||||
group: "select",
|
|
||||||
props: {
|
|
||||||
labelWidth: "0px"
|
|
||||||
},
|
|
||||||
required: true,
|
|
||||||
component: {
|
|
||||||
vm: SelectUser
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
{
|
||||||
|
group: "other",
|
||||||
label: "工作",
|
label: "工作",
|
||||||
prop: "occupation",
|
prop: "occupation",
|
||||||
group: "other",
|
|
||||||
component: {
|
component: {
|
||||||
name: "el-tree-select",
|
name: "el-tree-select",
|
||||||
props: {
|
props: {
|
||||||
@ -295,9 +298,9 @@ const Upsert = useUpsert<Eps.UserInfoEntity>({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
group: "other",
|
||||||
label: "身份证照片",
|
label: "身份证照片",
|
||||||
prop: "idCardPic",
|
prop: "idCardPic",
|
||||||
group: "other",
|
|
||||||
component: {
|
component: {
|
||||||
name: "cl-upload",
|
name: "cl-upload",
|
||||||
props: {
|
props: {
|
||||||
@ -566,4 +569,10 @@ const Search = useSearch({
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const visible = ref(false);
|
||||||
|
|
||||||
|
function open() {
|
||||||
|
visible.value = true;
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
145
src/modules/demo/views/crud/components/crud/base.vue
Normal file
145
src/modules/demo/views/crud/components/crud/base.vue
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
<template>
|
||||||
|
<div class="scope">
|
||||||
|
<div class="h">
|
||||||
|
<el-tag size="small" effect="dark">base</el-tag>
|
||||||
|
<span>起步</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="c">
|
||||||
|
<el-button @click="open">预览</el-button>
|
||||||
|
<demo-code :files="['crud/base.vue']" />
|
||||||
|
|
||||||
|
<!-- 自定义表格组件 -->
|
||||||
|
<cl-dialog v-model="visible" title="起步" width="80%">
|
||||||
|
<cl-crud ref="Crud">
|
||||||
|
<cl-row>
|
||||||
|
<cl-refresh-btn />
|
||||||
|
<cl-add-btn />
|
||||||
|
<cl-multi-delete-btn />
|
||||||
|
|
||||||
|
<cl-flex1 />
|
||||||
|
|
||||||
|
<cl-search-key />
|
||||||
|
</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(
|
||||||
|
{
|
||||||
|
// test 为测试数据模式,详细说明移步到 service 例子
|
||||||
|
service: "test"
|
||||||
|
},
|
||||||
|
(app) => {
|
||||||
|
//【很重要】首次请求,数据一并添加到请求参数中
|
||||||
|
app.refresh({
|
||||||
|
size: 10,
|
||||||
|
status: 1
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// cl-table 配置
|
||||||
|
const Table = useTable({
|
||||||
|
autoHeight: false,
|
||||||
|
contextMenu: ["refresh"],
|
||||||
|
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
type: "selection"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "姓名",
|
||||||
|
prop: "name",
|
||||||
|
minWidth: 140
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "手机号",
|
||||||
|
prop: "phone",
|
||||||
|
minWidth: 140
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "工作",
|
||||||
|
prop: "occupation",
|
||||||
|
dict: dict.get("occupation"),
|
||||||
|
minWidth: 140
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "创建时间",
|
||||||
|
prop: "createTime",
|
||||||
|
minWidth: 160,
|
||||||
|
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: "occupation",
|
||||||
|
component: {
|
||||||
|
name: "cl-select",
|
||||||
|
props: {
|
||||||
|
tree: true,
|
||||||
|
checkStrictly: true,
|
||||||
|
options: dict.get("occupation")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
const visible = ref(false);
|
||||||
|
|
||||||
|
function open() {
|
||||||
|
visible.value = true;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
164
src/modules/demo/views/crud/components/crud/dict.vue
Normal file
164
src/modules/demo/views/crud/components/crud/dict.vue
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
<template>
|
||||||
|
<div class="scope">
|
||||||
|
<div class="h">
|
||||||
|
<el-tag size="small" effect="dark">dict</el-tag>
|
||||||
|
<span>修改文案 / 接口</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="c">
|
||||||
|
<el-button @click="open">预览</el-button>
|
||||||
|
<demo-code :files="['crud/dict.vue']" />
|
||||||
|
|
||||||
|
<!-- 自定义表格组件 -->
|
||||||
|
<cl-dialog v-model="visible" title="修改文案 / 接口" width="80%">
|
||||||
|
<cl-crud ref="Crud">
|
||||||
|
<cl-row>
|
||||||
|
<cl-refresh-btn />
|
||||||
|
<cl-add-btn />
|
||||||
|
<cl-multi-delete-btn />
|
||||||
|
|
||||||
|
<cl-flex1 />
|
||||||
|
|
||||||
|
<cl-search-key />
|
||||||
|
</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,如:service.base.sys.user
|
||||||
|
service: "test",
|
||||||
|
|
||||||
|
//【很重要】字典配置,文案和请求方法等
|
||||||
|
dict: {
|
||||||
|
// 修改请求
|
||||||
|
// 比如说默认列表请求的是 page 接口,可以修改成 getUserList 等等,这取决于后端有没有这个接口。
|
||||||
|
api: {
|
||||||
|
list: "list",
|
||||||
|
add: "add",
|
||||||
|
update: "update",
|
||||||
|
delete: "delete",
|
||||||
|
info: "info",
|
||||||
|
page: "page"
|
||||||
|
},
|
||||||
|
|
||||||
|
// 修改文案
|
||||||
|
label: {
|
||||||
|
op: "操作",
|
||||||
|
add: "添加",
|
||||||
|
delete: "移除",
|
||||||
|
multiDelete: "批量移除",
|
||||||
|
update: "修改",
|
||||||
|
refresh: "刷新",
|
||||||
|
info: "详情"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
(app) => {
|
||||||
|
app.refresh();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// cl-table 配置
|
||||||
|
const Table = useTable({
|
||||||
|
autoHeight: false,
|
||||||
|
contextMenu: ["refresh"],
|
||||||
|
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
type: "selection"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "姓名",
|
||||||
|
prop: "name",
|
||||||
|
minWidth: 140
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "手机号",
|
||||||
|
prop: "phone",
|
||||||
|
minWidth: 140
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "工作",
|
||||||
|
prop: "occupation",
|
||||||
|
dict: dict.get("occupation"),
|
||||||
|
minWidth: 140
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "创建时间",
|
||||||
|
prop: "createTime",
|
||||||
|
minWidth: 160,
|
||||||
|
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: "occupation",
|
||||||
|
component: {
|
||||||
|
name: "cl-select",
|
||||||
|
props: {
|
||||||
|
tree: true,
|
||||||
|
checkStrictly: true,
|
||||||
|
options: dict.get("occupation")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
const visible = ref(false);
|
||||||
|
|
||||||
|
function open() {
|
||||||
|
visible.value = true;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
182
src/modules/demo/views/crud/components/crud/event.vue
Normal file
182
src/modules/demo/views/crud/components/crud/event.vue
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
<template>
|
||||||
|
<div class="scope">
|
||||||
|
<div class="h">
|
||||||
|
<el-tag size="small" effect="dark">event</el-tag>
|
||||||
|
<span>事件监听</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="c">
|
||||||
|
<el-button @click="open">预览</el-button>
|
||||||
|
<demo-code :files="['crud/event.vue']" />
|
||||||
|
|
||||||
|
<!-- 自定义表格组件 -->
|
||||||
|
<cl-dialog v-model="visible" title="事件监听" width="80%">
|
||||||
|
<cl-crud ref="Crud">
|
||||||
|
<cl-row>
|
||||||
|
<cl-refresh-btn />
|
||||||
|
<cl-add-btn />
|
||||||
|
<cl-multi-delete-btn />
|
||||||
|
|
||||||
|
<cl-flex1 />
|
||||||
|
|
||||||
|
<cl-search-key />
|
||||||
|
</cl-row>
|
||||||
|
|
||||||
|
<cl-row>
|
||||||
|
<cl-table ref="Table">
|
||||||
|
<!-- 自定义按钮 -->
|
||||||
|
<template #slot-btn="{ scope }">
|
||||||
|
<el-button @click="onEvent(scope.row)">自定义事件</el-button>
|
||||||
|
</template>
|
||||||
|
</cl-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";
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
|
|
||||||
|
const { service } = useCool();
|
||||||
|
const { dict } = useDict();
|
||||||
|
|
||||||
|
// cl-crud 配置
|
||||||
|
const Crud = useCrud(
|
||||||
|
{
|
||||||
|
// 配置 service
|
||||||
|
service: "test",
|
||||||
|
|
||||||
|
//【很重要】监听刷新事件,每次调用 Crud.value.refresh() 会触发
|
||||||
|
onRefresh(params, { next }) {
|
||||||
|
// 默认使用 next(params),也可以自己对数据进行处理
|
||||||
|
next({
|
||||||
|
...params,
|
||||||
|
status: 1
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
// 监听删除事件,点击删除按钮触发
|
||||||
|
onDelete(selection, { next }) {
|
||||||
|
// 传入 ids,批量删除多个数据
|
||||||
|
next({
|
||||||
|
ids: selection.map((e) => e.id)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
(app) => {
|
||||||
|
app.refresh();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// cl-table 配置
|
||||||
|
const Table = useTable({
|
||||||
|
autoHeight: false,
|
||||||
|
contextMenu: ["refresh"],
|
||||||
|
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
type: "selection"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "姓名",
|
||||||
|
prop: "name",
|
||||||
|
minWidth: 140
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "手机号",
|
||||||
|
prop: "phone",
|
||||||
|
minWidth: 140
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "工作",
|
||||||
|
prop: "occupation",
|
||||||
|
dict: dict.get("occupation"),
|
||||||
|
minWidth: 140
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "创建时间",
|
||||||
|
prop: "createTime",
|
||||||
|
minWidth: 160,
|
||||||
|
sortable: "desc"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "op",
|
||||||
|
width: 300,
|
||||||
|
buttons: ["edit", "delete", "slot-btn"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
// 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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
// 调用 Crud 方法
|
||||||
|
function onEvent(row: any) {
|
||||||
|
ElMessage.info("自定义打开新增");
|
||||||
|
|
||||||
|
// 打开新增表单
|
||||||
|
Crud.value?.rowAdd();
|
||||||
|
|
||||||
|
// 打开编辑表单
|
||||||
|
// Crud.value?.rowEdit(row);
|
||||||
|
|
||||||
|
// 打开删除提示框
|
||||||
|
// Crud.value?.rowDelete(row);
|
||||||
|
|
||||||
|
// 获取已请求的参数
|
||||||
|
// Crud.value?.getParams();
|
||||||
|
}
|
||||||
|
|
||||||
|
const visible = ref(false);
|
||||||
|
|
||||||
|
function open() {
|
||||||
|
visible.value = true;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
185
src/modules/demo/views/crud/components/crud/service.vue
Normal file
185
src/modules/demo/views/crud/components/crud/service.vue
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
<template>
|
||||||
|
<div class="scope">
|
||||||
|
<div class="h">
|
||||||
|
<el-tag size="small" effect="dark">service</el-tag>
|
||||||
|
<span>Service 配置</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="c">
|
||||||
|
<el-button @click="open">预览</el-button>
|
||||||
|
<demo-code :files="['crud/service.vue']" />
|
||||||
|
|
||||||
|
<!-- 自定义表格组件 -->
|
||||||
|
<cl-dialog v-model="visible" title="Service 配置" width="80%">
|
||||||
|
<cl-crud ref="Crud">
|
||||||
|
<cl-row>
|
||||||
|
<cl-refresh-btn />
|
||||||
|
<cl-add-btn />
|
||||||
|
<cl-multi-delete-btn />
|
||||||
|
|
||||||
|
<cl-flex1 />
|
||||||
|
|
||||||
|
<cl-search-key />
|
||||||
|
</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 { useCool } from "/@/cool";
|
||||||
|
|
||||||
|
//【很重要】service 是所有请求的集合,是一个对象(刷新页面和保存代码会自动读取后端的所有接口)
|
||||||
|
const { service } = useCool();
|
||||||
|
console.log("service", service);
|
||||||
|
|
||||||
|
// cl-crud 配置
|
||||||
|
const Crud = useCrud(
|
||||||
|
{
|
||||||
|
//【很重要】配置 service,如:service.demo.goods
|
||||||
|
// 不需要到具体的方法,如:service.demo.goods.page,这是错误的!
|
||||||
|
service: service.demo.goods
|
||||||
|
|
||||||
|
// 自定义配置1,添加本地 service 文件。
|
||||||
|
// 【很重要】参考 /src/modules/demo/service/test.ts
|
||||||
|
// 【很重要】必须放在目录 modules/*/service/ 下,才会自动注入到 service 中
|
||||||
|
// service: service.test
|
||||||
|
|
||||||
|
// 自定义配置2,针对一些特殊场景
|
||||||
|
// service: {
|
||||||
|
// page(params: any) {
|
||||||
|
// // params 请求参数
|
||||||
|
// //【很重要】必须返回一个 Promise 格式
|
||||||
|
// return Promise.resolve({
|
||||||
|
// list: [],
|
||||||
|
// pagination: {
|
||||||
|
// total: 1,
|
||||||
|
// page: 1,
|
||||||
|
// size: 20
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // add、delete、update、info、list 也是如此配置
|
||||||
|
// }
|
||||||
|
},
|
||||||
|
(app) => {
|
||||||
|
app.refresh();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// cl-table 配置
|
||||||
|
const Table = useTable({
|
||||||
|
autoHeight: false,
|
||||||
|
contextMenu: ["refresh"],
|
||||||
|
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
type: "selection"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "商品名称",
|
||||||
|
prop: "title",
|
||||||
|
minWidth: 140
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "价格",
|
||||||
|
prop: "price",
|
||||||
|
minWidth: 140
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "主图",
|
||||||
|
prop: "mainImage",
|
||||||
|
minWidth: 140,
|
||||||
|
component: {
|
||||||
|
name: "cl-image",
|
||||||
|
props: {
|
||||||
|
size: 60
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "描述",
|
||||||
|
prop: "description",
|
||||||
|
minWidth: 200,
|
||||||
|
showOverflowTooltip: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "创建时间",
|
||||||
|
prop: "createTime",
|
||||||
|
minWidth: 160,
|
||||||
|
sortable: "desc"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "op",
|
||||||
|
buttons: ["edit", "delete"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
// cl-upsert 配置
|
||||||
|
const Upsert = useUpsert({
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
label: "商品名称",
|
||||||
|
prop: "title",
|
||||||
|
required: true,
|
||||||
|
component: {
|
||||||
|
name: "el-input"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "价格",
|
||||||
|
prop: "price",
|
||||||
|
required: true,
|
||||||
|
component: {
|
||||||
|
name: "el-input-number"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "主图",
|
||||||
|
prop: "mainImage",
|
||||||
|
required: true,
|
||||||
|
component: {
|
||||||
|
name: "cl-upload"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "描述",
|
||||||
|
prop: "description",
|
||||||
|
component: {
|
||||||
|
name: "el-input",
|
||||||
|
props: {
|
||||||
|
type: "textarea",
|
||||||
|
rows: 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
const visible = ref(false);
|
||||||
|
|
||||||
|
function open() {
|
||||||
|
visible.value = true;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
118
src/modules/demo/views/crud/components/form/children.vue
Normal file
118
src/modules/demo/views/crud/components/form/children.vue
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
<template>
|
||||||
|
<div class="scope">
|
||||||
|
<div class="h">
|
||||||
|
<el-tag size="small" effect="dark">children</el-tag>
|
||||||
|
<span>层级显示</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="c">
|
||||||
|
<el-button @click="open">预览</el-button>
|
||||||
|
<demo-code :files="['form/children.vue']" />
|
||||||
|
|
||||||
|
<!-- 自定义表单组件 -->
|
||||||
|
<cl-form ref="Form"></cl-form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="f">
|
||||||
|
<span class="date">2024-01-01</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useForm } from "@cool-vue/crud";
|
||||||
|
|
||||||
|
const Form = useForm();
|
||||||
|
|
||||||
|
function open() {
|
||||||
|
Form.value?.open({
|
||||||
|
title: "层级显示",
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
label: "姓名",
|
||||||
|
prop: "name",
|
||||||
|
component: {
|
||||||
|
name: "el-input"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "年龄",
|
||||||
|
prop: "age",
|
||||||
|
value: 18,
|
||||||
|
component: {
|
||||||
|
name: "el-input-number"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 基础信息
|
||||||
|
{
|
||||||
|
component: {
|
||||||
|
//【很重要】使用 cl-form-card 组件渲染,也可以使用自定义
|
||||||
|
name: "cl-form-card",
|
||||||
|
props: {
|
||||||
|
// 标题
|
||||||
|
label: "基础信息",
|
||||||
|
// 是否展开,默认 true
|
||||||
|
expand: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
label: "账号",
|
||||||
|
prop: "account",
|
||||||
|
component: {
|
||||||
|
name: "el-input"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "密码",
|
||||||
|
prop: "password",
|
||||||
|
component: {
|
||||||
|
name: "el-input"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
// 其他信息
|
||||||
|
{
|
||||||
|
component: {
|
||||||
|
name: "cl-form-card",
|
||||||
|
props: {
|
||||||
|
label: "其他信息",
|
||||||
|
expand: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
label: "身份证",
|
||||||
|
prop: "idcard",
|
||||||
|
component: {
|
||||||
|
name: "el-input"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "学校",
|
||||||
|
prop: "school",
|
||||||
|
component: {
|
||||||
|
name: "el-input"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "专业",
|
||||||
|
prop: "major",
|
||||||
|
component: {
|
||||||
|
name: "el-input"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
on: {
|
||||||
|
submit(data, { close }) {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
106
src/modules/demo/views/crud/components/form/component/index.vue
Normal file
106
src/modules/demo/views/crud/components/form/component/index.vue
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
<template>
|
||||||
|
<div class="scope">
|
||||||
|
<div class="h">
|
||||||
|
<el-tag size="small" effect="dark">component</el-tag>
|
||||||
|
<span>组件渲染</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="c">
|
||||||
|
<el-button @click="open">预览</el-button>
|
||||||
|
<demo-code
|
||||||
|
:files="[
|
||||||
|
'form/component/index.vue',
|
||||||
|
'form/component/select-labels.vue',
|
||||||
|
'form/component/select-status.vue',
|
||||||
|
'form/component/select-work.vue'
|
||||||
|
]"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- 自定义表单组件 -->
|
||||||
|
<cl-form ref="Form">
|
||||||
|
<!-- 年龄插槽 -->
|
||||||
|
<template #slot-age="{ scope }">
|
||||||
|
<!-- scope 为表单值 -->
|
||||||
|
<el-input-number v-model="scope.age" :min="18" :max="100"></el-input-number>
|
||||||
|
</template>
|
||||||
|
</cl-form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="f">
|
||||||
|
<span class="date">2024-01-01</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useForm } from "@cool-vue/crud";
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
|
import SelectWork from "./select-work.vue";
|
||||||
|
import SelectLabels from "./select-labels.vue";
|
||||||
|
import SelectStatus from "./select-status.vue";
|
||||||
|
|
||||||
|
const Form = useForm();
|
||||||
|
|
||||||
|
function open() {
|
||||||
|
Form.value?.open({
|
||||||
|
title: "组件配置",
|
||||||
|
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
label: "昵称",
|
||||||
|
prop: "nickname",
|
||||||
|
// 组件配置方式1:标签名(方便,但是不建议组件全局注册)
|
||||||
|
component: {
|
||||||
|
// 必须是“全局注册”的组件名,如 element-plus 的 el-input、el-date-picker 等
|
||||||
|
name: "el-input"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "年龄",
|
||||||
|
prop: "age",
|
||||||
|
// 组件配置方式2:插槽(万能,就是代码多写点)
|
||||||
|
component: {
|
||||||
|
// 必须是 "slot-" 开头
|
||||||
|
name: "slot-age"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// -- start 组件配置方式3:组件实例(不想全局注册,但又想组件化)
|
||||||
|
{
|
||||||
|
label: "工作",
|
||||||
|
prop: "work",
|
||||||
|
component: {
|
||||||
|
// 双向绑定
|
||||||
|
vm: SelectWork
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "标签",
|
||||||
|
prop: "labels",
|
||||||
|
value: [],
|
||||||
|
component: {
|
||||||
|
// scope[prop]绑定
|
||||||
|
vm: SelectLabels
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "状态",
|
||||||
|
prop: "status",
|
||||||
|
value: 1,
|
||||||
|
component: {
|
||||||
|
// useForm 绑定
|
||||||
|
vm: SelectStatus
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// -- end
|
||||||
|
],
|
||||||
|
on: {
|
||||||
|
submit(data, { close }) {
|
||||||
|
ElMessage.info(
|
||||||
|
`${data.name || "无名"}(${data.age || 18}岁)工作:${data.work || "无"}`
|
||||||
|
);
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@ -0,0 +1,38 @@
|
|||||||
|
<template>
|
||||||
|
<!--【很重要】直接绑定表单值 scope[prop] -->
|
||||||
|
<!-- !符号,只是为了类型提示不错误 -->
|
||||||
|
<el-select v-model="scope[prop!]" multiple>
|
||||||
|
<el-option
|
||||||
|
v-for="(item, index) in list"
|
||||||
|
:key="index"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.label"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!--【很重要】必须要有name,避免注册后和其他冲突 -->
|
||||||
|
<script setup lang="ts" name="select-labels">
|
||||||
|
import { ref } from "vue";
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
scope: null, // 表单值
|
||||||
|
prop: String // 表单项配置的 prop
|
||||||
|
});
|
||||||
|
|
||||||
|
// 选项列表
|
||||||
|
const list = ref<{ label: string; value: string }[]>([
|
||||||
|
{
|
||||||
|
label: "倒茶",
|
||||||
|
value: "倒茶" // 测试直接使用label,真实情况可能是1,2,3,4或者id
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "设计",
|
||||||
|
value: "设计"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "开发",
|
||||||
|
value: "开发"
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
</script>
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
<template>
|
||||||
|
<!--【很重要】直接绑定status,或者使用 form[prop!] -->
|
||||||
|
<el-radio-group v-model="form.status">
|
||||||
|
<el-radio v-for="(item, index) in list" :key="index" :label="item.value">
|
||||||
|
{{ item.label }}
|
||||||
|
</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!--【很重要】必须要有name,避免注册后和其他冲突 -->
|
||||||
|
<script setup lang="ts" name="select-status">
|
||||||
|
import { useForm } from "@cool-vue/crud";
|
||||||
|
import { computed, ref } from "vue";
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
scope: null, // 表单值
|
||||||
|
prop: String // 表单项配置的 prop
|
||||||
|
});
|
||||||
|
|
||||||
|
// 使用 useForm,能直接获取到上级的表单实例,
|
||||||
|
// 比如操作表单的 Form.value?.submit、Form.value?.close等
|
||||||
|
// 获取表单值,Form.value?.form
|
||||||
|
const Form = useForm();
|
||||||
|
|
||||||
|
// 表单值,包一层不会太难受
|
||||||
|
const form = computed(() => Form.value?.form || {});
|
||||||
|
|
||||||
|
// 选项列表
|
||||||
|
const list = ref<{ label: string; value: number }[]>([
|
||||||
|
{
|
||||||
|
label: "很好",
|
||||||
|
value: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "不舒服",
|
||||||
|
value: 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "要嘎了",
|
||||||
|
value: 3
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
</script>
|
||||||
@ -0,0 +1,59 @@
|
|||||||
|
<template>
|
||||||
|
<el-select v-model="active" @change="onChange">
|
||||||
|
<el-option
|
||||||
|
v-for="(item, index) in list"
|
||||||
|
:key="index"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.label"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 【很重要】必须要有name,避免注册后和其他冲突 -->
|
||||||
|
<script setup lang="ts" name="select-work">
|
||||||
|
import { ref, watch } from "vue";
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
modelValue: Number
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(["update:modelValue", "change"]);
|
||||||
|
|
||||||
|
//【很重要】绑定值
|
||||||
|
// 这种方式虽然麻烦,但是可扩展性高,一些复杂的数据结构可以按这种方式绑定值
|
||||||
|
const active = ref();
|
||||||
|
|
||||||
|
// 选项列表
|
||||||
|
const list = ref<{ label: string; value: string }[]>([
|
||||||
|
{
|
||||||
|
label: "倒茶",
|
||||||
|
value: "倒茶" // 测试直接使用label,真实情况可能是1,2,3,4或者id
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "设计",
|
||||||
|
value: "设计"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "开发",
|
||||||
|
value: "开发"
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
//【很重要】更新绑定值,表单提交才能得到选择后的
|
||||||
|
function onChange(val: string) {
|
||||||
|
emit("update:modelValue", val);
|
||||||
|
emit("change", val);
|
||||||
|
}
|
||||||
|
|
||||||
|
//【很重要】使用监听的方式,避免表单打开数据是异步获取的情况
|
||||||
|
watch(
|
||||||
|
() => props.modelValue,
|
||||||
|
(val) => {
|
||||||
|
// 设置选中的值
|
||||||
|
active.value = val;
|
||||||
|
},
|
||||||
|
{
|
||||||
|
immediate: true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
</script>
|
||||||
122
src/modules/demo/views/crud/components/form/config.vue
Normal file
122
src/modules/demo/views/crud/components/form/config.vue
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
<template>
|
||||||
|
<div class="scope">
|
||||||
|
<div class="h">
|
||||||
|
<el-tag size="small" effect="dark">config</el-tag>
|
||||||
|
<span>参数配置</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="c">
|
||||||
|
<el-button @click="open">预览</el-button>
|
||||||
|
<demo-code :files="['form/config.vue']" />
|
||||||
|
|
||||||
|
<!-- 自定义表单组件 -->
|
||||||
|
<cl-form ref="Form">
|
||||||
|
<!-- 按钮插槽 -->
|
||||||
|
<template #slot-btns>
|
||||||
|
<el-button type="danger">按钮插槽</el-button>
|
||||||
|
</template>
|
||||||
|
</cl-form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="f">
|
||||||
|
<span class="date">2024-01-01</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useForm } from "@cool-vue/crud";
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
|
|
||||||
|
const Form = useForm();
|
||||||
|
|
||||||
|
function open() {
|
||||||
|
Form.value?.open({
|
||||||
|
title: "参数配置",
|
||||||
|
|
||||||
|
// 打开是否重置表单
|
||||||
|
isReset: false,
|
||||||
|
|
||||||
|
// 默认表单值
|
||||||
|
form: {
|
||||||
|
nickName: "神仙都没用"
|
||||||
|
},
|
||||||
|
|
||||||
|
// 表单配置
|
||||||
|
props: {
|
||||||
|
// 标签宽度
|
||||||
|
labelWidth: "120px",
|
||||||
|
|
||||||
|
// 标签位置
|
||||||
|
labelPosition: "top"
|
||||||
|
},
|
||||||
|
|
||||||
|
// 窗口的高。配置后,在窗口内部滚动。默认整个页面滚动
|
||||||
|
height: "60vh",
|
||||||
|
|
||||||
|
// 窗口的宽,默认 50%
|
||||||
|
width: "60%",
|
||||||
|
|
||||||
|
// 窗口设置
|
||||||
|
dialog: {
|
||||||
|
// 是否隐藏头部
|
||||||
|
hideHeader: false,
|
||||||
|
|
||||||
|
// 顶部操作按钮,默认["fullscreen", "close"]
|
||||||
|
// fullscreen 全屏
|
||||||
|
// close 关闭
|
||||||
|
controls: ["close"]
|
||||||
|
},
|
||||||
|
|
||||||
|
// 底部操作按钮
|
||||||
|
op: {
|
||||||
|
// 默认靠右布局
|
||||||
|
justify: "flex-end",
|
||||||
|
|
||||||
|
// 保存按钮文字
|
||||||
|
saveButtonText: "提交",
|
||||||
|
|
||||||
|
// 关闭按钮文字
|
||||||
|
closeButtonText: "关闭",
|
||||||
|
|
||||||
|
// 是否隐藏
|
||||||
|
hidden: false,
|
||||||
|
|
||||||
|
// 按钮配置
|
||||||
|
buttons: [
|
||||||
|
// 自定义
|
||||||
|
{
|
||||||
|
label: "自定义按钮",
|
||||||
|
onClick() {
|
||||||
|
ElMessage.success("自定义按钮点击");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// close 关闭
|
||||||
|
"close",
|
||||||
|
// save 保存
|
||||||
|
"save",
|
||||||
|
// 插槽使用,配合 template,往上看 cl-form 组件
|
||||||
|
"slot-btns"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
// 表单项配置
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
label: "昵称",
|
||||||
|
prop: "nickName",
|
||||||
|
component: {
|
||||||
|
name: "el-input"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
// 事件
|
||||||
|
on: {
|
||||||
|
submit(data, { close }) {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@ -1,44 +1,59 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-button type="primary" @click="open">自定义表单</el-button>
|
<div class="scope">
|
||||||
|
<div class="h">
|
||||||
|
<el-tag size="small" effect="dark">crud</el-tag>
|
||||||
|
<span>内嵌CRUD</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<cl-form ref="Form">
|
<div class="c">
|
||||||
<template #slot-crud>
|
<el-button @click="open">预览</el-button>
|
||||||
<cl-crud ref="Crud" border>
|
<demo-code :files="['form/crud.vue']" />
|
||||||
<cl-row>
|
|
||||||
<!-- 刷新按钮 -->
|
|
||||||
<cl-refresh-btn />
|
|
||||||
<!-- 新增按钮 -->
|
|
||||||
<cl-add-btn />
|
|
||||||
<!-- 删除按钮 -->
|
|
||||||
<cl-multi-delete-btn />
|
|
||||||
<cl-flex1 />
|
|
||||||
<!-- 关键字搜索 -->
|
|
||||||
<cl-search-key placeholder="搜索姓名、手机号" />
|
|
||||||
</cl-row>
|
|
||||||
|
|
||||||
<cl-row>
|
<!-- 自定义表单组件 -->
|
||||||
<!-- 数据表格 -->
|
<cl-form ref="Form">
|
||||||
<cl-table ref="Table" />
|
<template #slot-crud>
|
||||||
</cl-row>
|
<cl-crud ref="Crud" border>
|
||||||
|
<cl-row>
|
||||||
|
<!-- 刷新按钮 -->
|
||||||
|
<cl-refresh-btn />
|
||||||
|
<!-- 新增按钮 -->
|
||||||
|
<cl-add-btn />
|
||||||
|
<!-- 删除按钮 -->
|
||||||
|
<cl-multi-delete-btn />
|
||||||
|
<cl-flex1 />
|
||||||
|
<!-- 关键字搜索 -->
|
||||||
|
<cl-search-key placeholder="搜索姓名、手机号" />
|
||||||
|
</cl-row>
|
||||||
|
|
||||||
<cl-row>
|
<cl-row>
|
||||||
<cl-flex1 />
|
<!-- 数据表格 -->
|
||||||
<!-- 分页控件 -->
|
<cl-table ref="Table" />
|
||||||
<cl-pagination />
|
</cl-row>
|
||||||
</cl-row>
|
|
||||||
|
|
||||||
<!-- 新增、编辑 -->
|
<cl-row>
|
||||||
<cl-upsert ref="Upsert" />
|
<cl-flex1 />
|
||||||
</cl-crud>
|
<!-- 分页控件 -->
|
||||||
</template>
|
<cl-pagination />
|
||||||
</cl-form>
|
</cl-row>
|
||||||
|
|
||||||
|
<!-- 新增、编辑 -->
|
||||||
|
<cl-upsert ref="Upsert" />
|
||||||
|
</cl-crud>
|
||||||
|
</template>
|
||||||
|
</cl-form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="f">
|
||||||
|
<span class="date">2024-01-01</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script setup lang="ts">
|
||||||
import { useCrud, useForm, useTable, useUpsert, setFocus } from "@cool-vue/crud";
|
import { useCrud, useForm, useTable, useUpsert, setFocus } from "@cool-vue/crud";
|
||||||
import { useCool } from "/@/cool";
|
import { useCool } from "/@/cool";
|
||||||
|
|
||||||
const { refs, setRefs, service } = useCool();
|
const { service } = useCool();
|
||||||
|
|
||||||
// cl-upsert
|
// cl-upsert
|
||||||
const Upsert = useUpsert({
|
const Upsert = useUpsert({
|
||||||
@ -100,7 +115,7 @@ const Form = useForm();
|
|||||||
|
|
||||||
function open() {
|
function open() {
|
||||||
Form.value?.open({
|
Form.value?.open({
|
||||||
title: "自定义表单",
|
title: "内嵌CRUD",
|
||||||
props: {
|
props: {
|
||||||
labelPosition: "top"
|
labelPosition: "top"
|
||||||
},
|
},
|
||||||
@ -110,11 +125,10 @@ function open() {
|
|||||||
},
|
},
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
label: "获取 ref,打开后聚焦",
|
label: "姓名",
|
||||||
prop: "name",
|
prop: "name",
|
||||||
component: {
|
component: {
|
||||||
name: "el-input",
|
name: "el-input",
|
||||||
ref: setRefs("name"),
|
|
||||||
props: {
|
props: {
|
||||||
placeholder: "请填写姓名"
|
placeholder: "请填写姓名"
|
||||||
}
|
}
|
||||||
@ -131,13 +145,7 @@ function open() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
op: {
|
|
||||||
// buttons: ["save"]
|
|
||||||
},
|
|
||||||
on: {
|
on: {
|
||||||
open() {
|
|
||||||
refs.name.focus();
|
|
||||||
},
|
|
||||||
submit() {
|
submit() {
|
||||||
Form.value?.close();
|
Form.value?.close();
|
||||||
}
|
}
|
||||||
64
src/modules/demo/views/crud/components/form/disabled.vue
Normal file
64
src/modules/demo/views/crud/components/form/disabled.vue
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
<template>
|
||||||
|
<div class="scope">
|
||||||
|
<div class="h">
|
||||||
|
<el-tag size="small" effect="dark">disabled</el-tag>
|
||||||
|
<span>组件禁用</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="c">
|
||||||
|
<el-button @click="open">预览</el-button>
|
||||||
|
<demo-code :files="['form/disabled.vue']" />
|
||||||
|
|
||||||
|
<!-- 自定义表单组件 -->
|
||||||
|
<cl-form ref="Form"></cl-form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="f">
|
||||||
|
<span class="date">2024-01-01</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useForm } from "@cool-vue/crud";
|
||||||
|
|
||||||
|
const Form = useForm();
|
||||||
|
|
||||||
|
function open() {
|
||||||
|
Form.value?.open({
|
||||||
|
title: "组件禁用",
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
label: "账号",
|
||||||
|
prop: "account",
|
||||||
|
component: {
|
||||||
|
name: "el-input",
|
||||||
|
props: {
|
||||||
|
// 设置 boolean 值控制组件的禁用状态(前提是组件支持这个参数,element 的组件几乎都有)
|
||||||
|
disabled: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "密码",
|
||||||
|
prop: "password",
|
||||||
|
component: {
|
||||||
|
name: "el-input"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
on: {
|
||||||
|
open() {
|
||||||
|
// 通用 setProps 方法去设置 disabled, 1.5s后禁用
|
||||||
|
setTimeout(() => {
|
||||||
|
Form.value?.setProps("password", { disabled: true });
|
||||||
|
}, 1500);
|
||||||
|
},
|
||||||
|
|
||||||
|
submit(data, { close }) {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
93
src/modules/demo/views/crud/components/form/event.vue
Normal file
93
src/modules/demo/views/crud/components/form/event.vue
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
<template>
|
||||||
|
<div class="scope">
|
||||||
|
<div class="h">
|
||||||
|
<el-tag size="small" effect="dark">event</el-tag>
|
||||||
|
<span>组件事件</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="c">
|
||||||
|
<el-button @click="open">预览</el-button>
|
||||||
|
<demo-code :files="['form/event.vue']" />
|
||||||
|
|
||||||
|
<!-- 自定义表单组件 -->
|
||||||
|
<cl-form ref="Form"></cl-form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="f">
|
||||||
|
<span class="date">2024-01-01</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useForm } from "@cool-vue/crud";
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
|
|
||||||
|
const Form = useForm();
|
||||||
|
|
||||||
|
function open() {
|
||||||
|
Form.value?.open({
|
||||||
|
title: "组件事件",
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
label: "账号",
|
||||||
|
prop: "account",
|
||||||
|
component: {
|
||||||
|
name: "el-input",
|
||||||
|
props: {
|
||||||
|
// 组件内 emit 的用 on[name] 接收,如 onChange、onInput、onBlur 等
|
||||||
|
// 前提是组件内有触发事件
|
||||||
|
onBlur() {
|
||||||
|
ElMessage.info("账号检查中");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "是否实名",
|
||||||
|
prop: "status",
|
||||||
|
value: 1,
|
||||||
|
component: {
|
||||||
|
name: "el-radio-group",
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: "关闭",
|
||||||
|
value: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "开启",
|
||||||
|
value: 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
props: {
|
||||||
|
// 值改变事件
|
||||||
|
onChange(val: number) {
|
||||||
|
if (val == 1) {
|
||||||
|
// 显示表单项
|
||||||
|
Form.value?.showItem("idcard");
|
||||||
|
} else {
|
||||||
|
// 隐藏表单项
|
||||||
|
Form.value?.hideItem("idcard");
|
||||||
|
// 清空值
|
||||||
|
Form.value?.setForm("idcard", undefined);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "身份证",
|
||||||
|
prop: "idcard",
|
||||||
|
component: {
|
||||||
|
name: "el-input"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
on: {
|
||||||
|
submit(data, { close }) {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
105
src/modules/demo/views/crud/components/form/group.vue
Normal file
105
src/modules/demo/views/crud/components/form/group.vue
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
<template>
|
||||||
|
<div class="scope">
|
||||||
|
<div class="h">
|
||||||
|
<el-tag size="small" effect="dark">group</el-tag>
|
||||||
|
<span>分组显示</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="c">
|
||||||
|
<el-button @click="open">预览</el-button>
|
||||||
|
<demo-code :files="['form/group.vue']" />
|
||||||
|
|
||||||
|
<!-- 自定义表单组件 -->
|
||||||
|
<cl-form ref="Form"></cl-form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="f">
|
||||||
|
<span class="date">2024-01-01</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useForm } from "@cool-vue/crud";
|
||||||
|
|
||||||
|
const Form = useForm();
|
||||||
|
|
||||||
|
function open() {
|
||||||
|
Form.value?.open({
|
||||||
|
title: "分组显示",
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
//【很重要】必须为 tabs
|
||||||
|
type: "tabs",
|
||||||
|
props: {
|
||||||
|
// 分组样式
|
||||||
|
type: "card",
|
||||||
|
// 分组列表,必须是 { label, value } 的数组格式
|
||||||
|
labels: [
|
||||||
|
{
|
||||||
|
label: "基础信息", // 标题
|
||||||
|
value: "base" // 唯一标识
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "认证信息",
|
||||||
|
value: "auth"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 基础信息
|
||||||
|
{
|
||||||
|
group: "base", // 标识
|
||||||
|
label: "账号",
|
||||||
|
prop: "account",
|
||||||
|
required: true,
|
||||||
|
component: {
|
||||||
|
name: "el-input"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
group: "base", // 标识
|
||||||
|
label: "密码",
|
||||||
|
prop: "password",
|
||||||
|
required: true,
|
||||||
|
component: {
|
||||||
|
name: "el-input"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 其他信息 group = other
|
||||||
|
{
|
||||||
|
group: "auth", // 标识
|
||||||
|
label: "身份证",
|
||||||
|
prop: "idcard",
|
||||||
|
required: true,
|
||||||
|
component: {
|
||||||
|
name: "el-input"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
group: "auth", // 标识
|
||||||
|
label: "学校",
|
||||||
|
prop: "school",
|
||||||
|
component: {
|
||||||
|
name: "el-input"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
group: "auth", // 标识
|
||||||
|
label: "专业",
|
||||||
|
prop: "major",
|
||||||
|
component: {
|
||||||
|
name: "el-input"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
on: {
|
||||||
|
//【提示】当第一组验证通过后,会自动切换到下一组展示,直到全部通过才可提交
|
||||||
|
submit(data, { close }) {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
77
src/modules/demo/views/crud/components/form/hidden.vue
Normal file
77
src/modules/demo/views/crud/components/form/hidden.vue
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
<template>
|
||||||
|
<div class="scope">
|
||||||
|
<div class="h">
|
||||||
|
<el-tag size="small" effect="dark">hidden</el-tag>
|
||||||
|
<span>隐藏/显示</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="c">
|
||||||
|
<el-button @click="open">预览</el-button>
|
||||||
|
<demo-code :files="['form/hidden.vue']" />
|
||||||
|
|
||||||
|
<!-- 自定义表单组件 -->
|
||||||
|
<cl-form ref="Form"></cl-form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="f">
|
||||||
|
<span class="date">2024-01-01</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useForm } from "@cool-vue/crud";
|
||||||
|
|
||||||
|
const Form = useForm();
|
||||||
|
|
||||||
|
function open() {
|
||||||
|
Form.value?.open({
|
||||||
|
title: "隐藏/显示",
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
label: "状态",
|
||||||
|
prop: "status",
|
||||||
|
value: 0,
|
||||||
|
component: {
|
||||||
|
name: "el-radio-group",
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: "关闭",
|
||||||
|
value: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "开启",
|
||||||
|
value: 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "账号",
|
||||||
|
prop: "account",
|
||||||
|
component: {
|
||||||
|
name: "el-input"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
//【很重要】是否隐藏
|
||||||
|
hidden({ scope }) {
|
||||||
|
// scope 为表单值
|
||||||
|
// 返回一个 boolean 来控制当前表单项的隐藏/显示
|
||||||
|
return scope.status != 1;
|
||||||
|
},
|
||||||
|
label: "密码",
|
||||||
|
prop: "password",
|
||||||
|
component: {
|
||||||
|
name: "el-input"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
on: {
|
||||||
|
submit(data, { close }) {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
116
src/modules/demo/views/crud/components/form/layout.vue
Normal file
116
src/modules/demo/views/crud/components/form/layout.vue
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
<template>
|
||||||
|
<div class="scope">
|
||||||
|
<div class="h">
|
||||||
|
<el-tag size="small" effect="dark">layout</el-tag>
|
||||||
|
<span>布局</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="c">
|
||||||
|
<el-button @click="open">预览</el-button>
|
||||||
|
<demo-code :files="['form/layout.vue']" />
|
||||||
|
|
||||||
|
<!-- 自定义表单组件 -->
|
||||||
|
<cl-form ref="Form"></cl-form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="f">
|
||||||
|
<span class="date">2024-01-01</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useForm } from "@cool-vue/crud";
|
||||||
|
|
||||||
|
const Form = useForm();
|
||||||
|
|
||||||
|
function open() {
|
||||||
|
Form.value?.open({
|
||||||
|
title: "布局",
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
//【span】参考文档:https://element-plus.gitee.io/zh-CN/component/layout.html
|
||||||
|
// 使用 1/24 分栏,默认 24
|
||||||
|
span: 12,
|
||||||
|
label: "昵称",
|
||||||
|
prop: "nickname",
|
||||||
|
component: {
|
||||||
|
name: "el-input"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
span: 12,
|
||||||
|
label: "手机号",
|
||||||
|
prop: "phone",
|
||||||
|
component: {
|
||||||
|
name: "el-input",
|
||||||
|
props: {
|
||||||
|
maxlength: 11
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
//【flex】使宽度不填充满
|
||||||
|
flex: false,
|
||||||
|
label: "标签",
|
||||||
|
prop: "label",
|
||||||
|
component: {
|
||||||
|
name: "el-select",
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: "javascript",
|
||||||
|
value: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "vue",
|
||||||
|
value: 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "html",
|
||||||
|
value: 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "css",
|
||||||
|
value: 4
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "状态",
|
||||||
|
prop: "status",
|
||||||
|
value: 1,
|
||||||
|
component: {
|
||||||
|
name: "el-radio-group",
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: "开启",
|
||||||
|
value: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "关闭",
|
||||||
|
value: 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "备注",
|
||||||
|
prop: "remark",
|
||||||
|
component: {
|
||||||
|
name: "el-input",
|
||||||
|
props: {
|
||||||
|
type: "textarea",
|
||||||
|
rows: 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
on: {
|
||||||
|
submit(data, { close }) {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
83
src/modules/demo/views/crud/components/form/open.vue
Normal file
83
src/modules/demo/views/crud/components/form/open.vue
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
<template>
|
||||||
|
<div class="scope">
|
||||||
|
<div class="h">
|
||||||
|
<el-tag size="small" effect="dark">open</el-tag>
|
||||||
|
<span>起步</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="c">
|
||||||
|
<el-button @click="open">预览</el-button>
|
||||||
|
<demo-code :files="['form/open.vue']" />
|
||||||
|
|
||||||
|
<!-- 自定义表单组件 -->
|
||||||
|
<!--【很重要】ref 一定要对应 useForm 定义的值 -->
|
||||||
|
<cl-form ref="Form"></cl-form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="f">
|
||||||
|
<span class="date">2024-01-01</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useForm } from "@cool-vue/crud";
|
||||||
|
|
||||||
|
const Form = useForm();
|
||||||
|
|
||||||
|
function open() {
|
||||||
|
Form.value?.open({
|
||||||
|
title: "起步",
|
||||||
|
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
label: "昵称",
|
||||||
|
// 绑定值的标识,表单提交及回显会自动根据 prop 获取对应的值
|
||||||
|
prop: "nickname",
|
||||||
|
// 组件绑定
|
||||||
|
component: {
|
||||||
|
// 必须是“全局注册”的组件名,如 element-plus 的 el-input、el-date-picker 等
|
||||||
|
name: "el-input",
|
||||||
|
|
||||||
|
// 绑定的组件参数配置,如 clearable、placeholder 等
|
||||||
|
// 组件内 emit 的用 on[name] 接收,如 onChange、onInput、onBlur 等
|
||||||
|
props: {
|
||||||
|
placeholder: "请输入昵称",
|
||||||
|
clearable: true,
|
||||||
|
onChange(value: string) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "年龄",
|
||||||
|
prop: "age",
|
||||||
|
component: {
|
||||||
|
name: "el-input-number"
|
||||||
|
},
|
||||||
|
// 默认值,第一次打开有效
|
||||||
|
value: 18
|
||||||
|
}
|
||||||
|
],
|
||||||
|
on: {
|
||||||
|
// 打开时触发
|
||||||
|
open() {},
|
||||||
|
|
||||||
|
// 关闭时触发。当配置该方法时,关闭事件会被阻断,使用 done() 关闭窗口
|
||||||
|
close(action, done) {
|
||||||
|
// action 为关闭窗口的触发动作 "save" | "close"
|
||||||
|
// done 关闭事件
|
||||||
|
done();
|
||||||
|
},
|
||||||
|
|
||||||
|
// 提交时触发
|
||||||
|
submit(data, { done, close }) {
|
||||||
|
// data 为表单值
|
||||||
|
// done 关闭加载事件、但不关闭窗口
|
||||||
|
// close 关闭窗口
|
||||||
|
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
172
src/modules/demo/views/crud/components/form/options.vue
Normal file
172
src/modules/demo/views/crud/components/form/options.vue
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
<template>
|
||||||
|
<div class="scope">
|
||||||
|
<div class="h">
|
||||||
|
<el-tag size="small" effect="dark">options</el-tag>
|
||||||
|
<span>选项框配置</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="c">
|
||||||
|
<el-button @click="open">预览</el-button>
|
||||||
|
<demo-code :files="['form/options.vue']" />
|
||||||
|
|
||||||
|
<!-- 自定义表单组件 -->
|
||||||
|
<cl-form ref="Form"></cl-form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="f">
|
||||||
|
<span class="date">2024-01-01</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useForm } from "@cool-vue/crud";
|
||||||
|
import { computed, reactive } from "vue";
|
||||||
|
|
||||||
|
const Form = useForm();
|
||||||
|
|
||||||
|
// 觉得麻烦就 any,如 { user: [] as any[] }
|
||||||
|
const options = reactive<{ [key: string]: { label: string; value: any }[] }>({
|
||||||
|
user: []
|
||||||
|
});
|
||||||
|
|
||||||
|
function open() {
|
||||||
|
Form.value?.open({
|
||||||
|
title: "选项框配置",
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
label: "下拉框",
|
||||||
|
prop: "select",
|
||||||
|
component: {
|
||||||
|
name: "el-select",
|
||||||
|
props: {
|
||||||
|
clearable: true // 可清除
|
||||||
|
},
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: "javascript",
|
||||||
|
value: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "vue",
|
||||||
|
value: 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "html",
|
||||||
|
value: 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "css",
|
||||||
|
value: 4
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "单选框",
|
||||||
|
prop: "radio",
|
||||||
|
value: 1,
|
||||||
|
component: {
|
||||||
|
name: "el-radio-group",
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: "手机",
|
||||||
|
value: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "电脑",
|
||||||
|
value: 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "电视",
|
||||||
|
value: 3
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "多选框",
|
||||||
|
prop: "checkbox",
|
||||||
|
value: [2, 3],
|
||||||
|
component: {
|
||||||
|
name: "el-checkbox-group",
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: "咖啡",
|
||||||
|
value: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "汉堡",
|
||||||
|
value: 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "炸鸡",
|
||||||
|
value: 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "奶茶",
|
||||||
|
value: 4
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "动态配置1",
|
||||||
|
prop: "d1",
|
||||||
|
component: {
|
||||||
|
name: "el-select",
|
||||||
|
// 动态设置方法1,在 on.open 事件配置 options
|
||||||
|
options: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "动态配置2",
|
||||||
|
prop: "d2",
|
||||||
|
component: {
|
||||||
|
name: "el-select",
|
||||||
|
// 动态设置方法2,使用 computed 更新 options
|
||||||
|
options: computed(() => options.user)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
on: {
|
||||||
|
open() {
|
||||||
|
// 模拟 1.5s 后取的数据
|
||||||
|
setTimeout(() => {
|
||||||
|
// 动态设置方法1,使用 setOptions 方法设置
|
||||||
|
// d1 为 prop 值
|
||||||
|
Form.value?.setOptions("d1", [
|
||||||
|
{
|
||||||
|
label: "😊",
|
||||||
|
value: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "😭",
|
||||||
|
value: 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "😘",
|
||||||
|
value: 3
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 动态设置方法2,直接设置 options.user,由 computed 更新
|
||||||
|
options.user = [
|
||||||
|
{
|
||||||
|
label: "💰",
|
||||||
|
value: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "🚗",
|
||||||
|
value: 2
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}, 1500);
|
||||||
|
},
|
||||||
|
submit(data, { close }) {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
112
src/modules/demo/views/crud/components/form/plugin/index.vue
Normal file
112
src/modules/demo/views/crud/components/form/plugin/index.vue
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
<template>
|
||||||
|
<div class="scope">
|
||||||
|
<div class="h">
|
||||||
|
<el-tag size="small" effect="dark">plugin</el-tag>
|
||||||
|
<span>插件的使用</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="c">
|
||||||
|
<el-button @click="open('manager')">管理者</el-button>
|
||||||
|
<el-button @click="open('user')">用户</el-button>
|
||||||
|
<demo-code :files="['form/plugin/index.vue', 'form/plugin/role.ts']" />
|
||||||
|
|
||||||
|
<!-- 自定义表单组件 -->
|
||||||
|
<cl-form ref="Form"></cl-form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="f">
|
||||||
|
<span class="date">2024-01-01</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { setFocus, useForm } from "@cool-vue/crud";
|
||||||
|
import { setRole } from "./role";
|
||||||
|
|
||||||
|
const Form = useForm();
|
||||||
|
|
||||||
|
function open(role: string) {
|
||||||
|
Form.value?.open(
|
||||||
|
{
|
||||||
|
title: "插件的使用",
|
||||||
|
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
label: "姓名",
|
||||||
|
prop: "name",
|
||||||
|
required: true,
|
||||||
|
component: {
|
||||||
|
name: "el-input"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// 自定义参数 role,匹配插件传入的角色
|
||||||
|
role: "user",
|
||||||
|
label: "面试职位",
|
||||||
|
prop: "work",
|
||||||
|
value: 1,
|
||||||
|
component: {
|
||||||
|
name: "el-radio-group",
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: "前端开发",
|
||||||
|
value: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "后端开发",
|
||||||
|
value: 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "UI设计",
|
||||||
|
value: 3
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
role: "user",
|
||||||
|
label: "期望薪资",
|
||||||
|
prop: "salary",
|
||||||
|
value: 5000,
|
||||||
|
component: {
|
||||||
|
name: "el-input-number",
|
||||||
|
props: {
|
||||||
|
min: 2000,
|
||||||
|
max: 100000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
role: "manager",
|
||||||
|
label: "入职时间",
|
||||||
|
prop: "date",
|
||||||
|
component: {
|
||||||
|
name: "el-date-picker"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
role: "manager",
|
||||||
|
label: "负责人",
|
||||||
|
prop: "head",
|
||||||
|
component: {
|
||||||
|
name: "el-input"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
on: {
|
||||||
|
submit(data, { done, close }) {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[
|
||||||
|
// 自动聚焦插件,不传参数则默认第一个item
|
||||||
|
setFocus(),
|
||||||
|
|
||||||
|
// 自定义插件,角色权限控制
|
||||||
|
setRole(role)
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
20
src/modules/demo/views/crud/components/form/plugin/role.ts
Normal file
20
src/modules/demo/views/crud/components/form/plugin/role.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
/**
|
||||||
|
* 角色权限控制
|
||||||
|
* @param role
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function setRole(role?: string): ClForm.Plugin {
|
||||||
|
return ({ exposed }) => {
|
||||||
|
function deep(arr: ClForm.Item[]) {
|
||||||
|
arr.forEach((e) => {
|
||||||
|
if (e.role) {
|
||||||
|
e.hidden = e.role != role;
|
||||||
|
}
|
||||||
|
|
||||||
|
deep(e.children || []);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
deep(exposed.config.items);
|
||||||
|
};
|
||||||
|
}
|
||||||
75
src/modules/demo/views/crud/components/form/required.vue
Normal file
75
src/modules/demo/views/crud/components/form/required.vue
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
<template>
|
||||||
|
<div class="scope">
|
||||||
|
<div class="h">
|
||||||
|
<el-tag size="small" effect="dark">required</el-tag>
|
||||||
|
<span>必填项配置</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="c">
|
||||||
|
<el-button @click="open">预览</el-button>
|
||||||
|
<demo-code :files="['form/required.vue']" />
|
||||||
|
|
||||||
|
<!-- 自定义表单组件 -->
|
||||||
|
<cl-form ref="Form"></cl-form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="f">
|
||||||
|
<span class="date">2024-01-01</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useForm } from "@cool-vue/crud";
|
||||||
|
|
||||||
|
const Form = useForm();
|
||||||
|
|
||||||
|
function open() {
|
||||||
|
Form.value?.open({
|
||||||
|
title: "必填项配置",
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
label: "昵称",
|
||||||
|
prop: "nickname",
|
||||||
|
component: {
|
||||||
|
name: "el-input"
|
||||||
|
},
|
||||||
|
// 是否必填,默认判断绑定值是否空
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "手机号",
|
||||||
|
prop: "phone",
|
||||||
|
component: {
|
||||||
|
name: "el-input",
|
||||||
|
props: {
|
||||||
|
maxlength: 11
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 自定义规则
|
||||||
|
// 基础用法可参考:https://element-plus.gitee.io/zh-CN/component/form.html
|
||||||
|
// 高级用法可参考:https://github.com/yiminghe/async-validator
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
validator: (rule, value, callback) => {
|
||||||
|
if (value === "") {
|
||||||
|
callback(new Error("手机号不能为空"));
|
||||||
|
} else if (!/^1[3456789]\d{9}$/.test(value)) {
|
||||||
|
callback(new Error("手机号格式错误"));
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
on: {
|
||||||
|
submit(data, { close }) {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
123
src/modules/demo/views/crud/components/form/rules.vue
Normal file
123
src/modules/demo/views/crud/components/form/rules.vue
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
<template>
|
||||||
|
<div class="scope">
|
||||||
|
<div class="h">
|
||||||
|
<el-tag size="small" effect="dark">rules</el-tag>
|
||||||
|
<span>添加/删除表单项</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="c">
|
||||||
|
<el-button @click="open">预览</el-button>
|
||||||
|
<demo-code :files="['form/rules.vue']" />
|
||||||
|
|
||||||
|
<!-- 自定义表单组件 -->
|
||||||
|
<cl-form ref="Form">
|
||||||
|
<template #slot-cert="{ scope }">
|
||||||
|
<div class="cert">
|
||||||
|
<!--【很重要】prop、rules 配置格式如下 -->
|
||||||
|
<el-form-item
|
||||||
|
v-for="(item, index) in scope.cert"
|
||||||
|
:key="index"
|
||||||
|
:label="`证书${index + 1}`"
|
||||||
|
:prop="`cert.${index}.label`"
|
||||||
|
:rules="{
|
||||||
|
message: `请填写证书${index + 1}`,
|
||||||
|
required: true
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<div class="row">
|
||||||
|
<!-- 输入框 -->
|
||||||
|
<el-input v-model="item.label" placeholder="请填写证书"></el-input>
|
||||||
|
|
||||||
|
<!-- 删除行 -->
|
||||||
|
<el-icon @click="rowDel(index)">
|
||||||
|
<delete />
|
||||||
|
</el-icon>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<!-- 添加行 -->
|
||||||
|
<el-row type="flex" justify="end">
|
||||||
|
<el-button @click="rowAdd()">添加证书</el-button>
|
||||||
|
</el-row>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</cl-form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="f">
|
||||||
|
<span class="date">2024-01-01</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useForm } from "@cool-vue/crud";
|
||||||
|
import { Delete } from "@element-plus/icons-vue";
|
||||||
|
|
||||||
|
const Form = useForm();
|
||||||
|
|
||||||
|
function open() {
|
||||||
|
Form.value?.open({
|
||||||
|
title: "添加/删除表单项",
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
label: "昵称",
|
||||||
|
prop: "nickname",
|
||||||
|
component: {
|
||||||
|
name: "el-input"
|
||||||
|
},
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: "cert",
|
||||||
|
//【很重要】默认数据格式,以实际业务为主。
|
||||||
|
value: [
|
||||||
|
{
|
||||||
|
label: ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
component: {
|
||||||
|
name: "slot-cert"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
on: {
|
||||||
|
submit(data, { close }) {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function rowAdd() {
|
||||||
|
Form.value?.form.cert.push({
|
||||||
|
label: ""
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function rowDel(index: number) {
|
||||||
|
Form.value?.form.cert.splice(index, 1);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.cert {
|
||||||
|
.row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.el-input {
|
||||||
|
flex: 1;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-icon {
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -63,7 +63,7 @@
|
|||||||
<script lang="ts" setup name="select-user">
|
<script lang="ts" setup name="select-user">
|
||||||
import { useCrud, useForm, useTable } from "@cool-vue/crud";
|
import { useCrud, useForm, useTable } from "@cool-vue/crud";
|
||||||
import { useCool } from "/@/cool";
|
import { useCool } from "/@/cool";
|
||||||
import { PropType, computed, nextTick, reactive, ref, watch } from "vue";
|
import { type PropType, computed, nextTick, reactive, ref, watch } from "vue";
|
||||||
import { cloneDeep } from "lodash-es";
|
import { cloneDeep } from "lodash-es";
|
||||||
|
|
||||||
// 替换你的类型
|
// 替换你的类型
|
||||||
168
src/modules/demo/views/crud/components/other/tips.vue
Normal file
168
src/modules/demo/views/crud/components/other/tips.vue
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
<template>
|
||||||
|
<div class="scope">
|
||||||
|
<div class="h">
|
||||||
|
<el-tag size="small" effect="dark">tips</el-tag>
|
||||||
|
<span>代码类型提示</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="c">
|
||||||
|
<el-button @click="open">预览</el-button>
|
||||||
|
<demo-code :files="['other/tips.vue']" />
|
||||||
|
|
||||||
|
<!-- 自定义表格组件 -->
|
||||||
|
<cl-dialog v-model="visible" title="代码类型提示" width="80%">
|
||||||
|
<cl-crud ref="Crud">
|
||||||
|
<cl-row>
|
||||||
|
<cl-refresh-btn />
|
||||||
|
<cl-add-btn />
|
||||||
|
<cl-multi-delete-btn />
|
||||||
|
|
||||||
|
<cl-flex1 />
|
||||||
|
|
||||||
|
<cl-search-key />
|
||||||
|
</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 { useCool } from "/@/cool";
|
||||||
|
|
||||||
|
const { service } = useCool();
|
||||||
|
|
||||||
|
// cl-crud 配置
|
||||||
|
const Crud = useCrud(
|
||||||
|
{
|
||||||
|
service: service.demo.goods
|
||||||
|
},
|
||||||
|
(app) => {
|
||||||
|
app.refresh();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// cl-table 配置
|
||||||
|
//【很重要】添加类型标注 <Eps.DemoGoodsEntity>,也可以自定义<{ title: string; price: number }>
|
||||||
|
const Table = useTable<Eps.DemoGoodsEntity>({
|
||||||
|
autoHeight: false,
|
||||||
|
contextMenu: ["refresh"],
|
||||||
|
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
type: "selection"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "商品标题",
|
||||||
|
prop: "title", //【很重要】编辑的时候会提示 DemoGoodsEntity 实体的属性名
|
||||||
|
minWidth: 140
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "主图",
|
||||||
|
prop: "mainImage",
|
||||||
|
minWidth: 140,
|
||||||
|
component: {
|
||||||
|
name: "cl-image",
|
||||||
|
props: {
|
||||||
|
size: 60
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "价格",
|
||||||
|
prop: "price",
|
||||||
|
minWidth: 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "库存",
|
||||||
|
prop: "stock",
|
||||||
|
minWidth: 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "创建时间",
|
||||||
|
prop: "createTime",
|
||||||
|
minWidth: 160,
|
||||||
|
sortable: "desc"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "op"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
// cl-upsert 配置
|
||||||
|
//【很重要】添加类型标注 <Eps.DemoGoodsEntity>,也可以自定义<{ title: string; price: number }>
|
||||||
|
const Upsert = useUpsert<Eps.DemoGoodsEntity>({
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
label: "商品标题",
|
||||||
|
prop: "title", //【很重要】编辑的时候会提示 DemoGoodsEntity 实体的属性名
|
||||||
|
component: {
|
||||||
|
name: "el-input"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "主图",
|
||||||
|
prop: "mainImage",
|
||||||
|
component: {
|
||||||
|
name: "cl-upload"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "价格",
|
||||||
|
prop: "price",
|
||||||
|
hook: "number",
|
||||||
|
component: {
|
||||||
|
name: "el-input-number",
|
||||||
|
props: {
|
||||||
|
min: 0.01,
|
||||||
|
max: 10000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "库存",
|
||||||
|
prop: "stock",
|
||||||
|
component: {
|
||||||
|
name: "el-input-number",
|
||||||
|
props: {
|
||||||
|
min: 0,
|
||||||
|
max: 1000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
onSubmit(data, { next }) {
|
||||||
|
// 【很重要】data 的类型也会被定义成 DemoGoodsEntity
|
||||||
|
|
||||||
|
next({
|
||||||
|
...data,
|
||||||
|
title: data.title
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const visible = ref(false);
|
||||||
|
|
||||||
|
function open() {
|
||||||
|
visible.value = true;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
28
src/modules/demo/views/crud/components/other/tsx/index.scss
Normal file
28
src/modules/demo/views/crud/components/other/tsx/index.scss
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
.tsx-list {
|
||||||
|
.item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
border: 1px solid var(--el-border-color);
|
||||||
|
padding: 10px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 4px;
|
||||||
|
|
||||||
|
.el-icon {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: var(--el-bg-color-page);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-active {
|
||||||
|
color: var(--el-color-primary);
|
||||||
|
|
||||||
|
.el-icon {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
107
src/modules/demo/views/crud/components/other/tsx/index.tsx
Normal file
107
src/modules/demo/views/crud/components/other/tsx/index.tsx
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
import { defineComponent, ref } from "vue";
|
||||||
|
import { Check } from "@element-plus/icons-vue";
|
||||||
|
import "./index.scss";
|
||||||
|
|
||||||
|
interface Item {
|
||||||
|
name: string;
|
||||||
|
value: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
emits: ["checked"],
|
||||||
|
|
||||||
|
setup(props, { emit, expose, slots }) {
|
||||||
|
// 列表数据
|
||||||
|
const list = ref<Item[]>([
|
||||||
|
{
|
||||||
|
name: "鸡腿堡",
|
||||||
|
value: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "牛肉堡",
|
||||||
|
value: 2
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 选择值
|
||||||
|
const active = ref();
|
||||||
|
|
||||||
|
// 是否可见
|
||||||
|
const visible = ref(false);
|
||||||
|
|
||||||
|
// 打开
|
||||||
|
function open() {
|
||||||
|
visible.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 选择
|
||||||
|
function toCheck(item: Item) {
|
||||||
|
active.value = item.value;
|
||||||
|
|
||||||
|
// 自定义事件
|
||||||
|
emit("checked", item);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 暴露方法和变量,使上级可以使用 ref 的方式来调用
|
||||||
|
expose({
|
||||||
|
toCheck
|
||||||
|
});
|
||||||
|
|
||||||
|
// 必须返回一个方法
|
||||||
|
return () => {
|
||||||
|
return (
|
||||||
|
<div class="scope">
|
||||||
|
<div class="h">
|
||||||
|
<el-tag size="small" effect="dark">
|
||||||
|
tsx
|
||||||
|
</el-tag>
|
||||||
|
<span>tsx示例</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="c">
|
||||||
|
<el-button onClick={open}>预览</el-button>
|
||||||
|
<demo-code files={["other/tsx/index.tsx"]} />
|
||||||
|
|
||||||
|
{/* ref 的绑定值必须 .value */}
|
||||||
|
<cl-dialog v-model={visible.value} title="tsx示例">
|
||||||
|
<div class="tsx-list">
|
||||||
|
{/* 循环的使用 */}
|
||||||
|
{list.value.map((item) => {
|
||||||
|
// 插槽的使用
|
||||||
|
return slots.default ? (
|
||||||
|
slots.default(item)
|
||||||
|
) : (
|
||||||
|
<div
|
||||||
|
// 动态样式的使用
|
||||||
|
class={[
|
||||||
|
"item",
|
||||||
|
{ "is-active": item.value == active.value }
|
||||||
|
]}
|
||||||
|
// 事件的使用
|
||||||
|
onClick={() => toCheck(item)}
|
||||||
|
>
|
||||||
|
<span>{item.name}</span>
|
||||||
|
|
||||||
|
<el-icon>
|
||||||
|
<Check />
|
||||||
|
</el-icon>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</cl-dialog>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="f">
|
||||||
|
<span class="date">2024-01-01</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 不推荐用该方法,在 setup 中返回模板信息
|
||||||
|
// render() {
|
||||||
|
// return <div></div>;
|
||||||
|
// }
|
||||||
|
});
|
||||||
143
src/modules/demo/views/crud/components/search/base.vue
Normal file
143
src/modules/demo/views/crud/components/search/base.vue
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
<template>
|
||||||
|
<div class="scope">
|
||||||
|
<div class="h">
|
||||||
|
<el-tag size="small" effect="dark">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" :reset-btn="true" />
|
||||||
|
</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: 160,
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
const visible = ref(false);
|
||||||
|
|
||||||
|
function open() {
|
||||||
|
visible.value = true;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
176
src/modules/demo/views/crud/components/search/custom.vue
Normal file
176
src/modules/demo/views/crud/components/search/custom.vue
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
<template>
|
||||||
|
<div class="scope">
|
||||||
|
<div class="h">
|
||||||
|
<el-tag size="small" effect="dark">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: 160,
|
||||||
|
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>
|
||||||
109
src/modules/demo/views/crud/components/table/base.vue
Normal file
109
src/modules/demo/views/crud/components/table/base.vue
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
<template>
|
||||||
|
<div class="scope">
|
||||||
|
<div class="h">
|
||||||
|
<el-tag size="small" effect="dark">base</el-tag>
|
||||||
|
<span>起步</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="c">
|
||||||
|
<el-button @click="open">预览</el-button>
|
||||||
|
<demo-code :files="['table/base.vue']" />
|
||||||
|
|
||||||
|
<!-- 自定义表格组件 -->
|
||||||
|
<cl-dialog v-model="visible" title="起步" width="80%">
|
||||||
|
<!--【很重要】需要包含在 cl-crud 组件内 -->
|
||||||
|
<cl-crud ref="Crud">
|
||||||
|
<cl-row>
|
||||||
|
<!-- 参数文档查看:https://element-plus.org/zh-CN/component/table.html#table-%E5%B1%9E%E6%80%A7 -->
|
||||||
|
<cl-table ref="Table" stripe></cl-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, useTable } from "@cool-vue/crud";
|
||||||
|
import { ref } from "vue";
|
||||||
|
import { useDict } from "/$/dict";
|
||||||
|
|
||||||
|
const { dict } = useDict();
|
||||||
|
|
||||||
|
// cl-crud 配置
|
||||||
|
const Crud = useCrud(
|
||||||
|
{
|
||||||
|
// 测试数据,移步到 cl-crud 例子查看
|
||||||
|
service: "test"
|
||||||
|
},
|
||||||
|
(app) => {
|
||||||
|
app.refresh();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// cl-table 配置
|
||||||
|
const Table = useTable({
|
||||||
|
// 是否自动计算表格高度,表格高度等于减去上区域和下区域的高度
|
||||||
|
//【很重要】在弹窗或者上级不确定高度中,设置 autoHeight: false,避免显示异常。也可以手动设置最大高度 maxHeight: 500
|
||||||
|
autoHeight: false,
|
||||||
|
|
||||||
|
// 右键菜单,移步到右键菜单示例中查看
|
||||||
|
contextMenu: ["refresh"],
|
||||||
|
|
||||||
|
// 列配置,点击 columns 查看描述
|
||||||
|
// 更多配置查看 el-table-column 文档,https://element-plus.org/zh-CN/component/table.html#table-column-%E5%B1%9E%E6%80%A7
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
// 是否为多选框操作列
|
||||||
|
type: "selection"
|
||||||
|
|
||||||
|
// 是否为序号列
|
||||||
|
// type: "index"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// 表头标题
|
||||||
|
label: "姓名",
|
||||||
|
|
||||||
|
// 绑定值
|
||||||
|
prop: "name",
|
||||||
|
|
||||||
|
// 最小宽度
|
||||||
|
minWidth: 140
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "手机号",
|
||||||
|
prop: "phone",
|
||||||
|
minWidth: 140
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "工作",
|
||||||
|
prop: "occupation",
|
||||||
|
// 字典匹配,移步到字典示例中查看
|
||||||
|
dict: dict.get("occupation"),
|
||||||
|
minWidth: 140
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "创建时间",
|
||||||
|
prop: "createTime",
|
||||||
|
minWidth: 160,
|
||||||
|
// 是否排序,desc, asc
|
||||||
|
sortable: "desc"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
const visible = ref(false);
|
||||||
|
|
||||||
|
function open() {
|
||||||
|
visible.value = true;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
98
src/modules/demo/views/crud/components/table/children.vue
Normal file
98
src/modules/demo/views/crud/components/table/children.vue
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
<template>
|
||||||
|
<div class="scope">
|
||||||
|
<div class="h">
|
||||||
|
<el-tag size="small" effect="dark">children</el-tag>
|
||||||
|
<span>多级表头</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="c">
|
||||||
|
<el-button @click="open">预览</el-button>
|
||||||
|
<demo-code :files="['table/children.vue']" />
|
||||||
|
|
||||||
|
<!-- 自定义表格组件 -->
|
||||||
|
<cl-dialog v-model="visible" title="多级表头" width="80%">
|
||||||
|
<cl-crud ref="Crud">
|
||||||
|
<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 } 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: "baseInfo",
|
||||||
|
minWidth: 250,
|
||||||
|
|
||||||
|
// 配置 children 参数
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
label: "姓名",
|
||||||
|
prop: "name",
|
||||||
|
minWidth: 140
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "手机号",
|
||||||
|
prop: "phone",
|
||||||
|
minWidth: 140
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "工作",
|
||||||
|
prop: "occupation",
|
||||||
|
dict: dict.get("occupation"),
|
||||||
|
minWidth: 140
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "创建时间",
|
||||||
|
prop: "createTime",
|
||||||
|
minWidth: 160,
|
||||||
|
sortable: "desc"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
const visible = ref(false);
|
||||||
|
|
||||||
|
function open() {
|
||||||
|
visible.value = true;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
108
src/modules/demo/views/crud/components/table/column-custom.vue
Normal file
108
src/modules/demo/views/crud/components/table/column-custom.vue
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
<template>
|
||||||
|
<div class="scope">
|
||||||
|
<div class="h">
|
||||||
|
<el-tag size="small" effect="dark">column-custom</el-tag>
|
||||||
|
<span>自定义列展示</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="c">
|
||||||
|
<el-button @click="open">预览</el-button>
|
||||||
|
<demo-code :files="['table/column-custom.vue']" />
|
||||||
|
|
||||||
|
<!-- 自定义表格组件 -->
|
||||||
|
<cl-dialog v-model="visible" title="自定义列展示" width="80%">
|
||||||
|
<cl-crud ref="Crud">
|
||||||
|
<cl-row>
|
||||||
|
<!--【很重要】组件配置,设置为 Table 的 columns,也可以自定义 -->
|
||||||
|
<cl-column-custom :columns="Table?.columns" />
|
||||||
|
</cl-row>
|
||||||
|
|
||||||
|
<cl-row>
|
||||||
|
<cl-table ref="Table"></cl-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, 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: "status",
|
||||||
|
dict: [
|
||||||
|
{
|
||||||
|
label: "启用",
|
||||||
|
value: 1,
|
||||||
|
type: "success"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "禁用",
|
||||||
|
value: 0,
|
||||||
|
type: "danger"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
minWidth: 140
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "创建时间",
|
||||||
|
prop: "createTime",
|
||||||
|
minWidth: 160,
|
||||||
|
sortable: "desc"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
const visible = ref(false);
|
||||||
|
|
||||||
|
function open() {
|
||||||
|
visible.value = true;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
108
src/modules/demo/views/crud/components/table/component/index.vue
Normal file
108
src/modules/demo/views/crud/components/table/component/index.vue
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
<template>
|
||||||
|
<div class="scope">
|
||||||
|
<div class="h">
|
||||||
|
<el-tag size="small" effect="dark">component</el-tag>
|
||||||
|
<span>组件渲染</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="c">
|
||||||
|
<el-button @click="open">预览</el-button>
|
||||||
|
<demo-code :files="['table/component/index.vue']" />
|
||||||
|
|
||||||
|
<!-- 自定义表格组件 -->
|
||||||
|
<cl-dialog v-model="visible" title="组件渲染" width="80%">
|
||||||
|
<cl-crud ref="Crud">
|
||||||
|
<cl-row>
|
||||||
|
<cl-table ref="Table"></cl-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, useTable } from "@cool-vue/crud";
|
||||||
|
import { ref } from "vue";
|
||||||
|
import { useDict } from "/$/dict";
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
|
import UserInfo from "./user-info.vue";
|
||||||
|
|
||||||
|
const { dict } = useDict();
|
||||||
|
|
||||||
|
// cl-crud 配置
|
||||||
|
const Crud = useCrud(
|
||||||
|
{
|
||||||
|
service: "test"
|
||||||
|
},
|
||||||
|
(app) => {
|
||||||
|
app.refresh();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// cl-table 配置
|
||||||
|
const Table = useTable({
|
||||||
|
autoHeight: false,
|
||||||
|
contextMenu: ["refresh"],
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
type: "selection"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "姓名",
|
||||||
|
prop: "name",
|
||||||
|
minWidth: 140,
|
||||||
|
|
||||||
|
//【很重要】组件实例方式渲染
|
||||||
|
component: {
|
||||||
|
vm: UserInfo
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "手机号",
|
||||||
|
prop: "phone",
|
||||||
|
minWidth: 140,
|
||||||
|
|
||||||
|
//【很重要】组件名方式渲染
|
||||||
|
component: {
|
||||||
|
// 组件名,组件必须全局注册了
|
||||||
|
name: "el-input",
|
||||||
|
|
||||||
|
// 传入参数
|
||||||
|
props: {
|
||||||
|
onChange(val) {
|
||||||
|
ElMessage.info(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "工作",
|
||||||
|
prop: "occupation",
|
||||||
|
dict: dict.get("occupation"),
|
||||||
|
minWidth: 140
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "创建时间",
|
||||||
|
prop: "createTime",
|
||||||
|
minWidth: 160,
|
||||||
|
sortable: "desc"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
const visible = ref(false);
|
||||||
|
|
||||||
|
function open() {
|
||||||
|
visible.value = true;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
<template>
|
||||||
|
<div class="user-info">
|
||||||
|
<cl-avatar :size="36" />
|
||||||
|
|
||||||
|
<div class="det">
|
||||||
|
<p>{{ scope?.name }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- name 必须填写且唯一 -->
|
||||||
|
<script setup lang="ts" name="user-info">
|
||||||
|
const props = defineProps({
|
||||||
|
prop: String, // 列配置的 prop
|
||||||
|
scope: null // 列数据
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.user-info {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.det {
|
||||||
|
flex: 1;
|
||||||
|
margin-left: 10px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
191
src/modules/demo/views/crud/components/table/context-menu.vue
Normal file
191
src/modules/demo/views/crud/components/table/context-menu.vue
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
<template>
|
||||||
|
<div class="scope">
|
||||||
|
<div class="h">
|
||||||
|
<el-tag size="small" effect="dark">context-menu</el-tag>
|
||||||
|
<span>右键菜单</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="c">
|
||||||
|
<el-button @click="open">预览</el-button>
|
||||||
|
<demo-code :files="['table/context-menu.vue']" />
|
||||||
|
|
||||||
|
<!-- 自定义表格组件 -->
|
||||||
|
<cl-dialog v-model="visible" title="右键菜单">
|
||||||
|
<cl-crud ref="Crud">
|
||||||
|
<cl-row>
|
||||||
|
<cl-table ref="Table"></cl-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";
|
||||||
|
import { EditPen, MoreFilled } from "@element-plus/icons-vue";
|
||||||
|
|
||||||
|
const { dict } = useDict();
|
||||||
|
|
||||||
|
// cl-crud 配置
|
||||||
|
const Crud = useCrud(
|
||||||
|
{
|
||||||
|
service: "test"
|
||||||
|
},
|
||||||
|
(app) => {
|
||||||
|
app.refresh();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// cl-table 配置
|
||||||
|
const Table = useTable({
|
||||||
|
autoHeight: false,
|
||||||
|
|
||||||
|
// 右键菜单配置,为 [] 时则不显示内容
|
||||||
|
contextMenu: [
|
||||||
|
"refresh", // 刷新
|
||||||
|
"check", // 选择行
|
||||||
|
"edit", // 弹出编辑框
|
||||||
|
"delete", // 弹出删除提示
|
||||||
|
"info", // 弹出详情
|
||||||
|
"order-desc", // 使列倒序
|
||||||
|
"order-asc", // 使列升序
|
||||||
|
{
|
||||||
|
label: "禁用状态",
|
||||||
|
disabled: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "带图标",
|
||||||
|
prefixIcon: EditPen,
|
||||||
|
suffixIcon: MoreFilled
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "超出隐藏,看我有很多字非常多",
|
||||||
|
ellipsis: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "多层级",
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
label: "A",
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
label: "A-1",
|
||||||
|
callback(done) {
|
||||||
|
ElMessage.success("点击了A-1");
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "B"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "C"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
// row 行数据
|
||||||
|
// column 列属性
|
||||||
|
// event 事件对象
|
||||||
|
(row, column, event) => {
|
||||||
|
// 必须返回一个对象
|
||||||
|
return {
|
||||||
|
label: "自定义2",
|
||||||
|
callback(done) {
|
||||||
|
ElMessage.info("获取中");
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
ElMessage.success(`Ta 是${row.name}`);
|
||||||
|
|
||||||
|
// 关闭右键菜单,只有在用到 callback 方法时才需要
|
||||||
|
done();
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
type: "selection"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "姓名",
|
||||||
|
prop: "name",
|
||||||
|
minWidth: 140
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "手机号",
|
||||||
|
prop: "phone",
|
||||||
|
minWidth: 140
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "工作",
|
||||||
|
prop: "occupation",
|
||||||
|
dict: dict.get("occupation"),
|
||||||
|
minWidth: 140
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "创建时间",
|
||||||
|
prop: "createTime",
|
||||||
|
minWidth: 160,
|
||||||
|
sortable: "desc"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
// cl-upsert 配置,详细移步到 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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
const visible = ref(false);
|
||||||
|
|
||||||
|
function open() {
|
||||||
|
visible.value = true;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
156
src/modules/demo/views/crud/components/table/dict.vue
Normal file
156
src/modules/demo/views/crud/components/table/dict.vue
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
<template>
|
||||||
|
<div class="scope">
|
||||||
|
<div class="h">
|
||||||
|
<el-tag size="small" effect="dark">dict</el-tag>
|
||||||
|
<span>字典匹配</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="c">
|
||||||
|
<el-button @click="open">预览</el-button>
|
||||||
|
<demo-code :files="['table/dict.vue']" />
|
||||||
|
|
||||||
|
<!-- 自定义表格组件 -->
|
||||||
|
<cl-dialog v-model="visible" title="字典匹配" width="80%">
|
||||||
|
<cl-crud ref="Crud">
|
||||||
|
<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, useTable } from "@cool-vue/crud";
|
||||||
|
import { computed, reactive, ref } from "vue";
|
||||||
|
import { useDict } from "/$/dict";
|
||||||
|
|
||||||
|
const { dict } = useDict();
|
||||||
|
|
||||||
|
// cl-crud 配置
|
||||||
|
const Crud = useCrud(
|
||||||
|
{
|
||||||
|
service: "test"
|
||||||
|
},
|
||||||
|
(app) => {
|
||||||
|
app.refresh();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const options = reactive({
|
||||||
|
occupation: [] as { label: string; value: any }[]
|
||||||
|
});
|
||||||
|
|
||||||
|
// cl-table 配置
|
||||||
|
const Table = useTable({
|
||||||
|
autoHeight: false,
|
||||||
|
contextMenu: ["refresh"],
|
||||||
|
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
label: "姓名",
|
||||||
|
prop: "name",
|
||||||
|
minWidth: 140
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "手机号",
|
||||||
|
prop: "phone",
|
||||||
|
minWidth: 140
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "工作",
|
||||||
|
prop: "occupation",
|
||||||
|
|
||||||
|
//【很重要】字典匹配
|
||||||
|
// 使用字典模块的 get 方法绑定,菜单地址 /dict/list
|
||||||
|
dict: dict.get("occupation"),
|
||||||
|
|
||||||
|
// 是否使用不同颜色区分
|
||||||
|
dictColor: true,
|
||||||
|
|
||||||
|
minWidth: 140
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "等级",
|
||||||
|
prop: "occupation",
|
||||||
|
|
||||||
|
//【很重要】动态匹配列表的情况,使用 computed
|
||||||
|
dict: computed(() => options.occupation),
|
||||||
|
|
||||||
|
minWidth: 140
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "状态",
|
||||||
|
prop: "status",
|
||||||
|
|
||||||
|
// 自定义匹配列表
|
||||||
|
dict: [
|
||||||
|
{
|
||||||
|
label: "启用", // 显示文本
|
||||||
|
value: 1, // 匹配值
|
||||||
|
type: "success" // el-tag 的type:success、danger、warning、info 默认 primary
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "禁用",
|
||||||
|
value: 0,
|
||||||
|
type: "danger"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
minWidth: 140
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "创建时间",
|
||||||
|
prop: "createTime",
|
||||||
|
minWidth: 160,
|
||||||
|
sortable: "desc"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
const visible = ref(false);
|
||||||
|
|
||||||
|
function open() {
|
||||||
|
visible.value = true;
|
||||||
|
|
||||||
|
// 模拟接口获取数据
|
||||||
|
setTimeout(() => {
|
||||||
|
options.occupation = [
|
||||||
|
{
|
||||||
|
label: "A",
|
||||||
|
value: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "B",
|
||||||
|
value: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "C",
|
||||||
|
value: 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "D",
|
||||||
|
value: 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "E",
|
||||||
|
value: 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "F",
|
||||||
|
value: 5
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}, 1500);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
127
src/modules/demo/views/crud/components/table/hidden.vue
Normal file
127
src/modules/demo/views/crud/components/table/hidden.vue
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
<template>
|
||||||
|
<div class="scope">
|
||||||
|
<div class="h">
|
||||||
|
<el-tag size="small" effect="dark">hidden</el-tag>
|
||||||
|
<span>隐藏/显示</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="c">
|
||||||
|
<el-button @click="open">预览</el-button>
|
||||||
|
<demo-code :files="['table/hidden.vue']" />
|
||||||
|
|
||||||
|
<!-- 自定义表格组件 -->
|
||||||
|
<cl-dialog v-model="visible" title="隐藏/显示" width="80%">
|
||||||
|
<cl-crud ref="Crud">
|
||||||
|
<!--配置一个 tab -->
|
||||||
|
<el-tabs v-model="active">
|
||||||
|
<el-tab-pane label="员工" name="user"></el-tab-pane>
|
||||||
|
<el-tab-pane label="企业" name="company"></el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
|
||||||
|
<cl-row>
|
||||||
|
<!-- 使用方法 showColumn 显示 -->
|
||||||
|
<el-button @click="showColumn('account')">显示账号</el-button>
|
||||||
|
|
||||||
|
<!-- 使用方法 hideColumn 隐藏 -->
|
||||||
|
<el-button @click="hideColumn('account')">隐藏账号</el-button>
|
||||||
|
</cl-row>
|
||||||
|
|
||||||
|
<cl-row>
|
||||||
|
<cl-table ref="Table"></cl-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, useTable } from "@cool-vue/crud";
|
||||||
|
import { computed, ref } from "vue";
|
||||||
|
import { useDict } from "/$/dict";
|
||||||
|
|
||||||
|
const { dict } = useDict();
|
||||||
|
|
||||||
|
// cl-crud 配置
|
||||||
|
const Crud = useCrud(
|
||||||
|
{
|
||||||
|
// 测试数据,移步到 cl-crud 例子查看
|
||||||
|
service: "test"
|
||||||
|
},
|
||||||
|
(app) => {
|
||||||
|
app.refresh();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const active = ref("user");
|
||||||
|
|
||||||
|
// cl-table 配置
|
||||||
|
const Table = useTable({
|
||||||
|
autoHeight: false,
|
||||||
|
contextMenu: ["refresh"],
|
||||||
|
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
label: "ID",
|
||||||
|
prop: "id",
|
||||||
|
minWidth: 140,
|
||||||
|
|
||||||
|
//【很重要】配置 hidden 参数,格式为 boolean 或者 Vue.ComputedRef<boolean>
|
||||||
|
hidden: computed(() => {
|
||||||
|
return active.value != "company";
|
||||||
|
})
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "账号",
|
||||||
|
prop: "account",
|
||||||
|
minWidth: 140,
|
||||||
|
hidden: true // 默认 false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "姓名",
|
||||||
|
prop: "name",
|
||||||
|
minWidth: 140
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "手机号",
|
||||||
|
prop: "phone",
|
||||||
|
minWidth: 140
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "工作",
|
||||||
|
prop: "occupation",
|
||||||
|
dict: dict.get("occupation"),
|
||||||
|
minWidth: 140
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "创建时间",
|
||||||
|
prop: "createTime",
|
||||||
|
minWidth: 160,
|
||||||
|
sortable: "desc"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
function hideColumn(prop: string) {
|
||||||
|
Table.value?.hideColumn(prop);
|
||||||
|
}
|
||||||
|
|
||||||
|
function showColumn(prop: string) {
|
||||||
|
Table.value?.showColumn(prop);
|
||||||
|
}
|
||||||
|
|
||||||
|
const visible = ref(false);
|
||||||
|
|
||||||
|
function open() {
|
||||||
|
visible.value = true;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
163
src/modules/demo/views/crud/components/table/op.vue
Normal file
163
src/modules/demo/views/crud/components/table/op.vue
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
<template>
|
||||||
|
<div class="scope">
|
||||||
|
<div class="h">
|
||||||
|
<el-tag size="small" effect="dark">op</el-tag>
|
||||||
|
<span>操作栏</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="c">
|
||||||
|
<el-button @click="open">预览</el-button>
|
||||||
|
<demo-code :files="['table/base.vue']" />
|
||||||
|
|
||||||
|
<!-- 自定义表格组件 -->
|
||||||
|
<cl-dialog v-model="visible" title="操作栏" width="80%">
|
||||||
|
<cl-crud ref="Crud">
|
||||||
|
<cl-row>
|
||||||
|
<cl-table ref="Table">
|
||||||
|
<!-- 插槽的渲染方式 #[component.name] -->
|
||||||
|
<template #slot-btns="{ scope }">
|
||||||
|
<el-button
|
||||||
|
@click="
|
||||||
|
() => {
|
||||||
|
ElMessage.info(scope.row.name);
|
||||||
|
}
|
||||||
|
"
|
||||||
|
>插槽按钮</el-button
|
||||||
|
>
|
||||||
|
</template>
|
||||||
|
</cl-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: 160,
|
||||||
|
sortable: "desc"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
//【很重要】type 必须是 op
|
||||||
|
type: "op",
|
||||||
|
|
||||||
|
width: 410, // 宽度
|
||||||
|
|
||||||
|
//【很重要】操作按钮配置,edit 和 info 必须搭配 cl-upsert 实现
|
||||||
|
// edit 编辑,预先获取 service 的 info 接口数据,并带入 cl-upsert 的表单值中
|
||||||
|
// info 详情,cl-upsert 内的组件全部传入 disabled 参数
|
||||||
|
// delete 删除,调用 service 的 delete 接口删除行数据
|
||||||
|
buttons: [
|
||||||
|
"edit",
|
||||||
|
"info",
|
||||||
|
"delete",
|
||||||
|
{
|
||||||
|
label: "自定义",
|
||||||
|
onClick({ scope }) {
|
||||||
|
// scope 行作用域 { row, column, $index, store }
|
||||||
|
ElMessage.info("点击了自定义按钮");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"slot-btns"
|
||||||
|
]
|
||||||
|
|
||||||
|
// 动态返回按钮配置
|
||||||
|
// buttons() {
|
||||||
|
// return ['edit', 'info', 'delete']
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
// cl-upsert 配置,详细移步到 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") // 使用字典数据
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
const visible = ref(false);
|
||||||
|
|
||||||
|
function open() {
|
||||||
|
visible.value = true;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
143
src/modules/demo/views/crud/components/table/search.vue
Normal file
143
src/modules/demo/views/crud/components/table/search.vue
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
<template>
|
||||||
|
<div class="scope">
|
||||||
|
<div class="h">
|
||||||
|
<el-tag size="small" effect="dark">search</el-tag>
|
||||||
|
<span>表头搜索</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="c">
|
||||||
|
<el-button @click="open">预览</el-button>
|
||||||
|
<demo-code :files="['table/search.vue']" />
|
||||||
|
|
||||||
|
<!-- 自定义表格组件 -->
|
||||||
|
<cl-dialog v-model="visible" title="表头搜索" width="80%">
|
||||||
|
<cl-crud ref="Crud">
|
||||||
|
<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, 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,
|
||||||
|
|
||||||
|
//【很重要】搜索参数配置
|
||||||
|
search: {
|
||||||
|
isInput: false, // 默认false,是否输入框模式
|
||||||
|
value: "", // 默认值
|
||||||
|
refreshOnChange: true, // 默认false,搜索时刷新数据,service 的 page 接口请求参数为 { page: 1, [绑定的prop]: 输入值 }
|
||||||
|
// 自定义渲染组件
|
||||||
|
component: {
|
||||||
|
name: "el-input",
|
||||||
|
props: {
|
||||||
|
placeholder: "搜索姓名"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "手机号",
|
||||||
|
prop: "phone",
|
||||||
|
minWidth: 140,
|
||||||
|
|
||||||
|
//【很重要】搜索参数配置
|
||||||
|
search: {
|
||||||
|
// 自定义渲染组件
|
||||||
|
component: {
|
||||||
|
name: "el-input",
|
||||||
|
props: {
|
||||||
|
placeholder: "搜索手机号",
|
||||||
|
|
||||||
|
// 自定义 change 事件
|
||||||
|
onChange(val) {
|
||||||
|
Crud.value?.refresh({
|
||||||
|
page: 1,
|
||||||
|
phone: val
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "工作",
|
||||||
|
prop: "occupation",
|
||||||
|
dict: dict.get("occupation"),
|
||||||
|
minWidth: 140,
|
||||||
|
|
||||||
|
//【很重要】搜索参数配置
|
||||||
|
search: {
|
||||||
|
refreshOnChange: false, // cl-select 自带 onChange 刷新,故不需要这个参数
|
||||||
|
component: {
|
||||||
|
name: "cl-select",
|
||||||
|
props: {
|
||||||
|
tree: true, // 树形方式选择
|
||||||
|
checkStrictly: true, // 任意层级都能点
|
||||||
|
options: dict.get("occupation") // 使用字典数据
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "创建时间",
|
||||||
|
prop: "createTime",
|
||||||
|
minWidth: 160,
|
||||||
|
sortable: "desc",
|
||||||
|
|
||||||
|
//【很重要】搜索参数配置
|
||||||
|
search: {
|
||||||
|
component: {
|
||||||
|
name: "cl-date-picker", // cl-date-picker 自带 onChange 刷新
|
||||||
|
props: {
|
||||||
|
type: "date",
|
||||||
|
valueFormat: "YYYY-MM-DD"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
const visible = ref(false);
|
||||||
|
|
||||||
|
function open() {
|
||||||
|
visible.value = true;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
110
src/modules/demo/views/crud/components/table/selection.vue
Normal file
110
src/modules/demo/views/crud/components/table/selection.vue
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
<template>
|
||||||
|
<div class="scope">
|
||||||
|
<div class="h">
|
||||||
|
<el-tag size="small" effect="dark">selection</el-tag>
|
||||||
|
<span>多选框数据</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="c">
|
||||||
|
<el-button @click="open">预览</el-button>
|
||||||
|
<demo-code :files="['table/selection.vue']" />
|
||||||
|
|
||||||
|
<!-- 自定义表格组件 -->
|
||||||
|
<cl-dialog v-model="visible" title="多选框数据" width="80%">
|
||||||
|
<cl-crud ref="Crud">
|
||||||
|
<cl-row>
|
||||||
|
<el-button @click="selectRow">选中2行</el-button>
|
||||||
|
<el-button :disabled="Table?.selection.length == 0" @click="clear"
|
||||||
|
>取消选择</el-button
|
||||||
|
>
|
||||||
|
</cl-row>
|
||||||
|
|
||||||
|
<cl-row>
|
||||||
|
<cl-table ref="Table" />
|
||||||
|
</cl-row>
|
||||||
|
|
||||||
|
<cl-row>
|
||||||
|
<el-text>已选 {{ Table?.selection.length }} 人</el-text>
|
||||||
|
<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, 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", "check"],
|
||||||
|
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
type: "selection"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "姓名",
|
||||||
|
prop: "name",
|
||||||
|
minWidth: 140
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "手机号",
|
||||||
|
prop: "phone",
|
||||||
|
minWidth: 140
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "工作",
|
||||||
|
prop: "occupation",
|
||||||
|
dict: dict.get("occupation"),
|
||||||
|
minWidth: 140
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "创建时间",
|
||||||
|
prop: "createTime",
|
||||||
|
minWidth: 160,
|
||||||
|
sortable: "desc"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
function selectRow() {
|
||||||
|
const [a, b] = Table.value?.data || [];
|
||||||
|
|
||||||
|
// 选中2个
|
||||||
|
Table.value?.toggleRowSelection(a);
|
||||||
|
Table.value?.toggleRowSelection(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
function clear() {
|
||||||
|
// 更多方法查看文档:https://element-plus.gitee.io/zh-CN/component/table.html#table-%E6%96%B9%E6%B3%95
|
||||||
|
Table.value?.clearSelection();
|
||||||
|
}
|
||||||
|
|
||||||
|
const visible = ref(false);
|
||||||
|
|
||||||
|
function open() {
|
||||||
|
visible.value = true;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
97
src/modules/demo/views/crud/components/table/slot.vue
Normal file
97
src/modules/demo/views/crud/components/table/slot.vue
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
<template>
|
||||||
|
<div class="scope">
|
||||||
|
<div class="h">
|
||||||
|
<el-tag size="small" effect="dark">slot</el-tag>
|
||||||
|
<span>插槽的使用</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="c">
|
||||||
|
<el-button @click="open">预览</el-button>
|
||||||
|
<demo-code :files="['table/slot.vue']" />
|
||||||
|
|
||||||
|
<!-- 自定义表格组件 -->
|
||||||
|
<cl-dialog v-model="visible" title="插槽的使用" width="80%">
|
||||||
|
<cl-crud ref="Crud">
|
||||||
|
<cl-row>
|
||||||
|
<cl-table ref="Table">
|
||||||
|
<!--【很重要】必须与 prop 名保持一致,格式:column-[prop] -->
|
||||||
|
<template #column-name="{ scope }">
|
||||||
|
<cl-row type="flex" align="middle">
|
||||||
|
<cl-avatar :size="36" :style="{ marginRight: '10px' }" />
|
||||||
|
<el-text>{{ scope.row.name }}</el-text>
|
||||||
|
</cl-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #column-phone="{ scope }"> 📱{{ scope.row.phone }} </template>
|
||||||
|
</cl-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, 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: [
|
||||||
|
{
|
||||||
|
headerAlign: "left",
|
||||||
|
label: "姓名",
|
||||||
|
prop: "name",
|
||||||
|
minWidth: 140
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "手机号",
|
||||||
|
prop: "phone",
|
||||||
|
minWidth: 140
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "工作",
|
||||||
|
prop: "occupation",
|
||||||
|
dict: dict.get("occupation"),
|
||||||
|
minWidth: 140
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "创建时间",
|
||||||
|
prop: "createTime",
|
||||||
|
minWidth: 160,
|
||||||
|
sortable: "desc"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
const visible = ref(false);
|
||||||
|
|
||||||
|
function open() {
|
||||||
|
visible.value = true;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
116
src/modules/demo/views/crud/components/table/span-method.vue
Normal file
116
src/modules/demo/views/crud/components/table/span-method.vue
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
<template>
|
||||||
|
<div class="scope">
|
||||||
|
<div class="h">
|
||||||
|
<el-tag size="small" effect="dark">span-method</el-tag>
|
||||||
|
<span>合并行或列</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="c">
|
||||||
|
<el-button @click="open">预览</el-button>
|
||||||
|
<demo-code :files="['table/span-method.vue']" />
|
||||||
|
|
||||||
|
<!-- 自定义表格组件 -->
|
||||||
|
<cl-dialog v-model="visible" title="合并行或列" width="80%">
|
||||||
|
<cl-crud ref="Crud">
|
||||||
|
<cl-row>
|
||||||
|
<cl-table ref="Table" :span-method="onSpanMethod" />
|
||||||
|
</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, useTable } from "@cool-vue/crud";
|
||||||
|
import { ref } from "vue";
|
||||||
|
import { useDict } from "/$/dict";
|
||||||
|
import { TableColumnCtx } 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: "wages",
|
||||||
|
minWidth: 140
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "手机号",
|
||||||
|
prop: "phone",
|
||||||
|
minWidth: 140
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "工作",
|
||||||
|
prop: "occupation",
|
||||||
|
dict: dict.get("occupation"),
|
||||||
|
minWidth: 140
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "创建时间",
|
||||||
|
prop: "createTime",
|
||||||
|
minWidth: 160,
|
||||||
|
sortable: "desc"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
interface SpanMethodProps {
|
||||||
|
row: any;
|
||||||
|
column: TableColumnCtx<any>;
|
||||||
|
rowIndex: number;
|
||||||
|
columnIndex: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onSpanMethod({ row, column, rowIndex, columnIndex }: SpanMethodProps) {
|
||||||
|
// 根据实际业务需求调整返回值 { rowspan, colspan }
|
||||||
|
if (columnIndex === 0) {
|
||||||
|
if (rowIndex % 2 === 0) {
|
||||||
|
return {
|
||||||
|
rowspan: 2,
|
||||||
|
colspan: 1
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
rowspan: 0,
|
||||||
|
colspan: 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const visible = ref(false);
|
||||||
|
|
||||||
|
function open() {
|
||||||
|
visible.value = true;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
95
src/modules/demo/views/crud/components/table/summary.vue
Normal file
95
src/modules/demo/views/crud/components/table/summary.vue
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
<template>
|
||||||
|
<div class="scope">
|
||||||
|
<div class="h">
|
||||||
|
<el-tag size="small" effect="dark">summary</el-tag>
|
||||||
|
<span>表尾合计行</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="c">
|
||||||
|
<el-button @click="open">预览</el-button>
|
||||||
|
<demo-code :files="['table/summary.vue']" />
|
||||||
|
|
||||||
|
<!-- 自定义表格组件 -->
|
||||||
|
<cl-dialog v-model="visible" title="表尾合计行" width="80%">
|
||||||
|
<cl-crud ref="Crud">
|
||||||
|
<cl-row>
|
||||||
|
<cl-table ref="Table" show-summary :summary-method="getSummaries" />
|
||||||
|
</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, 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: "wages",
|
||||||
|
minWidth: 140
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "手机号",
|
||||||
|
prop: "phone",
|
||||||
|
minWidth: 140
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "工作",
|
||||||
|
prop: "occupation",
|
||||||
|
dict: dict.get("occupation"),
|
||||||
|
minWidth: 140
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "创建时间",
|
||||||
|
prop: "createTime",
|
||||||
|
minWidth: 160,
|
||||||
|
sortable: "desc"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
function getSummaries() {
|
||||||
|
return ["合计", "$" + Table.value?.data.reduce((a, b) => a + b.wages, 0)];
|
||||||
|
}
|
||||||
|
|
||||||
|
const visible = ref(false);
|
||||||
|
|
||||||
|
function open() {
|
||||||
|
visible.value = true;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
133
src/modules/demo/views/crud/components/upsert/base.vue
Normal file
133
src/modules/demo/views/crud/components/upsert/base.vue
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
<template>
|
||||||
|
<div class="scope">
|
||||||
|
<div class="h">
|
||||||
|
<el-tag size="small" effect="dark">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: 160,
|
||||||
|
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>
|
||||||
210
src/modules/demo/views/crud/components/upsert/event.vue
Normal file
210
src/modules/demo/views/crud/components/upsert/event.vue
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
<template>
|
||||||
|
<div class="scope">
|
||||||
|
<div class="h">
|
||||||
|
<el-tag size="small" effect="dark">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: 160,
|
||||||
|
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.test.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>
|
||||||
200
src/modules/demo/views/crud/components/upsert/hook/index.vue
Normal file
200
src/modules/demo/views/crud/components/upsert/hook/index.vue
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
<template>
|
||||||
|
<div class="scope">
|
||||||
|
<div class="h">
|
||||||
|
<el-tag size="small" effect="dark">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: 160,
|
||||||
|
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>
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
import { registerFormHook } from "@cool-vue/crud";
|
||||||
|
|
||||||
|
// 注册 hook
|
||||||
|
registerFormHook("pca2", (value, { method, form, prop }) => {
|
||||||
|
if (method == "bind") {
|
||||||
|
return [form.province, form.city, form.district];
|
||||||
|
} else {
|
||||||
|
const [province, city, district] = value || [];
|
||||||
|
form.province = province;
|
||||||
|
form.city = city;
|
||||||
|
form.district = district;
|
||||||
|
form[prop] = undefined;
|
||||||
|
}
|
||||||
|
});
|
||||||
146
src/modules/demo/views/crud/components/upsert/mode.vue
Normal file
146
src/modules/demo/views/crud/components/upsert/mode.vue
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
<template>
|
||||||
|
<div class="scope">
|
||||||
|
<div class="h">
|
||||||
|
<el-tag size="small" effect="dark">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: 160,
|
||||||
|
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>
|
||||||
288
src/modules/demo/views/crud/index.vue
Normal file
288
src/modules/demo/views/crud/index.vue
Normal file
@ -0,0 +1,288 @@
|
|||||||
|
<template>
|
||||||
|
<div class="crud-demo">
|
||||||
|
<el-tabs type="card" v-model="active" @tab-change="onTabChange">
|
||||||
|
<el-tab-pane v-for="(a, ai) in list" :key="ai" :label="a.title" :name="a.title">
|
||||||
|
<div class="group" v-for="(b, bi) in a.children" :key="bi">
|
||||||
|
<p class="label"># {{ b.label }}</p>
|
||||||
|
|
||||||
|
<el-row :gutter="10">
|
||||||
|
<el-col
|
||||||
|
v-for="(c, ci) in b.children"
|
||||||
|
:key="ci"
|
||||||
|
:xs="24"
|
||||||
|
:sm="12"
|
||||||
|
:md="8"
|
||||||
|
:lg="6"
|
||||||
|
>
|
||||||
|
<component :is="c" />
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</div>
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup name="demo-crud">
|
||||||
|
import { ref, onActivated } from "vue";
|
||||||
|
|
||||||
|
import CrudBase from "./components/crud/base.vue";
|
||||||
|
import CrudAll from "./components/crud/all.vue";
|
||||||
|
import CrudDict from "./components/crud/dict.vue";
|
||||||
|
import CrudEvent from "./components/crud/event.vue";
|
||||||
|
import CrudService from "./components/crud/service.vue";
|
||||||
|
|
||||||
|
import FormOpen from "./components/form/open.vue";
|
||||||
|
import FormConfig from "./components/form/config.vue";
|
||||||
|
import FormRequired from "./components/form/required.vue";
|
||||||
|
import FormLayout from "./components/form/layout.vue";
|
||||||
|
import FormOptions from "./components/form/options.vue";
|
||||||
|
import FormHidden from "./components/form/hidden.vue";
|
||||||
|
import FormDisabled from "./components/form/disabled.vue";
|
||||||
|
import FormEvent from "./components/form/event.vue";
|
||||||
|
import FormGroup from "./components/form/group.vue";
|
||||||
|
import FormChildren from "./components/form/children.vue";
|
||||||
|
import FormCrud from "./components/form/crud.vue";
|
||||||
|
import FormRules from "./components/form/rules.vue";
|
||||||
|
import FormComponent from "./components/form/component/index.vue";
|
||||||
|
import FormPlugin from "./components/form/plugin/index.vue";
|
||||||
|
|
||||||
|
import TableBase from "./components/table/base.vue";
|
||||||
|
import TableOp from "./components/table/op.vue";
|
||||||
|
import TableSearch from "./components/table/search.vue";
|
||||||
|
import TableSelection from "./components/table/selection.vue";
|
||||||
|
import TableSlot from "./components/table/slot.vue";
|
||||||
|
import TableSummary from "./components/table/summary.vue";
|
||||||
|
import TableHidden from "./components/table/hidden.vue";
|
||||||
|
import TableChildren from "./components/table/children.vue";
|
||||||
|
import TableContextMenu from "./components/table/context-menu.vue";
|
||||||
|
import TableDict from "./components/table/dict.vue";
|
||||||
|
import TableSpanMethod from "./components/table/span-method.vue";
|
||||||
|
import TableColumnCustom from "./components/table/column-custom.vue";
|
||||||
|
import TableComponent from "./components/table/component/index.vue";
|
||||||
|
|
||||||
|
import UpsertBase from "./components/upsert/base.vue";
|
||||||
|
import UpsertEvent from "./components/upsert/event.vue";
|
||||||
|
import UpsertMode from "./components/upsert/mode.vue";
|
||||||
|
import UpsertHook from "./components/upsert/hook/index.vue";
|
||||||
|
|
||||||
|
import SearchBase from "./components/search/base.vue";
|
||||||
|
import SearchCustom from "./components/search/custom.vue";
|
||||||
|
|
||||||
|
import AdvSearchBase from "./components/adv-search/base.vue";
|
||||||
|
import AdvSearchCustom from "./components/adv-search/custom.vue";
|
||||||
|
|
||||||
|
import OtherTsx from "./components/other/tsx";
|
||||||
|
import OtherTips from "./components/other/tips.vue";
|
||||||
|
import { useCool } from "/@/cool";
|
||||||
|
|
||||||
|
const { route, router } = useCool();
|
||||||
|
|
||||||
|
const active = ref();
|
||||||
|
|
||||||
|
const list = [
|
||||||
|
{
|
||||||
|
title: "cl-crud",
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
label: "基础",
|
||||||
|
children: [CrudBase, CrudService, CrudDict, CrudEvent]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "高级",
|
||||||
|
children: [CrudAll]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "cl-table",
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
label: "基础",
|
||||||
|
children: [
|
||||||
|
TableBase,
|
||||||
|
TableOp,
|
||||||
|
TableSearch,
|
||||||
|
TableSelection,
|
||||||
|
TableSlot,
|
||||||
|
TableDict,
|
||||||
|
TableHidden,
|
||||||
|
TableContextMenu,
|
||||||
|
TableSummary,
|
||||||
|
TableSpanMethod,
|
||||||
|
TableChildren
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "高级",
|
||||||
|
children: [TableColumnCustom, TableComponent]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "cl-upsert",
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
label: "基础",
|
||||||
|
children: [UpsertBase, UpsertEvent, UpsertMode]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "高级",
|
||||||
|
children: [UpsertHook]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "cl-form",
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
label: "基础",
|
||||||
|
children: [
|
||||||
|
FormOpen,
|
||||||
|
FormConfig,
|
||||||
|
FormRequired,
|
||||||
|
FormLayout,
|
||||||
|
FormOptions,
|
||||||
|
FormHidden,
|
||||||
|
FormDisabled,
|
||||||
|
FormEvent,
|
||||||
|
FormGroup,
|
||||||
|
FormChildren,
|
||||||
|
FormCrud
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "高级",
|
||||||
|
children: [FormRules, FormComponent, FormPlugin]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "cl-search",
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
label: "基础",
|
||||||
|
children: [SearchBase, SearchCustom]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "cl-adv-search",
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
label: "基础",
|
||||||
|
children: [AdvSearchBase, AdvSearchCustom]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "other",
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
label: "高级",
|
||||||
|
children: [OtherTsx, OtherTips]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
function onTabChange(val: any) {
|
||||||
|
router.replace({
|
||||||
|
query: {
|
||||||
|
key: val
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onActivated(() => {
|
||||||
|
const { key } = route.query;
|
||||||
|
active.value = (key || "cl-crud") as string;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.crud-demo {
|
||||||
|
overflow-x: hidden;
|
||||||
|
background-color: var(--el-bg-color);
|
||||||
|
padding: 10px;
|
||||||
|
height: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
:deep(.scope) {
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
white-space: nowrap;
|
||||||
|
border: 1px solid var(--el-border-color-light);
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s;
|
||||||
|
|
||||||
|
.h {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
height: 30px;
|
||||||
|
padding: 10px;
|
||||||
|
font-size: 12px;
|
||||||
|
|
||||||
|
.el-tag {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.c {
|
||||||
|
height: 50px;
|
||||||
|
padding: 10px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
&._svg {
|
||||||
|
.cl-svg {
|
||||||
|
margin-right: 15px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
font-size: 13px;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
&:after {
|
||||||
|
content: "";
|
||||||
|
width: 100%;
|
||||||
|
height: 1px;
|
||||||
|
position: absolute;
|
||||||
|
bottom: -2px;
|
||||||
|
left: 0;
|
||||||
|
background-color: var(--color-primary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.f {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
height: 30px;
|
||||||
|
padding: 10px;
|
||||||
|
font-size: 12px;
|
||||||
|
|
||||||
|
.date {
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
box-shadow: 0px 0px 10px 1px var(--el-color-info-light-9);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.group {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
.label {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user