表单中关联表单填充关联表单
本案例来自三方开发者「Jing」
1. 使用场景
宜搭目前关联表单组件无法填充关联表单组件,借助此例我们可以探讨一下如何去实现相应的功能。
等效于:
目前仅支持关联表单组件在主表中使用的场景,暂不支持在子表单中使用的场景。
若包含数据填充,关联表单需使用新版数据填充,旧版数据填充不支持触发,具体可见下述更新公告。
升级新版数据填充可参考目录【5.升级新版数据填充】(2023.10.30 后配置的关联表单无需操作)。
2. 实现功能
2.1. 配置关联表单数据表 1
用于后续关联表单关联数据。
2.2. 配置关联表单数据表 2
关联表单数据表 2 中放置一个关联表单关联数据表 1。
2.3. 不包含被填充关联表单的数据填充
2.3.1. 配置页面
2.3.2. 配置关联表单
关联 2.2 中配置的表单并设置显示字段。
关联 2.1 中配置的表单并设置显示字段。
2.3.3. 将下述代码拷贝至页面 JS 中
无需做任何修改。
/**
* 关联表单填充关联表单
* @param sourceAssociationFormFieldId 关联表单主表字段-关联表单组件唯一标识
* @param fillAssociationFormFieldId 当前表单字段-关联表单组件唯一标识
* @param value 关联表单实例数据
*/
export function associationFormFillAssociationForm(sourceAssociationFormFieldId = '', fillAssociationFormFieldId = '', value = []) {
if (sourceAssociationFormFieldId && fillAssociationFormFieldId) {
if (value && value.length) {
const { rawData = {} } = value[0];
const { instValue = [] } = rawData;
const sourceAssociationFormFieldData = instValue.filter((item) => {
return item.fieldId === sourceAssociationFormFieldId;
});
if (sourceAssociationFormFieldData.length) {
const fillData = (((sourceAssociationFormFieldData[0] || {}).fieldData || {}).value || []);
this.$(fillAssociationFormFieldId).setValue(fillData);
}
} else {
this.$(fillAssociationFormFieldId).reset();
}
}
}
2.3.4. onChange 中调用函数
注意修改括号内的唯一标识。
关联表单主表字段(sourceAssociationFormFieldId)的值填充到 当前表单字段(fillAssociationFormFieldId)。
/**
* 关联表单-数据表2 onChange
* @param value 当前值
*/
export function onChange({ value }) {
this.associationFormFillAssociationForm('associationFormField_lrolefps', 'associationFormField_lrolnvkw', value);
}
2.4. 包含被填充关联表单的数据填充
2.4.1. 配置页面
2.4.2. 配置关联表单
关联 2.2 中配置的表单并设置显示字段。
关联 2.1 中配置的表单并设置显示字段。
2.4.3. 配置数据填充
按需配置数据填充。
2.4.4. 将下述代码拷贝至页面 JS 中
无需做任何修改。
/**
* 关联表单填充关联表单
* @param sourceAssociationFormFieldId 关联表单主表字段-关联表单组件唯一标识
* @param fillAssociationFormFieldId 当前表单字段-关联表单组件唯一标识
* @param value 关联表单实例数据
*/
export function associationFormFillAssociationForm(sourceAssociationFormFieldId = '', fillAssociationFormFieldId = '', value = []) {
if (sourceAssociationFormFieldId && fillAssociationFormFieldId) {
if (value && value.length) {
const { rawData = {} } = value[0];
const { instValue = [] } = rawData;
const sourceAssociationFormFieldData = instValue.filter((item) => {
return item.fieldId === sourceAssociationFormFieldId;
});
if (sourceAssociationFormFieldData.length) {
const fillData = (((sourceAssociationFormFieldData[0] || {}).fieldData || {}).value || []);
this.$(fillAssociationFormFieldId).setValue(fillData);
}
} else {
this.$(fillAssociationFormFieldId).reset();
}
}
}
/**
* 触发关联表单数据填充
* @param associationFormFieldId 需要数据填充的关联表单组件唯一标识
*/
export function associationFormDataFilling(associationFormFieldId = '') {
if (associationFormFieldId) {
const associationFormValue = this.$(associationFormFieldId).getValue();
if (associationFormValue && associationFormValue.length) {
const { appType = '', formType = '', formUuid = '', instanceId = '' } = associationFormValue[0] || {};
if (appType && formType && formUuid && instanceId) {
const dataFillingRules = this.$(associationFormFieldId).get('dataFillingRules') || {}; // 关联表单填充条件
const { mainRules = [], tableRules = [] } = dataFillingRules;
if (mainRules.length) {
// 主表字段数据填充
if (formType === 'receipt') {
// 表单
fetch(`/${appType}/v1/form/getFormDataById.json?_csrf_token=${this.getCsrfToken()}&formInstId=${instanceId}`, {
headers: {
'Content-Type': 'application/json;charset=UTF-8',
},
})
.then((data) => {
return data.json();
}).then(({ content }) => {
const { formData = {} } = (content || {});
this.mainDataFilling(formData, mainRules);
}).catch(() => {
this.utils.toast({
title: '数据获取失败',
type: 'error',
});
});
}
if (formType === 'process') {
// 流程
fetch(`/${appType}/v1/process/getInstanceById.json?_csrf_token=${this.getCsrfToken()}&processInstanceId=${instanceId}`, {
headers: {
'Content-Type': 'application/json;charset=UTF-8',
},
})
.then((data) => {
return data.json();
}).then(({ content }) => {
const { data = {} } = (content || {});
this.mainDataFilling(data, mainRules);
}).catch(() => {
this.utils.toast({
title: '数据获取失败',
type: 'error',
});
});
}
}
if (tableRules.length) {
// 子表字段数据填充
const body = new URLSearchParams();
const searchBody = tableRules.map((item) => {
return {
page: 1,
limit: 500,
fieldId: item.tableId,
resultGroupKey: item.tableId,
searchField: (((item.filters || {}).rules) || []).map((i) => {
return {
key: i.id,
value: i.extValue === 'value' ? i.value : this.$(i.value).getValue(),
type: this.getType(i.componentType),
componentName: i.componentType,
operator: i.op,
};
}),
logicOperator: (item.filters || {}).condition,
}
});
body.append('_csrf_token', this.getCsrfToken());
body.append('formUuid', formUuid);
body.append('formInstId', instanceId);
body.append('instSubTableDataParamListStr', JSON.stringify(searchBody));
fetch(`/${appType}/query/formProcInstData/getInstMultiSubTableDatas.json`, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body,
})
.then((data) => {
return data.json();
}).then(({ content }) => {
// this.utils.__getFlowMaps().tableFieldIdMap 为非官方提供标准 API,有失效风险,谨慎使用
const targetTableFieldIdMap = this.utils.__getFlowMaps().tableFieldIdMap; // 获取当前页面子表单字段映射
const childDataFillingRules = {}; // 子表字段填充规则
tableRules.forEach((item) => {
if (!childDataFillingRules[item.tableId]) {
childDataFillingRules[item.tableId] = [];
}
const childRules = (item.rules || []).map((i) => {
return {
...i,
sourceTableField: item.tableId, // 目标子表单
targetTableField: targetTableFieldIdMap[i.target], // 当前页面子表单
};
});
childDataFillingRules[item.tableId] = childRules;
});
this.childDataFilling(content, childDataFillingRules);
}).catch(() => {
this.utils.toast({
title: '数据获取失败',
type: 'error',
});
});
}
}
}
}
}
/**
* 主表字段数据填充处理函数
* @param dataMap 源数据
* @param mainRules 主表字段填充规则
*/
export function mainDataFilling(dataMap = {}, mainRules = []) {
try {
mainRules.forEach((item) => {
this.$(item.target).setValue(this.mainDataSolve(dataMap, item.source, item.sourceType));
});
} catch (error) {
console.error(error);
this.utils.toast({
title: '主表字段数据填充错误',
type: 'error',
});
}
}
/**
* 主表数据处理函数
* @param dataMap 源数据
* @param source 源字段唯一标识
* @param sourceType 源字段类型
*/
export function mainDataSolve(dataMap = {}, source = '', sourceType = '') {
try {
if (dataMap[source]) {
switch (sourceType) {
case 'AttachmentField': // 附件
case 'ImageField': // 图片
case 'AddressField': // 地址
return dataMap[source] ? JSON.parse(dataMap[source]) : [];
case 'RadioField': // 单选
case 'CheckboxField': // 复选
case 'SelectField': // 下拉单选
case 'MultiSelectField': // 下拉复选
return dataMap[`${source}_id`];
case 'CascadeSelectField': // 级联选择
return (dataMap[`${source}_id`] || []).at(-1);
case 'EmployeeField': // 成员
return (dataMap[source] || []).map((item, index) => {
return {
label: item,
value: dataMap[`${source}_id`][index],
};
});
case 'DepartmentSelectField': // 部门
case 'CountrySelectField': // 国家 / 地区
return (dataMap[source] || []).map((item, index) => {
return {
text: item,
value: dataMap[`${source}_id`][index],
};
});
case 'DateField': // 日期
return Number(dataMap[source]);
case 'CascadeDateField': // 日期区间
return [Number(dataMap[source][0]), Number(dataMap[source][1])];
default:
return dataMap[source];
}
}
} catch (error) {
console.error(error);
this.utils.toast({
title: '数据填充处理错误',
type: 'error',
});
}
}
/**
* 子表字段数据填充处理函数
* @param dataMap 源数据
* @param childDataFillingRules 子表字段填充规则
*/
export function childDataFilling(dataMap = {}, childDataFillingRules = {}) {
try {
const tableDataResult = {};
Object.keys(dataMap).forEach((tableKey) => {
const items = [];
if (!tableDataResult[tableKey]) {
tableDataResult[tableKey] = [];
}
const tableDataItem = (dataMap[tableKey].values || []).map((item) => {
return item.instValue ? JSON.parse(JSON.parse(item.instValue)) : [];
});
tableDataItem.forEach((i) => {
const objItem = {};
i.forEach((j) => {
objItem[j.fieldId] = this.childDataSolve(j.fieldData, j.componentName);
});
items.push(objItem);
});
tableDataResult[tableKey] = items;
});
Object.keys(childDataFillingRules).forEach((key) => {
if (key && childDataFillingRules[key] && childDataFillingRules[key].length) {
const result = []; // 数据处理结果
tableDataResult[key].forEach((i) => {
const objItem = {};
childDataFillingRules[key].forEach((j) => {
objItem[j.target] = i[j.source];
});
result.push(objItem);
});
this.$(childDataFillingRules[key][0].targetTableField).setValue(result);
}
});
} catch (error) {
console.error(error);
this.utils.toast({
title: '子表单数据填充错误',
type: 'error',
});
}
}
/**
* 子表数据处理函数
* @param fieldData 源数据
* @param componentName 源字段类型
*/
export function childDataSolve(fieldData = {}, componentName = '') {
try {
if (componentName) {
switch (componentName) {
case 'CascadeSelectField': // 级联选择
return ((fieldData.value || []).at(-1) || {}).value;
default:
return fieldData.value;
}
}
} catch (error) {
console.error(error);
this.utils.toast({
title: '数据填充处理错误',
type: 'error',
});
}
}
/**
* 获取数据筛选的类型
* @param componentName 字段类型
*/
export function getType(componentName = '') {
if (componentName) {
switch (componentName) {
case 'RadioField': // 单选
case 'CheckboxField': // 复选
case 'SelectField': // 下拉单选
case 'MultiSelectField': // 下拉复选
case 'DepartmentSelectField': // 部门
case 'CountrySelectField': // 国家地区
return 'ARRAY';
case 'NumberField': // 数值
case 'RateField': // 评分
case 'DateField': // 日期
case 'CascadeDateField': // 日期区间
return 'DOUBLE';
default:
return 'TEXT';
}
}
}
/**
* 获取 csrfToken
*/
export function getCsrfToken() {
const tokenDom = document.getElementsByName('_csrf_token');
const csrfToken = tokenDom && tokenDom.length ? (tokenDom[0] || {}).value : '';
return csrfToken;
}
2.4.5. onChange 中调用函数
关联表单主表字段(sourceAssociationFormFieldId)的值填充到 当前表单字段(fillAssociationFormFieldId)。
需要数据填充的关联表单组件唯一标识(associationFormFieldId)。
/**
* 关联表单-数据表2 onChange
* @param value 当前值
*/
export function onChange({ value }) {
this.associationFormFillAssociationForm('associationFormField_lrolefps', 'associationFormField_lrolnvkw', value);
this.associationFormDataFilling('associationFormField_lrolnvkw');
}
3. 实现效果
3.1. 不包含被填充关联表单的数据填充
3.2. 包含被填充关联表单的数据填充
4. 在线试玩
5. 升级新版数据填充
将关联表单的填充条件重新保存即可升级到新版数据填充(下述操作后页面也需重新保存下)。
本文档对您是否有帮助?