refactor: PageTable优化

This commit is contained in:
meilin.huang
2023-12-16 17:41:15 +08:00
parent 06bce33c48
commit 68f8603c75
21 changed files with 372 additions and 216 deletions

View File

@@ -2,6 +2,7 @@
<component
:is="item?.render ?? `el-${item.type}`"
v-bind="{ ...handleSearchProps, ...placeholder, clearable: true }"
v-on="{ ...handleEvents }"
v-model.trim="itemValue"
:data="item.type === 'tree-select' ? item.options : []"
:options="['cascader', 'select-v2'].includes(item.type!) ? item.options : []"
@@ -48,19 +49,6 @@ const fieldNames = computed(() => {
};
});
// 接收 enumMap (el 为 select-v2 需单独处理 enumData)
// const enumMap = inject('enumMap', ref(new Map()));
// const columnEnum = computed(() => {
// let enumData = enumMap.value.get(props.item.prop);
// if (!enumData) return [];
// if (props.item?.type === 'select-v2' && props.item.fieldNames) {
// enumData = enumData.map((item: { [key: string]: any }) => {
// return { ...item, label: item[fieldNames.value.label], value: item[fieldNames.value.value] };
// });
// }
// return enumData;
// });
// 处理透传的 searchProps (type 为 tree-select、cascader 的时候需要给下默认 label && value && children)
const handleSearchProps = computed(() => {
const label = fieldNames.value.label;
@@ -77,6 +65,12 @@ const handleSearchProps = computed(() => {
return searchProps;
});
// 处理透传的 事件
const handleEvents = computed(() => {
let itemEvents = props.item?.props ?? {};
return itemEvents;
});
// 处理默认 placeholder
const placeholder = computed(() => {
const search = props.item;

View File

@@ -1,4 +1,5 @@
import { VNode } from 'vue';
import Api from '@/common/Api';
import { VNode, ref, toValue } from 'vue';
export type FieldNamesProps = {
label: string;
@@ -19,6 +20,78 @@ export type SearchItemType =
| 'switch'
| 'slider';
/**
* 表单组件可选项的api信息
*/
export class OptionsApi {
/**
* 请求获取options的api
*/
api: Api;
/**
* 请求参数
*/
params: any;
/**
* 是否立即执行否则在组件focus事件中获取
*/
immediate: boolean = false;
/**
* 是否只获取一次即若以获取则不继续调用该api
*/
once: boolean = true;
/**
* 转换函数主要用于将响应的api结果转换为满足组件options的结构
*/
convertFn: (apiResp: any) => any;
withConvertFn(fn: (apiResp: any) => any) {
this.convertFn = fn;
return this;
}
/**
* 立即获取该可选值
* @returns
*/
withImmediate() {
this.immediate = true;
return this;
}
/**
* 设为非一次性api即每次组件focus获取的时候都允许重新获取options
* @returns this
*/
withNoOnce() {
this.once = false;
return this;
}
/**
* 调用api获取组件可选项
* @returns 组件可选项信息
*/
async getOptions() {
let res = await this.api.request(toValue(this.params));
if (this.convertFn) {
res = this.convertFn(res);
}
return res;
}
static new(api: Api, params: any): OptionsApi {
const oa = new OptionsApi();
oa.api = api;
oa.params = params;
return oa;
}
}
/**
* 搜索项
*/
@@ -43,22 +116,50 @@ export class SearchItem {
*/
options: any;
/**
* 获取可选项的api信息
*/
optionsApi: OptionsApi;
/**
* 插槽名
*/
slot: string;
props?: any; // 搜索项参数,根据 element plus 官方文档来传递,该属性所有值会透传到组件
/**
* 搜索项参数,根据 element plus 官方文档来传递,该属性所有值会透传到组件
*/
props?: any;
tooltip?: string; // 搜索提示
/**
* 搜索项事件,根据 element plus 官方文档来传递,该属性所有值会透传到组件
*/
events?: any;
span?: number; // 搜索项所占用的列数,默认为 1 列
/**
* 搜索提示
*/
tooltip?: string;
offset?: number; // 搜索字段左侧偏移列数
/**
* 搜索项所占用的列数,默认为 1 列
*/
span?: number;
fieldNames: FieldNamesProps; // 指定 label && value && children 的 key 值用于select等类型组件
/**
* 搜索字段左侧偏移列数
*/
offset?: number;
render?: (scope: any) => VNode; // 自定义搜索内容渲染tsx语法
/**
* 指定 label && value && children 的 key 值用于select等类型组件
*/
fieldNames: FieldNamesProps;
/**
* 自定义搜索内容渲染tsx语法
*/
render?: (scope: any) => VNode;
constructor(prop: string, label: string) {
this.prop = prop;
@@ -69,7 +170,7 @@ export class SearchItem {
return new SearchItem(prop, label);
}
static text(prop: string, label: string): SearchItem {
static input(prop: string, label: string): SearchItem {
const tq = new SearchItem(prop, label);
tq.type = 'input';
return tq;
@@ -78,10 +179,11 @@ export class SearchItem {
static select(prop: string, label: string): SearchItem {
const tq = new SearchItem(prop, label);
tq.type = 'select';
tq.withOneProps('filterable', true);
return tq;
}
static date(prop: string, label: string): SearchItem {
static datePicker(prop: string, label: string): SearchItem {
const tq = new SearchItem(prop, label);
tq.type = 'date-picker';
return tq;
@@ -93,8 +195,40 @@ export class SearchItem {
return tq;
}
withSpan(span: number): SearchItem {
this.span = span;
/**
* 为组件设置一个props属性
* @param propsKey 属性key
* @param propsValue 属性value
* @returns
*/
withOneProps(propsKey: string, propsValue: any): SearchItem {
if (!this.props) {
this.props = {};
}
this.props[propsKey] = propsValue;
return this;
}
/**
* 为组件传递组件自身的props属性 (根据 element plus 官方文档来传递,该属性所有值会透传到组件)
* @returns this
*/
withProps(props: any = {}): SearchItem {
this.props = props;
return this;
}
/**
* 为组件传递组件自身事件函数
* @param event 事件名称
* @param fn 事件处理函数
* @returns
*/
bindEvent(event: string, eventFn: any): SearchItem {
if (!this.events) {
this.events = {};
}
this.props[event] = eventFn;
return this;
}
@@ -108,7 +242,38 @@ export class SearchItem {
return this;
}
setOptions(options: any): SearchItem {
/**
* 设置获取组件options可选项值的api配置
* @param optionsApi 可选项api配置
* @returns this
*/
withOptionsApi(optionsApi: OptionsApi): SearchItem {
this.optionsApi = optionsApi;
// 使用api获取组件可选项需要将options转为响应式否则组件无法响应式获取组件可选项
this.options = ref(null);
// 立即执行则直接调用api获取并赋值options
if (this.optionsApi.immediate) {
this.optionsApi.getOptions().then((res) => {
this.options.value = res;
});
} else {
// 注册focus事件在触发focus时赋值options
this.bindEvent('focus', async () => {
if (!toValue(this.options) || !optionsApi.once) {
this.options.value = await this.optionsApi.getOptions();
}
});
}
return this;
}
withSpan(span: number): SearchItem {
this.span = span;
return this;
}
withOptions(options: any): SearchItem {
this.options = options;
return this;
}