mirror of
https://github.com/cool-team-official/cool-admin-vue.git
synced 2026-03-13 15:21:02 +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 { virtual } from "./virtual";
|
||||
import { demo } from "./demo";
|
||||
|
||||
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) {
|
||||
const res = findFiles("./src/modules/");
|
||||
const res = findFiles("./src/");
|
||||
|
||||
return html.replace(
|
||||
"<body>",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "cool-admin",
|
||||
"version": "7.0.0",
|
||||
"version": "7.1.0",
|
||||
"scripts": {
|
||||
"dev": "vite --host",
|
||||
"build": "vite build",
|
||||
@ -9,7 +9,7 @@
|
||||
"lint:eslint": "eslint \"./src/**/*.{vue,ts,tsx}\" --fix"
|
||||
},
|
||||
"dependencies": {
|
||||
"@cool-vue/crud": "^7.1.3",
|
||||
"@cool-vue/crud": "^7.1.10",
|
||||
"@element-plus/icons-vue": "^2.1.0",
|
||||
"@vueuse/core": "^10.4.0",
|
||||
"@wangeditor/editor": "^5.1.23",
|
||||
@ -22,6 +22,7 @@
|
||||
"element-plus": "^2.4.3",
|
||||
"file-saver": "^2.0.5",
|
||||
"lodash-es": "^4.17.21",
|
||||
"marked": "^11.1.1",
|
||||
"mitt": "^3.0.1",
|
||||
"mockjs": "^1.1.0",
|
||||
"monaco-editor": "0.36.0",
|
||||
@ -53,6 +54,7 @@
|
||||
"eslint-config-prettier": "^9.0.0",
|
||||
"eslint-plugin-prettier": "^5.0.0",
|
||||
"eslint-plugin-vue": "^9.17.0",
|
||||
"glob": "^10.3.10",
|
||||
"lodash": "^4.17.21",
|
||||
"magic-string": "^0.30.3",
|
||||
"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;
|
||||
};
|
||||
|
||||
// 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
|
||||
declare namespace Render {
|
||||
type OpButton =
|
||||
@ -473,6 +440,26 @@ declare namespace ClForm {
|
||||
[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> {
|
||||
type?: "tabs";
|
||||
prop?: PropKey<T>;
|
||||
@ -501,14 +488,19 @@ declare namespace ClForm {
|
||||
xl: any;
|
||||
tag: string;
|
||||
};
|
||||
hook?: Hook.Form;
|
||||
group?: string;
|
||||
collapse?: boolean;
|
||||
value?: any;
|
||||
label?: string;
|
||||
renderLabel?: any;
|
||||
flex?: boolean;
|
||||
hidden?: (options: { scope: obj }) => boolean;
|
||||
hook?:
|
||||
| HookKey
|
||||
| {
|
||||
bind?: HookPipe | HookPipe[];
|
||||
submit?: HookPipe | HookPipe[];
|
||||
};
|
||||
hidden?: boolean | ((options: { scope: obj }) => boolean);
|
||||
prepend?: Render.Component;
|
||||
component?: Render.Component;
|
||||
append?: Render.Component;
|
||||
@ -632,16 +624,12 @@ declare namespace ClUpsert {
|
||||
}
|
||||
}
|
||||
|
||||
interface UpsertOptions {
|
||||
items: ClForm.Items;
|
||||
}
|
||||
|
||||
declare namespace ClAdvSearch {
|
||||
interface Config<T = any> {
|
||||
items?: ClForm.Item[];
|
||||
title?: string;
|
||||
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;
|
||||
}
|
||||
|
||||
@ -674,9 +662,8 @@ declare namespace ClSearch {
|
||||
declare namespace ClContextMenu {
|
||||
interface Item {
|
||||
label: string;
|
||||
icon?: string;
|
||||
prefixIcon?: string;
|
||||
suffixIcon?: string;
|
||||
prefixIcon?: any;
|
||||
suffixIcon?: any;
|
||||
ellipsis?: boolean;
|
||||
disabled?: boolean;
|
||||
hidden?: boolean;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@cool-vue/crud",
|
||||
"version": "7.1.3",
|
||||
"version": "7.1.10",
|
||||
"private": false,
|
||||
"main": "./dist/index.umd.min.js",
|
||||
"typings": "types/index.d.ts",
|
||||
|
||||
@ -1,16 +1,36 @@
|
||||
<template>
|
||||
<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-adv-search ref="AdvSearch"></cl-adv-search>
|
||||
</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>
|
||||
</template>
|
||||
|
||||
<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 {
|
||||
name?: string;
|
||||
@ -18,39 +38,119 @@ interface Data {
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
const visible = ref(true);
|
||||
|
||||
const Upsert = useUpsert<Data>({
|
||||
items: [
|
||||
{
|
||||
label: "xx",
|
||||
type: "tabs",
|
||||
props: {
|
||||
labels: [
|
||||
{
|
||||
label: "A",
|
||||
value: "A",
|
||||
icon: EditPen
|
||||
},
|
||||
{
|
||||
label: "B",
|
||||
value: "B"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
group: "B",
|
||||
prop: "age",
|
||||
component: {
|
||||
name: "el-input"
|
||||
}
|
||||
},
|
||||
{
|
||||
group: "B",
|
||||
prop: "证书",
|
||||
component: {
|
||||
name: "el-input"
|
||||
},
|
||||
hidden({ scope }) {
|
||||
return scope.age < 18;
|
||||
}
|
||||
},
|
||||
() => {
|
||||
return {
|
||||
group: "A",
|
||||
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>({
|
||||
contextMenu: [
|
||||
{
|
||||
label: "带图标",
|
||||
prefixIcon: EditPen
|
||||
},
|
||||
{
|
||||
label: "多层级",
|
||||
children: [
|
||||
{
|
||||
label: "A",
|
||||
children: [
|
||||
{
|
||||
label: "A-1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: "B"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
columns: [
|
||||
{
|
||||
label: "xx",
|
||||
prop: "a",
|
||||
label: "姓名",
|
||||
prop: "name",
|
||||
search: {
|
||||
component: {
|
||||
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>();
|
||||
|
||||
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>
|
||||
|
||||
<style scoped>
|
||||
.title {
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -78,6 +78,7 @@ export default defineComponent({
|
||||
function reset() {
|
||||
Form.value?.reset();
|
||||
emit("reset");
|
||||
search();
|
||||
}
|
||||
|
||||
// 清空数据
|
||||
@ -160,9 +161,9 @@ export default defineComponent({
|
||||
v-model={visible.value}
|
||||
direction="rtl"
|
||||
with-header={false}
|
||||
size={browser.isMini ? "100%" : props.size}>
|
||||
size={browser.isMini ? "100%" : config.size}>
|
||||
<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}>
|
||||
<Close />
|
||||
</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 { addClass, contains, removeClass } from "../../utils";
|
||||
import { useRefs } from "../../hooks";
|
||||
import { ElIcon } from "element-plus";
|
||||
import { ArrowRight } from "@element-plus/icons-vue";
|
||||
|
||||
const ClContextMenu = defineComponent({
|
||||
name: "cl-context-menu",
|
||||
@ -89,7 +91,7 @@ const ClContextMenu = defineComponent({
|
||||
|
||||
// 点击样式
|
||||
if (options.hover) {
|
||||
let d = options.hover === true ? {} : options.hover;
|
||||
const d = options.hover === true ? {} : options.hover;
|
||||
targetEl = event.target;
|
||||
|
||||
if (targetEl && isString(targetEl.className)) {
|
||||
@ -187,15 +189,22 @@ const ClContextMenu = defineComponent({
|
||||
.map((e, i) => {
|
||||
const id = `${pId}-${i}`;
|
||||
|
||||
if (!e.suffixIcon) {
|
||||
// 默认图标
|
||||
if (e.children) {
|
||||
e.suffixIcon = ArrowRight;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
class={{
|
||||
"is-active": ids.value.includes(id),
|
||||
"is-ellipsis": e.ellipsis,
|
||||
"is-ellipsis": e.ellipsis ?? true,
|
||||
"is-disabled": e.disabled
|
||||
}}>
|
||||
{/* 前缀图标 */}
|
||||
{e.prefixIcon && <i class={e.prefixIcon}></i>}
|
||||
{e.prefixIcon && <ElIcon>{h(toRaw(e.prefixIcon))}</ElIcon>}
|
||||
|
||||
{/* 标题 */}
|
||||
<span
|
||||
@ -206,9 +215,9 @@ const ClContextMenu = defineComponent({
|
||||
</span>
|
||||
|
||||
{/* 后缀图标 */}
|
||||
{e.suffixIcon && <i class={e.suffixIcon}></i>}
|
||||
{e.suffixIcon && <ElIcon>{h(toRaw(e.suffixIcon))}</ElIcon>}
|
||||
|
||||
{/* 子集*/}
|
||||
{/* 子集 */}
|
||||
{e.children &&
|
||||
e.showChildren &&
|
||||
deep(e.children, id, level + 1)}
|
||||
|
||||
@ -50,7 +50,12 @@ export default defineComponent({
|
||||
// 隐藏头部元素
|
||||
hideHeader: Boolean,
|
||||
// 关闭前
|
||||
beforeClose: Function
|
||||
beforeClose: Function,
|
||||
// 是否需要滚动条
|
||||
scrollbar: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
|
||||
emits: ["update:modelValue", "fullscreen-change"],
|
||||
@ -242,16 +247,28 @@ export default defineComponent({
|
||||
return renderHeader();
|
||||
},
|
||||
default() {
|
||||
return (
|
||||
<el-scrollbar
|
||||
class="cl-dialog__container"
|
||||
key={cacheKey.value}
|
||||
style={{ height: props.height }}>
|
||||
<div class="cl-dialog__default" style={{ padding: props.padding }}>
|
||||
const height = isFullscreen.value ? "100%" : props.height;
|
||||
|
||||
const style = {
|
||||
padding: props.padding,
|
||||
height
|
||||
};
|
||||
|
||||
function content() {
|
||||
return (
|
||||
<div class="cl-dialog__default" style={style} key={cacheKey.value}>
|
||||
{slots.default?.()}
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
if (props.scrollbar) {
|
||||
style.height = "auto";
|
||||
|
||||
return <el-scrollbar height={height}>{content()}</el-scrollbar>;
|
||||
} else {
|
||||
return content();
|
||||
}
|
||||
},
|
||||
footer() {
|
||||
const d = slots.footer?.();
|
||||
|
||||
@ -119,21 +119,32 @@ export default defineComponent({
|
||||
// 拷贝表单值
|
||||
const d = cloneDeep(form);
|
||||
|
||||
// 过滤隐藏的表单项
|
||||
config.items.forEach((e) => {
|
||||
if (e._hidden) {
|
||||
function deep(e: ClForm.Item) {
|
||||
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) {
|
||||
formHook.submit({
|
||||
...e,
|
||||
value: e.prop ? d[e.prop] : undefined,
|
||||
form: d
|
||||
});
|
||||
}
|
||||
deep(e);
|
||||
});
|
||||
|
||||
// 处理 "-" 多层级
|
||||
@ -152,7 +163,7 @@ export default defineComponent({
|
||||
let f: any = d[a];
|
||||
|
||||
// 设置默认值
|
||||
arr.forEach((e: any) => {
|
||||
arr.forEach((e) => {
|
||||
if (!f[e]) {
|
||||
f[e] = {};
|
||||
}
|
||||
@ -249,7 +260,7 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
// 设置表单数据
|
||||
config.items.map((e) => {
|
||||
config.items.forEach((e) => {
|
||||
function deep(e: ClForm.Item) {
|
||||
if (e.prop) {
|
||||
// 解析 prop
|
||||
@ -260,7 +271,7 @@ export default defineComponent({
|
||||
// prop 合并
|
||||
Tabs.mergeProp(e);
|
||||
|
||||
// 绑定值
|
||||
// hook 绑定值
|
||||
formHook.bind({
|
||||
...e,
|
||||
value: form[e.prop] !== undefined ? form[e.prop] : cloneDeep(e.value),
|
||||
@ -274,17 +285,17 @@ export default defineComponent({
|
||||
message: `${e.label}${dict.label.nonEmpty}`
|
||||
};
|
||||
}
|
||||
|
||||
// 子集
|
||||
if (e.children) {
|
||||
e.children.forEach(deep);
|
||||
}
|
||||
}
|
||||
|
||||
// 设置 tabs 默认值
|
||||
if (e.type == "tabs") {
|
||||
Tabs.set(e.value);
|
||||
}
|
||||
|
||||
// 子集
|
||||
if (e.children) {
|
||||
e.children.forEach(deep);
|
||||
}
|
||||
}
|
||||
|
||||
deep(e);
|
||||
@ -312,11 +323,19 @@ export default defineComponent({
|
||||
// 绑定表单数据
|
||||
function bindForm(data: any) {
|
||||
config.items.forEach((e) => {
|
||||
formHook.bind({
|
||||
...e,
|
||||
value: e.prop ? data[e.prop] : undefined,
|
||||
form: data
|
||||
});
|
||||
function deep(e: ClForm.Item) {
|
||||
formHook.bind({
|
||||
...e,
|
||||
value: e.prop ? data[e.prop] : undefined,
|
||||
form: data
|
||||
});
|
||||
|
||||
if (e.children) {
|
||||
e.children.forEach(deep);
|
||||
}
|
||||
}
|
||||
|
||||
deep(e);
|
||||
});
|
||||
|
||||
Object.assign(form, data);
|
||||
@ -344,105 +363,104 @@ export default defineComponent({
|
||||
const isLoaded = e.component && Tabs.isLoaded(e.group);
|
||||
|
||||
// 表单项
|
||||
const FormItem = isLoaded
|
||||
? h(
|
||||
<el-form-item
|
||||
class={{
|
||||
"no-label": !(e.renderLabel || e.label),
|
||||
"has-children": !!e.children
|
||||
}}
|
||||
data-group={e.group}
|
||||
data-prop={e.prop}
|
||||
label-width={props.inline ? "auto" : ""}
|
||||
label={e.label}
|
||||
prop={e.prop}
|
||||
rules={isDisabled ? null : e.rules}
|
||||
required={e._hidden ? false : e.required}
|
||||
v-show={inGroup && !e._hidden}
|
||||
/>,
|
||||
e.props,
|
||||
{
|
||||
label() {
|
||||
return e.renderLabel
|
||||
? renderNode(e.renderLabel, {
|
||||
scope: form,
|
||||
render: "slot",
|
||||
slots
|
||||
})
|
||||
: e.label;
|
||||
},
|
||||
default() {
|
||||
return (
|
||||
<div>
|
||||
<div class="cl-form-item">
|
||||
{["prepend", "component", "append"]
|
||||
.filter((k) => e[k])
|
||||
.map((name) => {
|
||||
const children = e.children && (
|
||||
<div class="cl-form-item__children">
|
||||
<el-row gutter={10}>
|
||||
{e.children.map(renderFormItem)}
|
||||
</el-row>
|
||||
</div>
|
||||
);
|
||||
const FormItem = h(
|
||||
<el-form-item
|
||||
class={{
|
||||
"no-label": !(e.renderLabel || e.label),
|
||||
"has-children": !!e.children
|
||||
}}
|
||||
key={e.prop}
|
||||
data-group={e.group || "-"}
|
||||
data-prop={e.prop || "-"}
|
||||
label-width={props.inline ? "auto" : ""}
|
||||
label={e.label}
|
||||
prop={e.prop}
|
||||
rules={isDisabled ? null : e.rules}
|
||||
required={e._hidden ? false : e.required}
|
||||
v-show={inGroup && !e._hidden}
|
||||
/>,
|
||||
e.props,
|
||||
{
|
||||
label() {
|
||||
return e.renderLabel
|
||||
? renderNode(e.renderLabel, {
|
||||
scope: form,
|
||||
render: "slot",
|
||||
slots
|
||||
})
|
||||
: e.label;
|
||||
},
|
||||
default() {
|
||||
return (
|
||||
<div>
|
||||
<div class="cl-form-item">
|
||||
{["prepend", "component", "append"]
|
||||
.filter((k) => e[k])
|
||||
.map((name) => {
|
||||
const children = e.children && (
|
||||
<div class="cl-form-item__children">
|
||||
<el-row gutter={10}>
|
||||
{e.children.map(renderFormItem)}
|
||||
</el-row>
|
||||
</div>
|
||||
);
|
||||
|
||||
const Item = renderNode(e[name], {
|
||||
item: e,
|
||||
prop: e.prop,
|
||||
scope: form,
|
||||
slots,
|
||||
children,
|
||||
_data: {
|
||||
isDisabled
|
||||
const Item = renderNode(e[name], {
|
||||
item: e,
|
||||
prop: e.prop,
|
||||
scope: form,
|
||||
slots,
|
||||
children,
|
||||
_data: {
|
||||
isDisabled
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<div
|
||||
v-show={!e.collapse}
|
||||
class={[
|
||||
`cl-form-item__${name}`,
|
||||
{
|
||||
flex1: e.flex !== false
|
||||
}
|
||||
});
|
||||
]}
|
||||
style={e[name].style}>
|
||||
{Item}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
return (
|
||||
<div
|
||||
v-show={!e.collapse}
|
||||
class={[
|
||||
`cl-form-item__${name}`,
|
||||
{
|
||||
flex1: e.flex !== false
|
||||
}
|
||||
]}
|
||||
style={e[name].style}>
|
||||
{Item}
|
||||
</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>
|
||||
)}
|
||||
{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>
|
||||
);
|
||||
}
|
||||
}
|
||||
)
|
||||
: null;
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// 行内
|
||||
if (props.inline) {
|
||||
return FormItem;
|
||||
}
|
||||
|
||||
return (
|
||||
<el-col key={e.prop} span={e.span || style.form.span} {...e.col}>
|
||||
// 是否行内
|
||||
const Item = props.inline ? (
|
||||
FormItem
|
||||
) : (
|
||||
<el-col span={e.span || style.form.span} {...e.col} v-show={inGroup && !e._hidden}>
|
||||
{FormItem}
|
||||
</el-col>
|
||||
);
|
||||
|
||||
return isLoaded ? Item : null;
|
||||
}
|
||||
|
||||
// 渲染表单
|
||||
|
||||
@ -87,8 +87,20 @@ export default defineComponent({
|
||||
|
||||
// 重置
|
||||
function reset() {
|
||||
const d: any = {};
|
||||
|
||||
config.items?.map((e) => {
|
||||
d[e.prop!] = undefined;
|
||||
});
|
||||
|
||||
// 重置表单
|
||||
Form.value?.reset();
|
||||
emit("reset");
|
||||
|
||||
// 列表刷新
|
||||
crud.refresh(d);
|
||||
|
||||
// 重置事件
|
||||
emit("reset", d);
|
||||
}
|
||||
|
||||
expose({
|
||||
@ -123,6 +135,7 @@ export default defineComponent({
|
||||
append() {
|
||||
return (
|
||||
<el-form-item>
|
||||
{/* 搜索按钮 */}
|
||||
<el-button
|
||||
type="primary"
|
||||
loading={loading.value}
|
||||
@ -132,11 +145,16 @@ export default defineComponent({
|
||||
}}>
|
||||
{crud.dict.label.search}
|
||||
</el-button>
|
||||
|
||||
{/* 重置按钮 */}
|
||||
{config.resetBtn && (
|
||||
<el-button size={style.size} onClick={reset}>
|
||||
{crud.dict.label.reset}
|
||||
</el-button>
|
||||
)}
|
||||
|
||||
{/* 自定义按钮 */}
|
||||
{slots?.buttons?.(Form.value?.form)}
|
||||
</el-form-item>
|
||||
);
|
||||
},
|
||||
|
||||
@ -371,6 +371,7 @@
|
||||
ul {
|
||||
display: inline-flex;
|
||||
white-space: nowrap;
|
||||
margin: 0;
|
||||
|
||||
li {
|
||||
display: inline-flex;
|
||||
@ -397,7 +398,9 @@
|
||||
position: absolute;
|
||||
bottom: -1px;
|
||||
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);
|
||||
}
|
||||
|
||||
@ -514,14 +517,7 @@
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
&__container {
|
||||
& > .el-scrollbar__wrap > .el-scrollbar__view {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
&__default {
|
||||
height: 100%;
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
|
||||
if (isArray(value)) {
|
||||
return isEmpty(value) ? undefined : 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;
|
||||
}
|
||||
|
||||
|
||||
@ -25,6 +25,10 @@ declare const _default: import("vue").DefineComponent<{
|
||||
};
|
||||
hideHeader: BooleanConstructor;
|
||||
beforeClose: FunctionConstructor;
|
||||
scrollbar: {
|
||||
type: BooleanConstructor;
|
||||
default: boolean;
|
||||
};
|
||||
}, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
||||
[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<{
|
||||
@ -54,6 +58,10 @@ declare const _default: import("vue").DefineComponent<{
|
||||
};
|
||||
hideHeader: BooleanConstructor;
|
||||
beforeClose: FunctionConstructor;
|
||||
scrollbar: {
|
||||
type: BooleanConstructor;
|
||||
default: boolean;
|
||||
};
|
||||
}>> & {
|
||||
"onUpdate:modelValue"?: ((...args: any[]) => any) | undefined;
|
||||
"onFullscreen-change"?: ((...args: any[]) => any) | undefined;
|
||||
@ -66,5 +74,6 @@ declare const _default: import("vue").DefineComponent<{
|
||||
controls: unknown[];
|
||||
fullscreen: boolean;
|
||||
modelValue: boolean;
|
||||
scrollbar: boolean;
|
||||
}, {}>;
|
||||
export default _default;
|
||||
|
||||
@ -56,17 +56,17 @@ export declare function useForm(): {
|
||||
xl: any;
|
||||
tag: string;
|
||||
} | undefined;
|
||||
hook?: string | {
|
||||
bind?: Hook.FormPipe | Hook.FormPipe[] | undefined;
|
||||
submit?: Hook.FormPipe | Hook.FormPipe[] | undefined;
|
||||
} | undefined;
|
||||
group?: string | undefined;
|
||||
collapse?: boolean | undefined;
|
||||
value?: any;
|
||||
label?: string | undefined;
|
||||
renderLabel?: any;
|
||||
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;
|
||||
}) => boolean) | undefined;
|
||||
prepend?: {
|
||||
|
||||
@ -143,9 +143,8 @@ export declare function useTable(props: any): {
|
||||
contextMenu: ("info" | "update" | "delete" | "edit" | "refresh" | {
|
||||
[x: string]: any;
|
||||
label: string;
|
||||
icon?: string | undefined;
|
||||
prefixIcon?: string | undefined;
|
||||
suffixIcon?: string | undefined;
|
||||
prefixIcon?: any;
|
||||
suffixIcon?: any;
|
||||
ellipsis?: boolean | undefined;
|
||||
disabled?: 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" />
|
||||
export declare const format: {
|
||||
[key: string]: Hook.fn;
|
||||
[key: string]: ClForm.HookFn;
|
||||
};
|
||||
declare const formHook: {
|
||||
bind(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;
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
export const proxy = {
|
||||
"/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,
|
||||
rewrite: (path: string) => path.replace(/^\/dev/, "")
|
||||
},
|
||||
|
||||
@ -1,13 +1,16 @@
|
||||
import { App } from "vue";
|
||||
import { isFunction, orderBy } from "lodash-es";
|
||||
import { isFunction, orderBy, chain } from "lodash-es";
|
||||
import { filename } from "../utils";
|
||||
import { module } from "../module";
|
||||
import { hmr } from "../hook";
|
||||
|
||||
// 扫描文件
|
||||
const files: any = import.meta.glob("/src/modules/*/{config.ts,service/**,directives/**}", {
|
||||
eager: true
|
||||
});
|
||||
const files: any = import.meta.glob(
|
||||
"/src/{modules,plugins}/*/{config.ts,service/**,directives/**}",
|
||||
{
|
||||
eager: true
|
||||
}
|
||||
);
|
||||
|
||||
// 模块列表
|
||||
module.list = hmr.getData("modules", []);
|
||||
@ -15,7 +18,7 @@ module.list = hmr.getData("modules", []);
|
||||
// 解析
|
||||
for (const i in files) {
|
||||
// 分割
|
||||
const [, , , name, action] = i.split("/");
|
||||
const [, , type, name, action] = i.split("/");
|
||||
|
||||
// 文件名
|
||||
const fname = filename(i);
|
||||
@ -29,6 +32,7 @@ for (const i in files) {
|
||||
// 数据
|
||||
const d = m || {
|
||||
name,
|
||||
type,
|
||||
value: null,
|
||||
services: [],
|
||||
directives: []
|
||||
|
||||
@ -13,6 +13,9 @@ const module = {
|
||||
get(name: string): Module {
|
||||
return this.list.find((e) => e.name == name)!;
|
||||
},
|
||||
config(name: string) {
|
||||
return this.get(name).options || {};
|
||||
},
|
||||
add(data: Module) {
|
||||
this.list.push(data);
|
||||
},
|
||||
|
||||
@ -6,6 +6,9 @@ import { useBase } from "/$/base";
|
||||
import { Loading } from "../utils";
|
||||
import { config } from "/@/config";
|
||||
|
||||
// 基本路径
|
||||
const baseUrl = import.meta.env.BASE_URL;
|
||||
|
||||
// 扫描文件
|
||||
const files = import.meta.glob(["/src/modules/*/{views,pages}/**/*", "!**/components"]);
|
||||
|
||||
@ -26,7 +29,10 @@ const routes: RouteRecordRaw[] = [
|
||||
|
||||
// 创建路由器
|
||||
const router = createRouter({
|
||||
history: config.app.router.mode == "history" ? createWebHistory() : createWebHashHistory(),
|
||||
history:
|
||||
config.app.router.mode == "history"
|
||||
? createWebHistory(baseUrl)
|
||||
: createWebHashHistory(baseUrl),
|
||||
routes
|
||||
}) 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 "./index.scss";
|
||||
import { defineComponent, type PropType } from "vue";
|
||||
import { UserFilled } from "@element-plus/icons-vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "cl-avatar",
|
||||
@ -7,7 +7,10 @@ export default defineComponent({
|
||||
props: {
|
||||
modelValue: String,
|
||||
src: String,
|
||||
icon: null,
|
||||
icon: {
|
||||
type: null,
|
||||
default: UserFilled
|
||||
},
|
||||
size: [String, Number] as PropType<"large" | "default" | "small" | number>,
|
||||
shape: String as PropType<"circle" | "square">,
|
||||
fit: {
|
||||
@ -19,18 +22,16 @@ export default defineComponent({
|
||||
setup(props) {
|
||||
return () => {
|
||||
return (
|
||||
<div class="cl-avatar">
|
||||
<el-avatar
|
||||
style={{
|
||||
height: props.size + "px",
|
||||
width: props.size + "px"
|
||||
}}
|
||||
{...{
|
||||
...props,
|
||||
src: props.modelValue || props.src
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<el-avatar
|
||||
style={{
|
||||
height: props.size + "px",
|
||||
width: props.size + "px"
|
||||
}}
|
||||
{...{
|
||||
...props,
|
||||
src: props.modelValue || props.src
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@ -71,13 +71,13 @@ function onCheckChange(_: any, { checkedKeys }: any) {
|
||||
|
||||
// 监听过滤
|
||||
watch(keyword, (val: string) => {
|
||||
Tree.value.filter(val);
|
||||
Tree.value?.filter(val);
|
||||
});
|
||||
|
||||
useUpsert({
|
||||
async onOpened() {
|
||||
await refresh();
|
||||
Tree.value.setCheckedKeys(props.modelValue || []);
|
||||
Tree.value?.setCheckedKeys(props.modelValue || []);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
@ -18,7 +18,7 @@
|
||||
preview-teleported
|
||||
>
|
||||
<template #error>
|
||||
<div class="image-slot">
|
||||
<div class="cl-image__slot">
|
||||
<el-icon :size="20"><picture-filled /></el-icon>
|
||||
</div>
|
||||
</template>
|
||||
@ -27,7 +27,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { PropType, computed, defineComponent } from "vue";
|
||||
import { type PropType, computed, defineComponent } from "vue";
|
||||
import { isArray, isNumber, isString } from "lodash-es";
|
||||
import { PictureFilled } from "@element-plus/icons-vue";
|
||||
import { parsePx } from "/@/cool/utils";
|
||||
@ -91,20 +91,13 @@ export default defineComponent({
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.cl-image {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.el-image {
|
||||
display: block;
|
||||
|
||||
.image-slot {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
background-color: #f7f7f7;
|
||||
border-radius: 4px;
|
||||
}
|
||||
&__slot {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
background-color: #f7f7f7;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -73,7 +73,7 @@ watch(keyword, (val: string) => {
|
||||
useUpsert({
|
||||
async onOpened() {
|
||||
await refresh();
|
||||
Tree.value.setCheckedKeys(
|
||||
Tree.value?.setCheckedKeys(
|
||||
(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 { ClViewGroup, useViewGroup } from "/$/base";
|
||||
import { service } from "/@/cool";
|
||||
import Node from "element-plus/es/components/tree/src/model/node";
|
||||
import ClAvatar from "../components/avatar/index";
|
||||
import { type ClViewGroup, useViewGroup } from "/@/plugins/view";
|
||||
|
||||
export function useDeptViewGroup(options: DeepPartial<ClViewGroup.Options>) {
|
||||
const { ViewGroup } = useViewGroup({
|
||||
|
||||
@ -1,2 +1 @@
|
||||
export * from "../components/view/group/hook";
|
||||
export * from "./dept";
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
|
||||
<el-form label-width="100px" :model="form" :disabled="loading">
|
||||
<el-form-item label="头像">
|
||||
<cl-upload is-space v-model="form.headImg" />
|
||||
<cl-upload v-model="form.headImg" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="昵称">
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
import { useForm } from "@cool-vue/crud";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { isEmpty } from "lodash-es";
|
||||
import { PropType } from "vue";
|
||||
import { type PropType } from "vue";
|
||||
import { useCool } from "/@/cool";
|
||||
import dayjs from "dayjs";
|
||||
import { Download } from "@element-plus/icons-vue";
|
||||
@ -30,6 +30,9 @@ function open() {
|
||||
props: {
|
||||
labelPosition: "top"
|
||||
},
|
||||
op: {
|
||||
saveButtonText: "导出"
|
||||
},
|
||||
items: [
|
||||
{
|
||||
label: "选择菜单",
|
||||
|
||||
@ -105,8 +105,8 @@ import { deepTree } from "/@/cool/utils";
|
||||
import { useStore } from "/$/base/store";
|
||||
import MenuImp from "./components/imp.vue";
|
||||
import MenuExp from "./components/exp.vue";
|
||||
import AutoMenu from "/$/magic/components/auto-menu/index.vue";
|
||||
import AutoPerms from "/$/magic/components/auto-perms/index.vue";
|
||||
import AutoMenu from "/$/helper/components/auto-menu/index.vue";
|
||||
import AutoPerms from "/$/helper/components/auto-perms/index.vue";
|
||||
|
||||
const { service, mitt } = useCool();
|
||||
const { menu } = useStore();
|
||||
@ -401,5 +401,5 @@ function addPermission({ id }: any) {
|
||||
});
|
||||
}
|
||||
|
||||
mitt.on("magic.createMenu", refresh);
|
||||
mitt.on("helper.createMenu", refresh);
|
||||
</script>
|
||||
|
||||
@ -19,19 +19,29 @@
|
||||
|
||||
<cl-upsert ref="Upsert">
|
||||
<template #slot-relevance="{ scope }">
|
||||
<el-switch
|
||||
v-model="scope.relevance"
|
||||
:active-value="1"
|
||||
:inactive-value="0"
|
||||
@change="onRelevanceChange"
|
||||
/>
|
||||
<span
|
||||
:style="{
|
||||
marginLeft: '10px',
|
||||
fontSize: '12px'
|
||||
}"
|
||||
>是否关联上下级</span
|
||||
>
|
||||
<div>
|
||||
<el-row>
|
||||
<el-switch
|
||||
v-model="scope.relevance"
|
||||
:active-value="1"
|
||||
:inactive-value="0"
|
||||
/>
|
||||
|
||||
<span
|
||||
:style="{
|
||||
marginLeft: '10px',
|
||||
fontSize: '12px'
|
||||
}"
|
||||
>
|
||||
是否关联上下级
|
||||
</span>
|
||||
</el-row>
|
||||
|
||||
<cl-dept-check
|
||||
v-model="scope.departmentIdList"
|
||||
:check-strictly="scope.relevance == 0"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</cl-upsert>
|
||||
</cl-crud>
|
||||
@ -96,30 +106,20 @@ const Upsert = useUpsert({
|
||||
{
|
||||
label: "数据权限",
|
||||
prop: "relevance",
|
||||
flex: false,
|
||||
component: {
|
||||
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) {
|
||||
onRelevanceChange(data.relevance || 0);
|
||||
}
|
||||
plugins: [setFocus()]
|
||||
});
|
||||
|
||||
// cl-table
|
||||
@ -164,11 +164,4 @@ const Table = useTable({
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
// 是否关联上下级
|
||||
function onRelevanceChange(val: number | string | boolean) {
|
||||
Upsert.value?.setProps("departmentIdList", {
|
||||
checkStrictly: val == 0
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -81,7 +81,8 @@ import { deepTree, revDeepTree } from "/@/cool/utils";
|
||||
import { isArray } from "lodash-es";
|
||||
import { ContextMenu, setFocus, useForm } from "@cool-vue/crud";
|
||||
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({
|
||||
drag: {
|
||||
@ -97,9 +98,8 @@ const props = defineProps({
|
||||
const emit = defineEmits(["refresh", "user-add"]);
|
||||
|
||||
const { service, browser } = useCool();
|
||||
const { ViewGroup } = useViewGroup();
|
||||
|
||||
const Form = useForm();
|
||||
const { ViewGroup } = useViewGroup();
|
||||
|
||||
// 树形列表
|
||||
const list = ref<Eps.BaseSysDepartmentEntity[]>([]);
|
||||
|
||||
@ -59,9 +59,9 @@
|
||||
<script lang="ts" name="sys-user" setup>
|
||||
import { useTable, useUpsert, useCrud } from "@cool-vue/crud";
|
||||
import { useCool } from "/@/cool";
|
||||
import { useViewGroup } from "../../hooks";
|
||||
import DeptList from "./components/dept-list.vue";
|
||||
import UserMove from "./components/user-move.vue";
|
||||
import { useViewGroup } from "/@/plugins/view";
|
||||
|
||||
const { service, refs, setRefs } = useCool();
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="cl-chat__wrap">
|
||||
<el-badge :value="unCount">
|
||||
<el-badge :value="unCount" :hidden="!unCount">
|
||||
<div class="cl-chat__icon" @click="open">
|
||||
<cl-svg name="icon-notice" :size="16" />
|
||||
</div>
|
||||
@ -14,6 +14,7 @@
|
||||
width="1200px"
|
||||
padding="0"
|
||||
keep-alive
|
||||
:scrollbar="false"
|
||||
:close-on-click-modal="false"
|
||||
close-on-press-escape
|
||||
:controls="['slot-expand', 'cl-flex1', 'fullscreen', 'close']"
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { ModuleConfig } from "/@/cool";
|
||||
import { addDeclare } from "/$/extend";
|
||||
import { CodeDeclare } from "./dict";
|
||||
import { addDeclare } from "/@/plugins/editor-monaco";
|
||||
|
||||
export default (): ModuleConfig => {
|
||||
return {
|
||||
|
||||
@ -54,9 +54,9 @@
|
||||
import { useForm } from "@cool-vue/crud";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
import { reactive, ref } from "vue";
|
||||
import { useViewGroup } from "/$/base";
|
||||
import { useCool } from "/@/cool";
|
||||
import { CodeSnippets, Status } from "../dict";
|
||||
import { useViewGroup } from "/@/plugins/view";
|
||||
|
||||
const { service } = useCool();
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="scope">
|
||||
<div class="h">
|
||||
<span>cl-context-menu</span>
|
||||
<el-tag size="small" effect="dark">cl-context-menu</el-tag>
|
||||
右键菜单
|
||||
</div>
|
||||
<div class="c">
|
||||
@ -17,7 +17,7 @@
|
||||
import { ContextMenu } from "@cool-vue/crud";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
function open(e: any) {
|
||||
function open(e: MouseEvent) {
|
||||
ContextMenu.open(e, {
|
||||
list: [
|
||||
{
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="scope">
|
||||
<div class="h">
|
||||
<span>v-copy</span>
|
||||
<el-tag size="small" effect="dark">v-copy</el-tag>
|
||||
复制到剪贴板
|
||||
</div>
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="scope">
|
||||
<div class="h">
|
||||
<span>cl-crud</span>
|
||||
<el-tag size="small" effect="dark">cl-crud</el-tag>
|
||||
增删改查,超快的
|
||||
</div>
|
||||
<div class="c">
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="scope">
|
||||
<div class="h">
|
||||
<span>design-page</span>
|
||||
<el-tag size="small" effect="dark">design-page</el-tag>
|
||||
页面设计
|
||||
</div>
|
||||
<div class="c">
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="scope">
|
||||
<div class="h">
|
||||
<span>cl-editor</span>
|
||||
<el-tag size="small" effect="dark">cl-editor</el-tag>
|
||||
编辑器
|
||||
</div>
|
||||
<div class="c">
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="scope">
|
||||
<div class="h">
|
||||
<span>file</span>
|
||||
<el-tag size="small" effect="dark">file</el-tag>
|
||||
文件管理
|
||||
</div>
|
||||
<div class="c">
|
||||
|
||||
@ -1,18 +1,14 @@
|
||||
<template>
|
||||
<div class="scope">
|
||||
<div class="h">
|
||||
<span>cl-form</span>
|
||||
<el-tag size="small" effect="dark">cl-form</el-tag>
|
||||
很强的表单
|
||||
</div>
|
||||
<div class="c">
|
||||
<form-btn />
|
||||
<router-link to="/demo/crud?key=cl-form">传送门</router-link>
|
||||
</div>
|
||||
<div class="f">
|
||||
<span class="date">2019/01/01</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import FormBtn from "./form-btn.vue";
|
||||
</script>
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="scope">
|
||||
<div class="h">
|
||||
<span>cl-svg</span>
|
||||
<el-tag size="small" effect="dark">cl-svg</el-tag>
|
||||
svg图片库
|
||||
</div>
|
||||
<div class="c _svg">
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="scope">
|
||||
<div class="h">
|
||||
<span>cl-upload</span>
|
||||
<el-tag size="small" effect="dark">cl-upload</el-tag>
|
||||
图片上传
|
||||
</div>
|
||||
<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>
|
||||
<cl-crud ref="Crud">
|
||||
<cl-row>
|
||||
<!-- 刷新按钮 -->
|
||||
<cl-refresh-btn />
|
||||
<div class="scope">
|
||||
<div class="h">
|
||||
<el-tag size="small" effect="dark">all</el-tag>
|
||||
<span>完整示例</span>
|
||||
</div>
|
||||
|
||||
<!-- 新增按钮 -->
|
||||
<cl-add-btn />
|
||||
<div class="c">
|
||||
<el-button @click="open">预览</el-button>
|
||||
<demo-code :files="['crud/all.vue']" />
|
||||
|
||||
<!-- 批量删除按钮 -->
|
||||
<cl-multi-delete-btn />
|
||||
<cl-dialog v-model="visible" title="完整示例" width="80%">
|
||||
<cl-crud ref="Crud">
|
||||
<cl-row>
|
||||
<!-- 刷新按钮 -->
|
||||
<cl-refresh-btn />
|
||||
|
||||
<!-- 自定义表单 -->
|
||||
<form-btn />
|
||||
<!-- 新增按钮 -->
|
||||
<cl-add-btn />
|
||||
|
||||
<!-- 筛选 -->
|
||||
<cl-filter label="状态筛选">
|
||||
<!-- 配置props,选择后会自动过滤列表 -->
|
||||
<cl-select :options="options.status" prop="status" :width="120" />
|
||||
</cl-filter>
|
||||
<!-- 批量删除按钮 -->
|
||||
<cl-multi-delete-btn />
|
||||
|
||||
<!-- 字典 -->
|
||||
<cl-filter label="工作(字典)">
|
||||
<cl-select :options="dict.get('occupation')" prop="occupation" :width="120" />
|
||||
</cl-filter>
|
||||
<!-- 筛选 -->
|
||||
<cl-filter label="状态筛选">
|
||||
<!-- 配置props,选择后会自动过滤列表 -->
|
||||
<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-import-btn template="/用户导入模版.xlsx" />
|
||||
<cl-flex1 />
|
||||
|
||||
<!-- 导出 -->
|
||||
<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-row>
|
||||
<!-- 关键字搜索 -->
|
||||
<cl-search-key placeholder="搜索姓名、手机号" :width="250" />
|
||||
|
||||
<cl-row>
|
||||
<!-- 表格 -->
|
||||
<cl-table ref="Table" show-summary :summary-method="onSummaryMethod">
|
||||
<!-- 展开信息 -->
|
||||
<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>
|
||||
<!-- 高级搜索按钮 -->
|
||||
<cl-adv-btn />
|
||||
</cl-row>
|
||||
|
||||
<el-descriptions-item label="姓名">
|
||||
{{ scope.row.name }}
|
||||
</el-descriptions-item>
|
||||
<cl-row>
|
||||
<!-- 表格 -->
|
||||
<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="存款">
|
||||
{{ scope.row.wages }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="姓名">
|
||||
{{ scope.row.name }}
|
||||
</el-descriptions-item>
|
||||
|
||||
<el-descriptions-item label="出生年月">
|
||||
{{ scope.row.createTime }}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
</template>
|
||||
<el-descriptions-item label="存款">
|
||||
{{ scope.row.wages }}
|
||||
</el-descriptions-item>
|
||||
|
||||
<!-- 自定义列 -->
|
||||
<template #column-wages="{ scope }">
|
||||
<span>{{ scope.row.wages }}🤑</span>
|
||||
</template>
|
||||
</cl-table>
|
||||
</cl-row>
|
||||
<el-descriptions-item label="出生年月">
|
||||
{{ scope.row.createTime }}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<cl-row>
|
||||
<cl-flex1 />
|
||||
<!-- 自定义列 -->
|
||||
<template #column-wages="{ scope }">
|
||||
<span>{{ scope.row.wages }}🤑</span>
|
||||
</template>
|
||||
</cl-table>
|
||||
</cl-row>
|
||||
|
||||
<!-- 分页 -->
|
||||
<cl-pagination />
|
||||
</cl-row>
|
||||
<cl-row>
|
||||
<cl-flex1 />
|
||||
|
||||
<!-- 新增、编辑 -->
|
||||
<cl-upsert ref="Upsert" />
|
||||
<!-- 分页 -->
|
||||
<cl-pagination />
|
||||
</cl-row>
|
||||
|
||||
<!-- 高级搜索 -->
|
||||
<cl-adv-search ref="AdvSearch" />
|
||||
</cl-crud>
|
||||
<!-- 新增、编辑 -->
|
||||
<cl-upsert ref="Upsert" />
|
||||
|
||||
<!-- 高级搜索 -->
|
||||
<cl-adv-search ref="AdvSearch" />
|
||||
</cl-crud>
|
||||
</cl-dialog>
|
||||
</div>
|
||||
|
||||
<div class="f">
|
||||
<span class="date">2024-01-01</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="tsx" name="demo-crud" setup>
|
||||
import { useCrud, useUpsert, useTable, useAdvSearch, setFocus, useSearch } from "@cool-vue/crud";
|
||||
import { useDict } from "/$/dict";
|
||||
import { reactive } from "vue";
|
||||
import { reactive, ref } from "vue";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
import { useCool } from "/@/cool";
|
||||
import FormBtn from "../components/form-btn.vue";
|
||||
import SelectUser from "../components/select-user.vue";
|
||||
|
||||
// 基础
|
||||
const { service, refs, setRefs } = useCool();
|
||||
@ -140,6 +165,7 @@ const Crud = useCrud(
|
||||
(app) => {
|
||||
// Crud 加载完,默认刷新一次
|
||||
app.refresh({
|
||||
size: 10
|
||||
// status: 1 // 带额外参数的请求
|
||||
});
|
||||
}
|
||||
@ -153,11 +179,6 @@ function refresh(params?: any) {
|
||||
// 新增、编辑
|
||||
// 插入类型 <Eps.UserInfoEntity>,prop 和 data 会有提示
|
||||
const Upsert = useUpsert<Eps.UserInfoEntity>({
|
||||
dialog: {
|
||||
height: "600px", // 固定高
|
||||
width: "1000px" // 固定宽
|
||||
},
|
||||
|
||||
items: [
|
||||
// 分组
|
||||
{
|
||||
@ -169,10 +190,6 @@ const Upsert = useUpsert<Eps.UserInfoEntity>({
|
||||
label: "基础信息",
|
||||
value: "base"
|
||||
},
|
||||
{
|
||||
label: "选择用户",
|
||||
value: "select"
|
||||
},
|
||||
{
|
||||
label: "其他配置",
|
||||
value: "other"
|
||||
@ -214,8 +231,8 @@ const Upsert = useUpsert<Eps.UserInfoEntity>({
|
||||
};
|
||||
},
|
||||
{
|
||||
prop: "user",
|
||||
group: "base",
|
||||
prop: "user",
|
||||
component: {
|
||||
name: "cl-form-card",
|
||||
props: {
|
||||
@ -241,8 +258,8 @@ const Upsert = useUpsert<Eps.UserInfoEntity>({
|
||||
]
|
||||
},
|
||||
{
|
||||
prop: "contact",
|
||||
group: "base",
|
||||
prop: "contact",
|
||||
component: {
|
||||
name: "cl-form-card",
|
||||
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: "工作",
|
||||
prop: "occupation",
|
||||
group: "other",
|
||||
component: {
|
||||
name: "el-tree-select",
|
||||
props: {
|
||||
@ -295,9 +298,9 @@ const Upsert = useUpsert<Eps.UserInfoEntity>({
|
||||
}
|
||||
},
|
||||
{
|
||||
group: "other",
|
||||
label: "身份证照片",
|
||||
prop: "idCardPic",
|
||||
group: "other",
|
||||
component: {
|
||||
name: "cl-upload",
|
||||
props: {
|
||||
@ -566,4 +569,10 @@ const Search = useSearch({
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
const visible = ref(false);
|
||||
|
||||
function open() {
|
||||
visible.value = true;
|
||||
}
|
||||
</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>
|
||||
<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">
|
||||
<template #slot-crud>
|
||||
<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>
|
||||
<div class="c">
|
||||
<el-button @click="open">预览</el-button>
|
||||
<demo-code :files="['form/crud.vue']" />
|
||||
|
||||
<cl-row>
|
||||
<!-- 数据表格 -->
|
||||
<cl-table ref="Table" />
|
||||
</cl-row>
|
||||
<!-- 自定义表单组件 -->
|
||||
<cl-form ref="Form">
|
||||
<template #slot-crud>
|
||||
<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-flex1 />
|
||||
<!-- 分页控件 -->
|
||||
<cl-pagination />
|
||||
</cl-row>
|
||||
<cl-row>
|
||||
<!-- 数据表格 -->
|
||||
<cl-table ref="Table" />
|
||||
</cl-row>
|
||||
|
||||
<!-- 新增、编辑 -->
|
||||
<cl-upsert ref="Upsert" />
|
||||
</cl-crud>
|
||||
</template>
|
||||
</cl-form>
|
||||
<cl-row>
|
||||
<cl-flex1 />
|
||||
<!-- 分页控件 -->
|
||||
<cl-pagination />
|
||||
</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>
|
||||
|
||||
<script lang="ts" setup>
|
||||
<script setup lang="ts">
|
||||
import { useCrud, useForm, useTable, useUpsert, setFocus } from "@cool-vue/crud";
|
||||
import { useCool } from "/@/cool";
|
||||
|
||||
const { refs, setRefs, service } = useCool();
|
||||
const { service } = useCool();
|
||||
|
||||
// cl-upsert
|
||||
const Upsert = useUpsert({
|
||||
@ -100,7 +115,7 @@ const Form = useForm();
|
||||
|
||||
function open() {
|
||||
Form.value?.open({
|
||||
title: "自定义表单",
|
||||
title: "内嵌CRUD",
|
||||
props: {
|
||||
labelPosition: "top"
|
||||
},
|
||||
@ -110,11 +125,10 @@ function open() {
|
||||
},
|
||||
items: [
|
||||
{
|
||||
label: "获取 ref,打开后聚焦",
|
||||
label: "姓名",
|
||||
prop: "name",
|
||||
component: {
|
||||
name: "el-input",
|
||||
ref: setRefs("name"),
|
||||
props: {
|
||||
placeholder: "请填写姓名"
|
||||
}
|
||||
@ -131,13 +145,7 @@ function open() {
|
||||
}
|
||||
}
|
||||
],
|
||||
op: {
|
||||
// buttons: ["save"]
|
||||
},
|
||||
on: {
|
||||
open() {
|
||||
refs.name.focus();
|
||||
},
|
||||
submit() {
|
||||
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">
|
||||
import { useCrud, useForm, useTable } from "@cool-vue/crud";
|
||||
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";
|
||||
|
||||
// 替换你的类型
|
||||
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