“我脚下的影子,从来不肯试着像谁” —— 《烟味》· 陈奕迅
这次来xx,做的最多的就是表格,比如二级表头,比如多个不同表表头,懒得一个个去写(毕竟不是三年内的小朋友了),结合之前的纪委打工系列总结,索性就从头到尾缕一缕逻辑来个大的
引入几个不知道啥时候总结的经验
resource = handleFn(params1,params2,...)
- 优先关注返回数据,
即需要的是什么格式的数据,中间的处理过程由handleFn处理,然后关注根据已有的条件,适当调整后作为参数传入。
- options式开发:
将通用的数据放置在config文件中,页面中按需调用,包括函数,对象映射,数组,以及字符串等多种数据格式,但是在组件眼中,不管它是何种类型,都仅归于配置一类,他们的特征都是根据对应的值返回对应的映射,或者根据一些入参返回对应的数据类型,存在的目的是为了作为页面的初始数据,在经过生命周期或者某些动作后更新值供界面使用,换句话说,我们加入option的目的是假设它
有
,并不是无
或空
- 抽取共性,保留不同
规定一个变量的初始值首先应该满足大多数场景的默认值,针对个别特例,则取反值,重点:
抽
当前需求:tabs内有多个子项,不同的子项表示·不同·的表数据,不同指的是可能会有多/单层表头,可能会有/无序号,可能会有/无编辑态,可能会有/无合计项,编辑态下会有/input/select/datepiker 三重输入类型,其中编辑态下的select态下的字典项也分为三种类型,后端传入/前端写死/省市联动下的后端传入,有不同的访问列表以及导出接口。
想要实现上述所说一系列繁琐的功能,也必须得归纳一下
期望的效果是在完成上述功能的前提下,仅在配置文件增减少量内容即可实现动态实现表内容。
目的:
-
输出合理且规整的表头数据,满足上述大部分需求
-
输出对应的key的字典项的初值
需求拆解:
一个完整的表头最少要有以下项:label,id,prop,children(如果有子项),
一张表要有额外的配置,比如是否需要序号,对应的字典的key(用于从后端取字典),以及前端本地的字典项,当前表的表头数据,当前表的标题(用在title),当前表本身的key(唯一值,用于双向绑定tabs的值),请求当前表的列表接口,请求当前表的导出接口,是否需要合并行,为了尽量减少手动录入的流程,须要有初始表数据,以及基于初始表数据生成的真正的表头数据
1. 引入基础函数
- 目的:赋予表头项唯一key
// 生成随机id 万以内
const randomNum = () => Math.floor(Math.random() * 100000) + 1;
- 递归收集表头数据中所有不为空的prop并将其作为表格初值(新增行&编辑行要用到)
// 收集表头中所有不为空的prop
function collectProps(data) {const result = {};function recurse(items) {items.forEach((item) => {if (item.prop && item.prop.trim() !== "") {result[item.prop] = ``;}if (item.children && item.children.length > 0) {recurse(item.children);}});}recurse(data);return result;
}
- 前端本地生成的字典项,要与后端返回的要用到的数据结构保持一致
// 基础字典 前端自生成
export const selectBaseOptions = [`是`,`否`].map(item=>({codeName:item,codeValue:item}))
- 递归渲染多级表头
// 生成表头数据
/*** 示例入参:[{ label: '姓名', prop: 'name' },{ label: '年龄', prop: 'age' },{label: '地址',prop: 'address',children: [{ label: '省份', prop: 'province' },{label: '城市',prop: 'city',children: [{ label: '区县', prop: 'district' },{ label: '街道', prop: 'street' }]}]}
]* **/
/*** return* 生成的表头数据结构如下:type column {
id:number
label:string
prop:string | ''
children?:column
}* [{ id: 123, label: '姓名', prop: 'name' },{ id: 456, label: '年龄', prop: 'age' },{id: 789,label: '地址',prop: '',children: [{ id: 101, label: '省份', prop: 'province' },{id: 202,label: '城市',prop: '',children: [{ id: 303, label: '区县', prop: 'district' },{ id: 404, label: '街道', prop: 'street' }]}]}
]* **/
// 👇生成表头数据函数 👆 生成表头数据函数注释说明
function generateHeader(config, generateId = randomNum) {if (!Array.isArray(config)) return [];if (Array.isArray(config) && config.length === 0) return [];function processHeader(header) {const id = generateId();if (header.children) {return {id: id,label: header.label,prop: "",children: header.children.map(processHeader),};}return {id: id,label: header.label,prop: header.prop,};}return config.map(processHeader);
}
- 生成表逻辑拆解
基于需求: tabs内有多个子项,不同的子项表示不同的表数据, 因而表与tab是强绑定态,因而可以将表头数据与表标题写在一起
(1). 定义基础表头数据
此表头涵盖表标题,以及独有的key,获取表列表的接口以及当前表的导出接口,以及对应的表头和表头key集合,数据结构如下:
// 表头
interface ListColumn {label: string; // 列的标签prop: string; // 列的属性名children?: ListColumn[]; // 可选的子列
}
// 基础表对象
interface BaseTableConfig {title: string; // 报表标题py: string; // 拼音缩写,作为tab绑定的keyneedSum: boolean; // 是否需要合计项tableResourceUrl: string; // 表格数据资源的URLreportUrl: string; // 报表导出的URLlist: ListColumn[]
}// 基础表配置列表,长度是表的个数 须mock数据-》将上述数据结构交给ai生成即可,此处不展示详细数据
const baseTableConfigList: BaseTableConfig[] = [];// 基于baseTableConfigList生成tabs列表
export const tableHeadFormattedList = baseTableConfigList.map((v, i) => {// console.log("v :>> ", v);const tableHeaderConfig = generateHeader(v.list);return {value: v.py,idx: i + 1 + "",label: v.title,key: v.title,needSn: false,...vtableHeaderConfig, // 此处是各个表最终的表头数据,包含多层表头};
});
至此,基本完成了表配置,当导入时,表头数据也会随tab的切换而切换,支持列表请求与导出接口切换
接下来要配置编辑态下的下拉框字典
要回答的是在什么时机下根据什么条件返回什么样的数据
下回分解