Set default values for associated forms in forms (the first item is selected by default)
This case is from Jing, a three-party developer 」
1. Usage scenarios
YIDA currently, the default value cannot be set for the associated form component. In this example, we can discuss how to implement the corresponding functions.
Currently, only the scenarios in which the associated form component is used in the main table are supported. Currently, the scenarios in subforms are not supported.
If data filling is included, the associated form must be filled with the new version of data. The old version of data filling cannot be triggered. For more information, see the following update announcement.
For more information about how to upgrade the new version of data filling, see Directory [5. Upgrade the new version of data filling] (the associated form configured after 2023.10.30 does not need to be operated).
2. Implement functions
2.1. Configure associated form tables
Used to associate data with subsequent forms.
2.2. Does not contain data padding
2.2.1. Configuration page
2.2.2. Configure associated forms
Associate the form configured in 2.1 and set display fields.
2.2.3. Copy the following code to Page JS
No modification is required.
/**
* 获取关联表单设置默认值(默认第一个选项)
* @param associationFormField 需要设置默认值的关联表单组件唯一标识
*/
export function getAssociationFormFirstData(associationFormField = '') {
if (this.utils.isSubmissionPage() && associationFormField) {
const {
formUuid, // 关联表单
appType, // 应用 appType
formType, // 表单类型
mainFieldId, // 主要信息字段唯一标识
subFieldId, // 次要信息字段唯一标识
} = this.$(associationFormField).get('associationForm'); // 获取关联表单配置
const {
condition, // 筛选条件关系
rules = [], // 筛选条件
} = this.$(associationFormField).get('dataFilterRules'); // 获取关联表单筛选条件
const searchField = rules.map((item) => {
return {
key: item.id,
value: item.extValue === 'value' ? item.value : this.$(item.value).getValue(),
type: this.getType(item.componentType),
componentName: item.componentType,
operator: item.op,
};
});
const orderConfig = this.$(associationFormField).get('orderConfig') || []; // 获取关联表单排序条件
const dynamicOrder = {}; // 排序条件
orderConfig.forEach((item) => {
dynamicOrder[item.fieldId] = item.order === 'asc' ? '+' : '-';
});
const body = new URLSearchParams();
body.append('_csrf_token', this.getCsrfToken());
body.append('formUuid', formUuid);
body.append('manageUuid', formUuid);
body.append('appType', appType);
body.append('currentPage', 1);
body.append('page', 1);
body.append('pageSize', 20);
body.append('limit', 20);
body.append('logicOperator', condition);
body.append('searchField', JSON.stringify(searchField));
body.append('dynamicOrder', JSON.stringify(dynamicOrder));
fetch(`/${appType}/query/formProcInstData/getInstanceDatas.json`, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body,
}).then((data) => {
return data.json();
}).then(({ content }) => {
const { totalCount, values = [] } = content;
if (totalCount) {
const { dataMap = {}, formInstanceId = '', processInstanceId = '' } = values[0] || {};
this.$(associationFormField).setValue([{
appType,
formType,
formUuid,
instanceId: formInstanceId || processInstanceId,
subTitle: dataMap[subFieldId],
title: dataMap[mainFieldId],
}]);
}
}).catch(() => {
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.2.4. Call functions in didMount
Note to modify the unique identifier in parentheses (you need to set the unique identifier of the associated form component by default).
// 当页面渲染完毕后马上调用下面的函数,这个函数是在当前页面 - 设置 - 生命周期 - 页面加载完成时中被关联的。
export function didMount() {
this.getAssociationFormFirstData('associationFormField_lrq26sam');
}
2.3. Include data padding
2.3.1. Configuration page
2.3.2. Configure associated forms
Associate the form configured in 2.1 and set display fields.
2.3.3. Configure Data filling
Configure Data filling on demand.
2.3.4. Copy the following code to Page JS
No modification is required.
/**
* 获取关联表单设置默认值(默认第一个选项)
* @param associationFormField 需要设置默认值的关联表单组件唯一标识
*/
export function getAssociationFormFirstData(associationFormField = '') {
if (this.utils.isSubmissionPage() && associationFormField) {
const {
formUuid, // 关联表单
appType, // 应用 appType
formType, // 表单类型
mainFieldId, // 主要信息字段唯一标识
subFieldId, // 次要信息字段唯一标识
} = this.$(associationFormField).get('associationForm'); // 获取关联表单配置
const {
condition, // 筛选条件关系
rules = [], // 筛选条件
} = this.$(associationFormField).get('dataFilterRules'); // 获取关联表单筛选条件
const searchField = rules.map((item) => {
return {
key: item.id,
value: item.extValue === 'value' ? item.value : this.$(item.value).getValue(),
type: this.getType(item.componentType),
componentName: item.componentType,
operator: item.op,
};
});
const orderConfig = this.$(associationFormField).get('orderConfig') || []; // 获取关联表单排序条件
const dynamicOrder = {}; // 排序条件
orderConfig.forEach((item) => {
dynamicOrder[item.fieldId] = item.order === 'asc' ? '+' : '-';
});
const body = new URLSearchParams();
body.append('_csrf_token', this.getCsrfToken());
body.append('formUuid', formUuid);
body.append('manageUuid', formUuid);
body.append('appType', appType);
body.append('currentPage', 1);
body.append('page', 1);
body.append('pageSize', 20);
body.append('limit', 20);
body.append('logicOperator', condition);
body.append('searchField', JSON.stringify(searchField));
body.append('dynamicOrder', JSON.stringify(dynamicOrder));
fetch(`/${appType}/query/formProcInstData/getInstanceDatas.json`, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body,
}).then((data) => {
return data.json();
}).then(({ content }) => {
const { totalCount, values = [] } = content;
if (totalCount) {
const { dataMap = {}, formInstanceId = '', processInstanceId = '' } = values[0] || {};
this.$(associationFormField).setValue([{
appType,
formType,
formUuid,
instanceId: formInstanceId || processInstanceId,
subTitle: dataMap[subFieldId],
title: dataMap[mainFieldId],
}]);
this.associationFormDataFilling(associationFormField); // 触发关联表单数据填充
}
}).catch(() => {
this.utils.toast({
title: '数据获取失败',
type: 'error',
});
});
}
}
/**
* 触发关联表单数据填充
* @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.3.5. Call functions in didMount
Note to modify the unique identifier in parentheses (you need to set the default value and the unique identifier of the associated form component that triggers data filling).
// 当页面渲染完毕后马上调用下面的函数,这个函数是在当前页面 - 设置 - 生命周期 - 页面加载完成时中被关联的。
export function didMount() {
this.getAssociationFormFirstData('associationFormField_lrq3dp10');
}
3. Effect
3.1. Does not contain data padding
3.2. Include data padding
4. Try it online
5. Upgrade the new version of data filling
Save the fill conditions of the associated form again to upgrade to the new version of the data fill (the page needs to be saved again after the following operations).