mirror of
https://github.com/cool-team-official/cool-admin-vue.git
synced 2026-01-27 08:38:15 +00:00
table 表头添加搜索 search 参数
This commit is contained in:
parent
7e6105d649
commit
8554990783
@ -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",
|
||||
|
||||
11
packages/crud/index.d.ts
vendored
11
packages/crud/index.d.ts
vendored
@ -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>;
|
||||
|
||||
@ -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",
|
||||
|
||||
58
packages/crud/src/components/table/helper/header.tsx
Normal file
58
packages/crud/src/components/table/helper/header.tsx
Normal 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>;
|
||||
}
|
||||
@ -29,3 +29,4 @@ export * from "./render";
|
||||
export * from "./row";
|
||||
export * from "./selection";
|
||||
export * from "./sort";
|
||||
export * from "./header";
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
@ -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) => {
|
||||
|
||||
@ -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
|
||||
|
||||
2
packages/crud/types/components/table/helper/header.d.ts
vendored
Normal file
2
packages/crud/types/components/table/helper/header.d.ts
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/// <reference types="../index" />
|
||||
export declare function renderHeader(item: ClTable.Column, { scope, slots }: any): any;
|
||||
@ -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";
|
||||
|
||||
4
packages/crud/types/utils/index.d.ts
vendored
4
packages/crud/types/utils/index.d.ts
vendored
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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) => {
|
||||
|
||||
@ -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
@ -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"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user