方法一
- 子表自动回填
场景:合同主表选择“合同模板”的主表数据,并且返回“合同模板”一对多子表的多行数据。
实现这个需求需要配置两个对话框
一.查询”合同模板“主表数据的对话框
注意返回字段这个地方要返回一个主表数据的主键
在数据库内主从表数据的关系如下
可以看到,主表的其中的一条数据的id等于子表的ref_id_,我们可以根据返回主表一条数据的id来筛选子表中ref_id_对应的数据
二.查询”合同模板“子表数据的对话框
要注意的是子表数据对话框中要加入一个条件字段,选择外键(ref_id_),选择条件为等于,值来源为参数传入
三.新建一个表单,主表中起码要有一个对话框,主表对话框绑定刚才配置好的,查询“合同模板”主表数据对话框,设定返回值中返回一个数据对应的主键id
拉入子表,选中子表点击子表回填,绑定刚刚配置好的”合同模板“子表对话框
刚刚在设置子表对话框的时候加入了一个条件字段,这里我们绑定主表对话框返回主键id的字段
这样配置我们就可以做到根据主表返回的主键id来筛选对应的子表数据
- js代码实现
四.我们在表单引入脚本中加入js,当主表对话框选择了数据之后,子表对话框根据自己绑定的参数(如图,现在绑定的是主表主键id)并自动回填数据,js代码如下:
/** * 获取子表回填的数据 */ async function getFillBackSubTabData(){ //获取表单信息 let form = await getForm(); let expand = JSON.parse(form.expand); if(!expand || !expand.list){ return ; } let fillBackSubTabs = new Array(); for(let i = 0;i < expand.list.length; i++ ){ let ctrl = expand.list[i]; if(ctrl && ctrl.ctrlType && ctrl.ctrlType == "subtable" && ctrl.customDialogjson && ctrl.customDialogjson.custDialog && ctrl.customDialogjson.custDialog.alias){ fillBackSubTabs.push(ctrl); } } let subTabMap = {}; for(let i = 0 ; i < fillBackSubTabs.length ; i++){ subTabMap[fillBackSubTabs[i].name] = await getDatas(fillBackSubTabs[i]); } return subTabMap; } async function getForm(){ //预览页面 if(window.app.$route.name == 'previewForm'){ let formId = window.app.$route.params.formId; return new Promise((resolve,reject)=>{ window.app.$http.get("${form}/form/form/v1/getFormById?id="+formId).then(resp=>{ resolve(resp.data); }) }) }else{ //启动、审批页面,有formContent let formContent = getByComponentsName("formContent"); if(!formContent || !formContent.formKey){ window.app.$message.warning("获取表单信息失败"); return null; } let formKey = formContent.formKey; return new Promise((resolve,reject)=>{ window.app.$http.get("${form}/form/formServiceController/v1/getByFormKey?formKey="+formKey).then(resp=>{ resolve(resp.data); }) }) } } async function getDatas(ctrl){ let data = getOnlineFormData(); let condition = ctrl.customDialogjson.custDialog.conditions; let param = { pageBean:{ page:1, pageSize:-1, showTotal:false }, querys:[] } for(let i = 0; i < condition.length ;i++){ let bind = condition[i].bind; let bindData = data[bind.split(".")[2]]; if(!bindData){ continue; } let operation = ""; if(condition[i].condition == "EQ"){ operation = "EQUAL" }else if(condition[i].condition == "LK"){ operation = "LIKE" }else{ operation = condition[i].condition; } param.querys.push({ group:"subTabDialog", operation:operation, property:condition[i].field, relation:"OR", value:bindData }) } if(param.querys.length == 0){ return new Promise((resolve,reject)=>{ resolve([]); }) } let resp = await window.app.$http.get(`${window.context.form}/form/customDialog/v1/getByAlias?alias=${ctrl.customDialogjson.custDialog.alias}`); if(!resp || !resp.data || !resp.data.resultfield){ return new Promise((resolve,reject)=>{ resolve([]); }) } let dialogDef = resp.data; let mappingConf = ctrl.customDialogjson.custDialog.mappingConf; let resultField = JSON.parse(dialogDef.resultfield); let map = {}; //对话框返回值的字段名和target的映射 for(let i = 0;i<mappingConf.length ;i++){ let from = mappingConf[i].from; for(let j = 0;j<resultField.length ; j++){ if(resultField[j].comment == from){ map[resultField[j].field] = mappingConf[i].target; break; } } } let dialogDataResp = await window.app.$http.post(`${window.context.form}/form/customDialog/v1/getListData?mapParam=&alias=${ctrl.customDialogjson.custDialog.alias}`,param); if(!dialogDataResp || !dialogDataResp.data || !dialogDataResp.data.rows || dialogDataResp.data.rows.length == 0){ return new Promise((resolve,reject)=>{ resolve([]); }) } let rows = dialogDataResp.data.rows; let subTabDataList = []; rows.forEach(row=>{ let subTabDataOne = {} for(let key in row){ if(map.hasOwnProperty(key)){ let target = map[key]; for(let i = 0;i<target.length;i++){ if(target[i]){ subTabDataOne[target[i].split(".")[2]] = row[key]; } } } } subTabDataList.push(subTabDataOne); }) return new Promise((resolve,reject)=>{ resolve(subTabDataList); }) } function getByComponentsName(name) { function innerGetter(node) { if (node.$vnode && node.$vnode.tag && node.$vnode.tag.replace(/^vue-component-\d*-/g, "") == name) { return node; } if (node.$children && node.$children.length > 0) { for (let i = 0; i < node.$children.length; i++) { let rtn = innerGetter(node.$children[i]); if (rtn) return rtn; } } } return innerGetter(window.app) } function getOnlineFormData(){ let onlineForm = document.querySelector("[name='online-form']").__vue__; return onlineForm.data[Object.keys(onlineForm.data)[0]] } let dialog = document.querySelector("[model-name='data.zbjssj.dhk']").__vue__; let target = dialog.dialogConfirm; let data = getOnlineFormData(); dialog.dialogConfirm = function(){ target(); setTimeout(()=>{ getFillBackSubTabData().then(resp=>{ for(let key in resp){ window.app.$set(data,"sub_"+key,resp[key]) } }) },100) }
- 注意事项
自动回填的Js可复用,到js的最下层,按照图片部分修改,目前是取当前表单上的所有子表
1. 主表对话框绑定的字段
2. 如果多个子表,可以只反填其中一个,子表名称要用英文双引号括起来
示例:
3. 子表名称
方法二
- 补充其他写法
若上面的不生效,可以使用下面这种方法
- 配置关联查询,需要配置条件字段,作为入参的参数
- 点击预览关联查询,此时用开发者工具能看到请求的接口地址以及参数
- 获取到接口地址以及参数后,就可以开始编写js代码,参考代码如下,其中post请求就是用关联查询获取数据
let vm = document.getElementsByName("online-form")[0].__vue__; vm.$watch("data.zbsjzddc.djbh", function (newV) { if (newV) { //清空子表 vm.data.zbsjzddc.sub_zddcxx = []; //请求子表数据 let params = [{ key: "F_xmmc", value: newV }]; let url = `${window.context.form}/form/customQuery/v1/doQuery?alias=xmcyda&page=1`; vm.$http.post(url, params).then((resp) => { debugger; if (resp.data.rows.length > 0) { resp.data.rows.forEach((item, index) => { //初始化子表,每次循环都先放入一条空的子表行数据 let subinit = { ...vm.data.zbsjzddc.initData.zddcxx }; vm.data.zbsjzddc.sub_zddcxx.push(subinit); //对应子表字段 vm.data.zbsjzddc.sub_zddcxx[index].xx1 = item.F_xmmc; vm.data.zbsjzddc.sub_zddcxx[index].xx2 = item.F_xm; vm.data.zbsjzddc.sub_zddcxx[index].xx3 = item.F_js; }); vm.$message.success(`获取子表数据成功!`); } else { vm.$message.success(`无相关数据!`); } }); } else { //newV为空时清空子表 vm.data.zbsjzddc.sub_zddcxx = []; vm.$message.success(`清空成功!`); } });