table 表头添加搜索 search 参数

This commit is contained in:
神仙都没用 2023-12-14 21:53:40 +08:00
parent 7e6105d649
commit 8554990783
18 changed files with 309 additions and 84 deletions

View File

@ -9,7 +9,7 @@
"lint:eslint": "eslint \"./src/**/*.{vue,ts,tsx}\" --fix"
},
"dependencies": {
"@cool-vue/crud": "^7.0.8",
"@cool-vue/crud": "^7.0.9",
"@element-plus/icons-vue": "^2.1.0",
"@vueuse/core": "^10.4.0",
"@wangeditor/editor": "^5.1.23",

View File

@ -40,8 +40,8 @@ declare type obj = {
declare type DeepPartial<T> = T extends Function
? T
: T extends object
? { [P in keyof T]?: DeepPartial<T[P]> }
: T;
? { [P in keyof T]?: DeepPartial<T[P]> }
: T;
// 合并
declare type Merge<A, B> = Omit<A, keyof B> & B;
@ -327,10 +327,17 @@ declare namespace ClTable {
type: "index" | "selection" | "expand" | "op";
hidden: boolean | Vue.Ref<boolean>;
component: Render.Component;
search: {
isInput: boolean;
value: any;
component: Render.Component;
};
searchComponent: Render.Component;
dict: DictOptions | Vue.Ref<DictOptions>;
dictFormatter: (values: DictOptions) => string;
dictColor: boolean;
dictSeparator: string;
dictAllLevels: boolean;
buttons: OpButton | ((options: { scope: obj }) => OpButton);
align: "left" | "center" | "right";
label: string | Vue.Ref<string>;

View File

@ -1,6 +1,6 @@
{
"name": "@cool-vue/crud",
"version": "7.0.8",
"version": "7.0.9",
"private": false,
"main": "./dist/index.umd.min.js",
"typings": "types/index.d.ts",

View File

@ -0,0 +1,58 @@
import { Search } from "@element-plus/icons-vue";
import { h } from "vue";
import { useCrud } from "../../../hooks";
import { renderNode } from "../../../utils/vnode";
export function renderHeader(item: ClTable.Column, { scope, slots }: any) {
const crud = useCrud();
const slot = slots[`header-${item.prop}`];
if (slot) {
return slot({
scope
});
}
if (!item.search || !item.search.component) {
return scope.column.label;
}
// 显示输入框
function show(e: MouseEvent) {
item.search.isInput = true;
e.stopPropagation();
}
// 文字
const text = (
<div onClick={show}>
<el-icon class="icon">
<Search />
</el-icon>
<span>{scope.column.label}</span>
</div>
);
// 输入框
const input = h(renderNode(item.search.component, { prop: item.prop }), {
clearable: true,
modelValue: item.search.value,
onVnodeMounted(vn) {
// 默认聚焦
vn.component?.exposed?.focus?.();
},
onInput(val: any) {
item.search.value = val;
},
onChange(val: any) {
crud.value?.refresh({
page: 1,
[item.prop]: val === "" ? undefined : val
});
}
});
return <div class="cl-table-header__search">{item.search.isInput ? input : text}</div>;
}

View File

@ -29,3 +29,4 @@ export * from "./render";
export * from "./row";
export * from "./selection";
export * from "./sort";
export * from "./header";

View File

@ -4,6 +4,7 @@ import { cloneDeep, isEmpty, orderBy } from "lodash-es";
import { getValue } from "../../../utils";
import { parseTableDict, parseTableOpButtons } from "../../../utils/parse";
import { renderNode } from "../../../utils/vnode";
import { renderHeader } from "./header";
// 渲染
export function useRender() {
@ -78,15 +79,7 @@ export function useRender() {
return h(ElTableColumn, props, {
header(scope: any) {
const slot = slots[`header-${item.prop}`];
if (slot) {
return slot({
scope
});
} else {
return scope.column.label;
}
return renderHeader(item, { scope, slots });
},
default(scope: any) {
if (item.children) {

View File

@ -101,6 +101,31 @@
margin-bottom: 5px;
}
}
.cl-table-header__search {
display: inline-block;
width: 100%;
cursor: pointer;
.icon {
margin-right: 5px;
position: relative;
top: 2px;
font-size: 14px;
}
&:hover {
color: var(--el-color-primary);
}
& > div {
width: 100%;
.el-date-editor {
margin-right: 0;
}
}
}
}
.cl-filter {
@ -362,7 +387,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);
}

View File

@ -97,31 +97,42 @@ const userList = [
class TestService {
// 分页列表
async page(params: any) {
const { status, occupation, keyWord, page, size, phone, name, sort, order } = params || {};
const { keyWord, page, size, sort, order } = params || {};
// 关键字查询
const keyWordLikeFields = ["phone", "name"];
// 等值查询
const fieldEq = ["createTime", "occupation", "status"];
// 模糊查询
const likeFields = ["phone", "name"];
// 过滤后的列表
const list = orderBy(userList, order, sort).filter((e) => {
if (status !== undefined) {
return e.status == status;
}
if (phone !== undefined) {
return String(e.phone).includes(phone);
}
if (name !== undefined) {
return e.name.includes(name);
}
const list = orderBy(userList, order, sort).filter((e: any) => {
let f = true;
if (keyWord !== undefined) {
return e.name.includes(keyWord) || String(e.phone).includes(keyWord);
f = !!keyWordLikeFields.find((k) => String(e[k]).includes(String(params.keyWord)));
}
if (occupation !== undefined) {
return e.occupation == occupation;
}
fieldEq.forEach((k) => {
if (f) {
if (params[k] !== undefined) {
f = e[k] == params[k];
}
}
});
return true;
likeFields.forEach((k) => {
if (f) {
if (params[k] !== undefined) {
f = String(e[k]).includes(String(params[k]));
}
}
});
return f;
});
return new Promise((resolve) => {

View File

@ -115,13 +115,23 @@ export function getValue(data: any, params?: any) {
}
// 深度查找
export function deepFind(value: any, list: any[]) {
function deep(arr: any[]): any | undefined {
export function deepFind(value: any, list: any[], options?: { allLevels: boolean }) {
const { allLevels = true } = options || {};
function deep(arr: any[], name: string[]): any | undefined {
for (const e of arr) {
if (e.value === value) {
return e;
if (allLevels) {
return {
...e,
label: [...name, e.label].join(" / ")
};
} else {
return e;
}
} else if (e.children) {
const d = deep(e.children);
const d = deep(e.children, [...name, e.label]);
if (d !== undefined) {
return d;
}
@ -130,7 +140,7 @@ export function deepFind(value: any, list: any[]) {
return undefined;
}
return deep(list);
return deep(list, []);
}
// uuid

View File

@ -0,0 +1,2 @@
/// <reference types="../index" />
export declare function renderHeader(item: ClTable.Column, { scope, slots }: any): any;

View File

@ -39,6 +39,72 @@ export declare function useTable(props: any): {
functionSlot?: boolean | undefined;
vm?: any;
};
search: {
isInput: boolean;
value: any;
component: {
[x: string]: any;
name?: string | undefined;
options?: {
[x: string]: any;
label?: string | undefined;
value?: any;
color?: string | undefined;
type?: string | undefined;
}[] | {
value: {
[x: string]: any;
label?: string | undefined;
value?: any;
color?: string | undefined;
type?: string | undefined;
}[];
} | undefined;
props?: {
[x: string]: any;
onChange?: ((value: any) => void) | undefined;
} | {
value: {
[x: string]: any;
onChange?: ((value: any) => void) | undefined;
};
} | undefined;
style?: obj | undefined;
functionSlot?: boolean | undefined;
vm?: any;
};
};
searchComponent: {
[x: string]: any;
name?: string | undefined;
options?: {
[x: string]: any;
label?: string | undefined;
value?: any;
color?: string | undefined;
type?: string | undefined;
}[] | {
value: {
[x: string]: any;
label?: string | undefined;
value?: any;
color?: string | undefined;
type?: string | undefined;
}[];
} | undefined;
props?: {
[x: string]: any;
onChange?: ((value: any) => void) | undefined;
} | {
value: {
[x: string]: any;
onChange?: ((value: any) => void) | undefined;
};
} | undefined;
style?: obj | undefined;
functionSlot?: boolean | undefined;
vm?: any;
};
dict: {
[x: string]: any;
label?: string | undefined;
@ -57,6 +123,7 @@ export declare function useTable(props: any): {
dictFormatter: (values: DictOptions) => string;
dictColor: boolean;
dictSeparator: string;
dictAllLevels: boolean;
buttons: ((options: {
scope: obj;
}) => ClTable.OpButton) | ("info" | "delete" | "edit" | `slot-${string}` | {
@ -133,3 +200,4 @@ export * from "./render";
export * from "./row";
export * from "./selection";
export * from "./sort";
export * from "./header";

View File

@ -7,5 +7,7 @@ export declare function merge(d1: any, d2: any): any;
export declare function addClass(el: Element, name: string): void;
export declare function removeClass(el: Element, name: string): void;
export declare function getValue(data: any, params?: any): any;
export declare function deepFind(value: any, list: any[]): any;
export declare function deepFind(value: any, list: any[], options?: {
allLevels: boolean;
}): any;
export declare function uuid(separator?: string): string;

View File

@ -3,6 +3,7 @@
<el-date-picker
v-model="date"
:type="type"
:editable="false"
:default-time="defaultTime"
:value-format="valueFormat"
:style="{ width }"
@ -77,13 +78,17 @@ const date = ref();
const quickType = ref(props.defaultQuickType);
//
function onChange(value: any[]) {
function onChange(value: any) {
//
quickType.value = "";
//
let params = {};
if (value === null) {
value = undefined;
}
if (isRange.value) {
let [startTime, endTime] = value || [];
@ -103,10 +108,12 @@ function onChange(value: any[]) {
};
}
Crud.value?.refresh({
...params,
page: 1
});
if (props.prop) {
Crud.value?.refresh({
...params,
page: 1
});
}
emit("update:modelValue", value);
emit("change", value);

View File

@ -11,6 +11,11 @@ import "@cool-vue/crud/dist/index.css";
export default (): Merge<ModuleConfig, CrudOptions> => {
return {
options: {
style: {
table: {
// contextMenu: [], 是否关闭表格右键菜单
}
},
dict: {
sort: {
prop: "order",

View File

@ -45,31 +45,44 @@ const userList: User[] = data.list;
class Test {
// 分页列表
async page(params: any) {
const { status, occupation, keyWord, page, size, phone, name, sort, order } = params || {};
const { keyWord, page, size, sort, order } = params || {};
console.log("[test]", params);
// 关键字查询
const keyWordLikeFields = ["phone", "name"];
// 等值查询
const fieldEq = ["createTime", "occupation", "status"];
// 模糊查询
const likeFields = ["phone", "name"];
// 过滤后的列表
const list = orderBy(userList, order, sort).filter((e) => {
if (status !== undefined) {
return e.status == status;
}
if (phone !== undefined) {
return String(e.phone).includes(phone);
}
if (name !== undefined) {
return e.name.includes(name);
}
const list = orderBy(userList, order, sort).filter((e: any) => {
let f = true;
if (keyWord !== undefined) {
return e.name.includes(keyWord) || String(e.phone).includes(keyWord);
f = !!keyWordLikeFields.find((k) => String(e[k]).includes(String(params.keyWord)));
}
if (occupation !== undefined) {
return e.occupation == occupation;
}
fieldEq.forEach((k) => {
if (f) {
if (params[k] !== undefined) {
f = e[k] == params[k];
}
}
});
return true;
likeFields.forEach((k) => {
if (f) {
if (params[k] !== undefined) {
f = String(e[k]).includes(String(params[k]));
}
}
});
return f;
});
return new Promise((resolve) => {

View File

@ -36,17 +36,7 @@
<cl-column-custom :columns="Table?.columns" :ref="setRefs('columnCustom')" />
<!-- 关键字搜索 -->
<cl-search-key
field="name"
:field-list="[
{
label: '姓名',
value: 'name'
},
{ label: '手机号', value: 'phone' }
]"
:width="250"
/>
<cl-search-key placeholder="搜索姓名、手机号" :width="250" />
<!-- 高级搜索按钮 -->
<cl-adv-btn />
@ -77,6 +67,11 @@
</el-descriptions>
</div>
</template>
<!-- 自定义列 -->
<template #column-wages="{ scope }">
<span>{{ scope.row.wages }}🤑</span>
</template>
</cl-table>
</cl-row>
@ -394,22 +389,33 @@ const Table = useTable({
{
label: "姓名",
prop: "name",
minWidth: 150
minWidth: 120
},
{
label: "手机号",
prop: "phone",
minWidth: 140
minWidth: 140,
//
search: {
// cool
component: {
name: "el-input",
props: {
placeholder: "搜索手机号"
}
}
}
},
{
label: "账号",
prop: "account",
minWidth: 140
minWidth: 150
},
{
label: "存款(元)",
prop: "wages",
minWidth: 120,
minWidth: 150,
sortable: "desc" //
},
{
@ -417,7 +423,18 @@ const Table = useTable({
prop: "occupation",
dict: dict.get("occupation"),
dictColor: true,
minWidth: 120
minWidth: 150,
//
search: {
// jsx
component: {
name: "cl-select",
props: {
options: dict.get("occupation")
}
}
}
},
{
label: "状态",
@ -431,9 +448,13 @@ const Table = useTable({
{
label: "出生年月",
orderNum: 1,
minWidth: 140,
minWidth: 165,
prop: "createTime",
sortable: "custom"
search: {
component: (
<cl-date-picker type="date" value-format="YYYY-MM-DD" placeholder="搜索日期" />
)
}
},
{
type: "op",

File diff suppressed because one or more lines are too long

View File

@ -344,10 +344,10 @@
"@babel/helper-validator-identifier" "^7.22.20"
to-fast-properties "^2.0.0"
"@cool-vue/crud@^7.0.8":
version "7.0.8"
resolved "https://registry.yarnpkg.com/@cool-vue/crud/-/crud-7.0.8.tgz#14855d5a326b5f91bb35b5791954341e5a61db23"
integrity sha512-hI8cyoRnRrwPNsyoVtb6nVCKVFFbsqhFH6HR1B2/NVRqfn87wvDoQ2kkm76K7kafO/bZM9WJu8tetYuqkaSoOw==
"@cool-vue/crud@^7.0.9":
version "7.0.9"
resolved "https://registry.yarnpkg.com/@cool-vue/crud/-/crud-7.0.9.tgz#06c169380c1536385877154b98fd86eea8ce635d"
integrity sha512-Saaqq3A6Hunctkfnyv+TFhpOyPr8XY5kyMdOflLgPKD8lhgsgu2/cN9wRM9q0rx7uar/D/oHYjN7/Vfn1Hfs9w==
dependencies:
array.prototype.flat "^1.2.4"
core-js "^3.21.1"