自定义表单控件 - 扩展出一个选择框
注:开窗功能实现,具体可看本人文章:EKP其它/EKPSQL工具_Liquid-Li的博客-CSDN博客
1、实现效果



2、具体实现 - 配置xml扩展(WebContent/WEB-INF/KmssConfig/xp/xform/plugin.xml)
2、具体实现 - 前端
WebContent/xp/xform/designer/relation_choose/relation_choose.js
/* 1、菜单栏配置 */
Designer_Config.operations['xpRelationChoose'] = {lab : "5",imgIndex : 58,// sys/xform/designer/style/css/editor-icon-m_z.png中从上往下数的索引位置,用于菜单的图标展示title : "XP选择框",// 菜单图标名称run : function(designer) {// 点击菜单控件图标时执行的方法,一般类似这样写即可designer.toolBar.selectButton('xpRelationChoose');},type : 'cmd',order: 1001,// 页签里面的排序顺序,小前大后,可为小数shortcut : '',select : true,line_splits_font: true,cursorImg : 'style/cursor/relationChoose.cur'// 鼠标点击菜单图标之后的鼠标手势加图标的展示
};
Designer_Config.buttons.form.push("xpRelationChoose");// 放入菜单选项卡(control为"扩展"选项卡)
Designer_Menus.tool.menu['xpRelationChoose'] = Designer_Config.operations['xpRelationChoose'];// 放入右键菜单/* 2、控件属性配置 */
Designer_Config.controls["xpRelationChoose"] = {type : "xpRelationChoose",// 和service配置解析类型一致storeType : 'field',inherit : 'base',container : false,onDraw : _Designer_Control_XpRelationChoose_OnDraw,// 拖动控件到表单中展示js方法drawMobile : _Designer_Control_RelationChoose_DrawMobile,drawXML : _Designer_Control_XpRelationChoose_DrawXML,// 控件值xmlonInitialize : _Designer_Control_XpRelationChoose_OnInitialize,onInitializeDict : _Designer_Control_DisplayText_OnInitializeDict,initDefaultValueAfterPaste :_Designer_Control_XpRelationChoose_initDefaultValueAfterPaste,// 粘贴后初始化默认值implementDetailsTable : true,// 是否允许在明细表中展示resizeMode : 'onlyWidth', // 尺寸调整模式(onlyWidth, onlyHeight, all, no)info : {name : "XP选择框",// 双击控件开窗时上方的标题//preview : "mutiTab.png"},attrs : {// 双击控件弹出的属性框参数label : Designer_Config.attrs.label,required: {text: Designer_Lang.controlAttrRequired,value: "true",type: 'checkbox',checked: false,show: true},width : {text: Designer_Lang.controlAttrWidth,value: "120",type: 'text',show: true,validator: Designer_Control_Attr_Width_Validator,// 修改参数的校验方法checkout: Designer_Control_Attr_Width_Checkout// 提交时候的校验方法},summary: {text: Designer_Lang.controlAttrSummary,value: "true",type: 'checkbox',checked: false,synchronous: true,//多表单是否同步show: true},encrypt : Designer_Config.attrs.encrypt,/* 以下为新增的参数 */freeEdit: {text: "自由编辑",value: "true",type: 'checkbox',checked: false,show: true},editCallbackFunName: {text : "编辑回调",hint:"回调参数(obj, flagid, value)",value : 'editCallback_' + new Date().getTime(),type : 'text',required: false,show : true},openWinFunName: {text : "开窗函数",hint: "函数参数(obj)",value : 'openWinFun_' + new Date().getTime(),type : 'text',required: true,// lang: true,// 值是否加入多语言show : true,convertor: function (name, attr, value, values) {if (!value) {return 'openWinFun_' + new Date().getTime();}return value;}},clearCallbackFunName: {text : "清空回调",hint: "回调参数(obj, flagid)",value : 'clearCallback_' + new Date().getTime(),type : 'text',required: false,show : true},clearFieldId: {text : "联动清空",hint: "1、栏位ID,分号分隔 2、明细表栏位:明细表ID.栏位ID",value : '',type : 'textarea',show : true},notNullCheck: {text : "非空检查",hint: "1、栏位ID,分号分隔 2、明细表栏位:明细表ID.栏位ID",value : '',type : 'textarea',show : true},}
};function _Designer_Control_XpRelationChoose_OnInitialize(){this.onInitializeDict();
}function _Designer_Control_XpRelationChoose_initDefaultValueAfterPaste(values){// values.openWinFunName = "";return values;
}function _Designer_Control_XpRelationChoose_OnDraw(parentNode, childNode) {var values = this.options.values;if (this.options.values.id == null){this.options.values.id = "fd_" + Designer.generateID();}var domElement = _CreateDesignElement('div', this, parentNode, childNode);domElement.className="xform_relation_choose";domElement.style.display="inline";var values = this.options.values;var inputDom = document.createElement('input');inputDom.className="inputsgl";inputDom.label = _Get_Designer_Control_Label(this.options.values, this);domElement.style._widthUnit = "px";if (this.options.values.width ) {if( this.options.values.width.toString().indexOf('%') > -1){inputDom.style.width = this.options.values.width;domElement.style._widthUnit = "%";}else{inputDom.style.width = this.options.values.width+"px";}}else{values.width = "120";inputDom.style.width=values.width+"px";}domElement.style._width = $(inputDom).width();domElement.appendChild(inputDom);if(values.required == 'true') {$(domElement).append('*');}$(domElement).append(' ');inputDom.id = this.options.values.id;if (values.required == "true") {$(inputDom).attr("required", "true");$(inputDom).attr("_required", "true");} else {$(inputDom).attr("required", "false");$(inputDom).attr("_required", "false");}if(values.summary == "true"){$(inputDom).attr("summary", "true");}else{$(inputDom).attr("summary", "false");}if (values.width) {$(inputDom).attr("width", values.width);}/* 以下为新增的参数 */if (values.freeEdit) {$(inputDom).attr("freeEdit" , values.freeEdit);}if (values.editCallbackFunName) {$(inputDom).attr("editCallbackFunName" , values.editCallbackFunName);}if (values.openWinFunName) {$(inputDom).attr("openWinFunName" , values.openWinFunName);}if (values.clearCallbackFunName) {$(inputDom).attr("clearCallbackFunName" , values.clearCallbackFunName);}if (values.clearFieldId) {$(inputDom).attr("clearFieldId" , values.clearFieldId);}if (values.notNullCheck) {$(inputDom).attr("notNullCheck" , values.notNullCheck);}var a = document.createElement("a");a.innerText = Designer_Lang.relation_choose_button + "(xp)";domElement.appendChild(a);
}function _Designer_Control_XpRelationChoose_DrawXML() {var values = this.options.values;// 如果一个控件对应多个值,需要补充这两个属性,用于流程文档提交业务处理var customElementProperties = {};customElementProperties.isMultiVal = "true";customElementProperties.controlId = values.id;buf=[];buf.push( ' \r\n');buf.push(_Designer_Control_RelationChoose_DrawXML_HiddenPropertyTemp(values.id+"_text",values.label + Designer_Lang.controlDisplayValueMessage,this.type,customElementProperties,values));return buf.join('');
}function _Designer_Control_RelationChoose_DrawXML_HiddenPropertyTemp(name,label,businessType,customElementProperties,values,isStore){var buf = [];customElementProperties.isShow = 'false';buf.push( ' 0 && values.summary == 'true'){//摘要汇总buf.push('summary="true" ');}buf.push('/>\r\n');return buf.join('');
}
WebContent/xp/xform/designer/relation_choose/relation_choose_display.jsp
<%@ page language="java" pageEncoding="UTF-8" contentType="text/html; charset=UTF-8"%>
<%@ include file="/sys/ui/jsp/common.jsp" %>
<%-- 编辑、选择、清空 --%><%--编辑--%>Edit <%--选择--%> <%--清空--%> <%-- 公用js --%>
WebContent/xp/xform/designer/relation_choose/relation_choose_script.js
/*** 点击"选择"时触发* @author liquid* @date 2023年4月5日* @param {object} obj "选择"按钮的dom* @return {void}*/
function xpRelationChoose_sqlOpenWin(obj) {// liquid 2023年4月5日16:46:38let paramsStr = $(obj).closest(".relationChoose_operation").attr("params").replace(/quot;/g, "\"");let params = JSON.parse(paramsStr);let openWinFunName = params["openWinFunName"];let openWinFun = window[openWinFunName];let notNullCheckIds = params["notNullCheck"];if (typeof openWinFun === "function" &&xpDesigner_notNullCheckBeforeOpen(notNullCheckIds, obj)) {openWinFun(obj);} else if (typeof openWinFun !== "function"){alert(xp_lang("0022_key") + openWinFunName );}
}/*** 点击"清空"时触发* @author liquid* @date 2023年4月5日* @param {object} obj "清空"按钮的dom* @return {void}*/
function xpRelationChoose_clearValue(obj) {// liquid 2023年4月5日16:46:38let flagid = $(obj).closest("xformflag").attr("flagid");if (isNotEmpty(flagid)) {clearField(flagid);exeValueChange(flagid);// 执行自身值变化事件// 执行一次校验// var myid = $(obj).closest("xformflag").attr("property");// var validation = $GetFormValidation(document.forms[0]);// if(myid && validation && $("input[name='"+myid+"']").length > 0){// validation.validateElement($("input[name='"+myid+"']")[0]);// }}// 联动清空let paramsStr = $(obj).closest(".relationChoose_operation").attr("params").replace(/quot;/g, "\"");let params = JSON.parse(paramsStr);let clearFieldId = params["clearFieldId"];if (isNotEmpty(clearFieldId)) {let relativeFlagidArr = clearFieldId.split(";");for (const relativeFlagid of relativeFlagidArr) {if (isEmpty(relativeFlagid)) {continue;}// 明细表中的控件if (relativeFlagid.includes(".")) {xpRelationChoose_clearInDetailList(relativeFlagid, obj);continue;}// 非明细表控件clearField(relativeFlagid);}}// 清空后回调let clearCallbackFunName = params["clearCallbackFunName"];let clearCallbackFun = window[clearCallbackFunName];if (typeof clearCallbackFun === "function") {clearCallbackFun(obj, flagid);}
}/*** 联动清空明细表栏位* @author liquid* @date 2023年4月5日* @param {string} flagId 栏位ID(明细表ID.栏位ID)* @param {object} obj "清空"按钮的dom* @return {void}* @private*/
function xpRelationChoose_clearInDetailList(flagId, obj) {let dotIndex = flagId.indexOf(".");let detailListId = flagId.substring(0, dotIndex);let detailObj = getDetailObj(detailListId);let fieldId = flagId.substring(dotIndex + 1);/* 选择框与flagId在同一明细表 */let tableId = $(obj).closest("table").attr("id");if (isNotEmpty(tableId) && tableId.includes(detailListId)) {let rowIndex = detailObj.getRowIndexByDom(obj);detailObj.clearSingle(rowIndex, fieldId);exeValueChange(detailObj.getFlagidInDetailList(rowIndex, fieldId));return;}/* 选择框与flagId不在同一明细表 */detailObj.clearColumn(fieldId);for (let i = 0; i < detailObj.getRowLength(); i++) {exeValueChange(detailObj.getFlagidInDetailList(i, fieldId));}
}/*** 点击"编辑"时触发* @author liquid* @date 2023年4月5日* @param {object} obj "编辑"按钮的dom* @return {void}*/
function xpRelationChoose_freeEdit(obj) {let flagid = $(obj).closest("xformflag").attr("flagid");let value = `${window.prompt()}`;let paramsStr = $(obj).closest(".relationChoose_operation").attr("params").replace(/quot;/g, "\"");let params = JSON.parse(paramsStr);if (isNotEmpty(value)) {setValueById(flagid, value);const editCallbackFunName = params["editCallbackFunName"];const editCallbackFun = window[editCallbackFunName];if (typeof editCallbackFun === "function") {editCallbackFun(obj, flagid, value);}}
}
WebContent/xp/xform/designer/designerUtil.js
/*** 某些栏位的非空检查* @author liquid* @date 2023年4月5日* @param {string} notNullCheckIds 需判空的栏位ID字符串* @param {object} obj 触发元素的dom* @return {boolean} 是否全部非空* @private*/
function xpDesigner_notNullCheckBeforeOpen(notNullCheckIds, obj) {let notNullCheckIdArr = notNullCheckIds.split(";");for (const notNullCheckId of notNullCheckIdArr) {if (isEmpty(notNullCheckId)) {continue;}let xformLabel = getXFormLabel(notNullCheckId);let dotIndex = notNullCheckId.indexOf(".");/* 待判断的栏位在明细表 */if (dotIndex > -1) {let detailListId = notNullCheckId.substring(0, dotIndex);let detailObj = getDetailObj(detailListId);let fieldId = notNullCheckId.substring(dotIndex + 1);// 选择框与flagId在同一明细表let tableId = $(obj).closest("table").attr("id");if (isNotEmpty(tableId) && tableId.includes(detailListId)) {let rowIndex = detailObj.getRowIndexByDom(obj);let value = detailObj.getDataSingle(rowIndex, fieldId);if (xpDesigner_isNull(value)) {alert(xp_lang("0023_key") + xformLabel);return false;}} else {// 选择框与flagId不在同一明细表let dataArr = detailObj.getDataByColumnId(fieldId);if (xpDesigner_isArrNull(dataArr)) {alert(xp_lang("0024_key") + xformLabel);return false;}}}/* 待判断的栏位不在明细表 */if (dotIndex < 0) {let value = getValueById(notNullCheckId);if (xpDesigner_isNull(value)) {alert(xp_lang("0023_key") + xformLabel);return false;}}}return true;
}
function xpDesigner_isNull(var1) {return isEmpty(var1) || "{};[];[\"\"];[\"\",\"\"];[null];[null,null]".includes(JSON.stringify(var1));
}
function xpDesigner_isArrNull(varArr1) {for (const var1 of varArr1) {if (xpDesigner_isNull(var1)) {return true;}}return false;
}
2、具体实现 - 前端(开窗)
资料选择器 Select Data
{{getSelectDisplayValue(p_value)}}{{getSelectDisplayValue(p_value)}}
查无数据×
window.Com_Parameter = pageParent()["Com_Parameter"];
let vue_outer_div;
const pageParams = getPageParams();
console.log({pageParams});
let firstResult = 0;
let maxResults = Number(pageParams["maxResults"] || 20);// 默认每页20条记录
let lang = pageParams["lang"] || getLang();
let firstQuery = pageParams["firstQuery"] || "1";// 窗口打开后是否自动执行查询
let mainCallbackName = pageParams["mainCallbackName"] || "";
let inParamsWithSearch = pageParent(window)[pageParams["inParamsWithSearchKey"]] || {};// 搜索框传入动态默认参数
pageParent(window)[pageParams["inParamsWithSearchKey"]] = undefined;
let inParamsNotWithSearch = pageParent(window)[pageParams["inParamsNotWithSearchKey"]] || {};// 搜索框传入动态默认参数
pageParent(window)[pageParams["inParamsNotWithSearchKey"]] = undefined;
const parentCallback = pageParams["parentCallback"];// 待回调的父页面函数名(点击行、点击确定)
lang = lang.toUpperCase();
let sqlDefinitionFdId = "";
let sqlKey = pageParams["sqlKey"];
let winType = pageParams["winType"];// 窗口类型(single单、multiple多选)
let selectedData = pageParent(window)[pageParams["selectedDataKey"]] || [];// 已选择的数据
pageParent(window)[pageParams["selectedDataKey"]] = undefined;
let selectedData_copy = JSON.parse(JSON.stringify(selectedData));
let searchValue;
let search;
let search_copy;
let titles;
let winTitle;
let rightMenu_itemArr;
let historyData = {ekp: {}}
let rowData4RightMenu;/* 对传入参数进行处理 */
let inParamsFunc = inParams[sqlKey];
if (inParamsFunc) {if (!inParamsWithSearch || JSON.stringify(inParamsWithSearch) === "{}") {let func = inParamsFunc["withSearch"];if (typeof func === "function") {inParamsWithSearch = func() || {};}}if (!inParamsNotWithSearch || JSON.stringify(inParamsNotWithSearch) === "{}") {let func = inParamsFunc["notWithSearch"];if (typeof func === "function") {inParamsNotWithSearch = func() || {};}}
}/* 页面初始化 */
$(() => {initConfig();// 设置开窗配置vue_outer_div = new Vue({el: '#outer_div',data: {lang: lang,search: search[lang],titles: titles[lang],nowData: [],total: 999,nowPage: 1,lastPageIndex: 0,winType: winType,multipleSelectedData: selectedData,// 多选状态下:已选数据rightMenu: {// 右键菜单数据对象visible: false,top: 0,left: 0,},rightMenu_itemArr: rightMenu_itemArr[lang],data_div_height: 0,noDataShow: false,},methods: {isEmpty: isEmpty,isNotEmpty: isNotEmpty,dataRowClass: dataRowClass,getSelectDisplayValue: getSelectDisplayValue,getSelectTrueValue: getSelectTrueValue,getTodayStr: getTodayStr,hideColumn: hideColumn,totalWidth : totalWidth},computed: {},watch: {rightMenu(value) {if (value.visible) {document.body.addEventListener('click', closeRightMenu)} else {document.body.removeEventListener('click', closeRightMenu)}}}});// 执行查询if (firstQuery === "1") {searchData(true, 0);}// 设置数据区高度let interval_setDivHeight = setInterval(() => {let pagingOuterDiv_top = $("#paging_outer_div")[0].offsetTop;let dataDiv_top = $("#data_div")[0].offsetTop;if (pagingOuterDiv_top !== 0) {vue_outer_div.$data.data_div_height = pagingOuterDiv_top - dataDiv_top - 5;clearInterval(interval_setDivHeight);}}, 200)
})/*** 初始化配置* @author liquid* @date 2022年11月15日*/
function initConfig() {const _path_in = "xp/modeling/app/it/actions/XpEkpSqlDefinitionAction.do?method=getOpenWinConfigJson";const _data_in = {key: sqlKey}let openWinConfigJson;ajaxAction(_path_in, _data_in, false, {success: (res)=>{if (res.status !== "success") {errorHandler(res); return;}// 业务逻辑sqlDefinitionFdId = res["fdId"];openWinConfigJson = JSON.parse(res["openWinConfigJson"]);console.log("openWinConfigJson",openWinConfigJson);},error: (error)=>{errorHandler(error);}})search = setDefaultParams(openWinConfigJson.search || {});search_copy = JSON.parse(JSON.stringify(search));// 列标题titles = openWinConfigJson.titles || {"ZH-CN":[], "EN-US":[]};// 窗口标题 - 移动端winTitle = openWinConfigJson.winTitle;document.title = winTitle[lang];// 窗口标题 - pc端let setTitle = window.parent["setWinCenterWithMaskTitle"];if (typeof setTitle === "function") {setTitle(winTitle[lang]);}// 右键菜单rightMenu_itemArr = openWinConfigJson.rightMenu_itemArr || {"ZH-CN":[], "EN-US":[]};// search = {// "ZH-CN": [// [// {// "name": "id",// "title": "ID",// "type": "text",// "items": [],// "default": "",// "placeholder": "组织架构对象ID",// "fuzzy": "Y"// },// {// "name": "org_type",// "title": "类型",// "type": "dropdown",// "items": [// "机构|1",// "部门|2",// "岗位|4",// "人员|8",// "群组|16",// "通用岗位|32"// ],// "default": "8",// "placeholder": "",// "fuzzy": "N"// }// ],// [// {// "name": "name",// "title": "名称",// "type": "text",// "items": [],// "default": "",// "placeholder": "",// "fuzzy": "Y"// },// {// "name": "name_pinyin",// "title": "名称拼音",// "type": "text",// "items": [],// "default": "",// "placeholder": "",// "fuzzy": "Y"// }// ]// ],// "EN-US": [// [// {// "name": "id",// "title": "ID",// "type": "text",// "items": [],// "default": "",// "placeholder": "Organization ID",// "fuzzy": "Y"// },// {// "name": "org_type",// "title": "Type",// "type": "dropdown",// "items": [// "Company|1",// "Dept.|2",// "Post|4",// "Personnel|8",// "Group|16",// "Universal Post|32"// ],// "default": "8",// "placeholder": "",// "fuzzy": "N"// }// ],// [// {// "name": "name",// "title": "Name",// "type": "text",// "items": [],// "default": "",// "placeholder": "",// "fuzzy": "Y"// },// {// "name": "name_pinyin",// "title": "Name Pinyin",// "type": "text",// "items": [],// "default": "",// "placeholder": "",// "fuzzy": "Y"// }// ]// ]// };// search_copy = JSON.parse(JSON.stringify(search));// titles = {// "ZH-CN": [// {// "label": "ID",// "width": "25%"// },// {// "label": "类型",// "width": "5%"// },// {// "label": "名称",// "width": "25%"// },// {// "label": "名称拼音",// "width": "45%"// }// ],// "EN-US": [// {// "label": "ID",// "width": "25%"// },// {// "label": "Type",// "width": "5%"// },// {// "label": "Name",// "width": "25%"// },// {// "label": "Name Pinyin",// "width": "45%"// }// ]// }// rightMenu_itemArr = {// "ZH-CN": [// {// title: "选项1"// },// {// title: "选项2"// },// {// title: "选项3"// }// ],// "EN-US": [// {// title: "item-1"// },// {// title: "item-2"// },// {// title: "item-3"// }// ],// };
}/*** 计算数据区外层宽度* @author zengwenfu* @date 2022年12月14日* @returns {string}*/
function totalWidth(){let mWidth = 0;if (titles["ZH-CN"][0].width.indexOf("px") > -1) {for (var i = 0; i < titles["ZH-CN"].length; i++) {mWidth += parseInt(titles["ZH-CN"][i].width);}return "width:"+mWidth+"px";}return "width:100%";
}/*** 斑马线* @author liquid* @date 2022年11月18日* @param {number}index 行下标* @returns {string}*/
function dataRowClass(index){return index % 2 === 0 ? "data_tr_0" : "data_tr_1";
}/*** 行点击事件* @author liquid* @date 2022年11月18日* @param {array}rowData 触发行的数据* @param {number}rowIndex 触发行的行下标* @param event 触发事件对象*/
function dataRowClick(rowData, rowIndex, event) {let selectTxt = window.getSelection().toString();if (isNotEmpty(selectTxt)) {// 避免选择文本时也触发点击事件的逻辑return;}const targetClassName= event.target.className;if (isEmpty(targetClassName) ||!"multiple_choose_single;data_td".includes(targetClassName)) {// 只有点击行的时候,才执行以下代码,避免在多选状态下点击checkbox时也触发return;}const rtnData = makeRowData(rowData);/* 单选 */if (winType === "single") {let isCloseWin = rowConfirm_callback(rtnData, "rowClick");if (!isCloseWin) {// 不关闭开窗,以下回调不执行return;}if(window.opener){window.opener.postMessage(rtnData);}let mainCallBack = window.parent[mainCallbackName];if (mainCallBack) {mainCallBack(rtnData.sqlData);}closeWin();}/* 多选 */if (winType === "multiple") {const check = $(".multiple_choose_single > input")[rowIndex];setChecked([rowIndex], !check.checked);// 回调let isCloseWin = rowConfirm_callback(rtnData, "rowClick");if (isCloseWin) {closeWin();}}
}/*** 构造被点击行的数据* @author liquid* @date 2022年12月14日* @param rowData*/
function makeRowData(rowData) {const json = {};for (let i = 0; i < rowData.length; i++) {json[titles["ZH-CN"][i].valueKey] = rowData[i];}return {"sqlData": {arr: rowData,json: json},}
}/*** 行鼠标右键事件* @author liquid* @date 2022年12月14日* @param {array}rowData 触发行的数据* @param {number}rowIndex 触发行的行下标* @param event 触发事件对象*/
function dataRowRightClick(rowData, rowIndex, event) {rowData4RightMenu = makeRowData(rowData);event.preventDefault();openRightMenu(event);
}/*** 显示数据细节* @author zengwenfu* @param rowData* @returns {string}*/
function showDetail(rowData){let str = "";for(let i = 0;i < rowData.length; i++){let data = rowData[i] ? rowData[i] : "";str += titles[lang][i].label + " :" + data + "\n";}return str;
}/*** 打开自定义右键菜单* @author liquid* @date 2022年12月14日* @param event 触发事件对象*/
function openRightMenu(event) {vue_outer_div.$data.rightMenu = {left: event.clientX,top: event.clientY,visible: true};
}/*** 关闭自定义右键菜单* @author liquid* @date 2022年12月14日*/
function closeRightMenu() {vue_outer_div.$data.rightMenu = {visible: false}
}/*** [多选]选中或取消选中之后执行一些操作* @author liquid* @date 2022年11月22日* @param indexes 选中或取消选中的下标数组* @param checked 选中(true),取消选中(false)*/
function setChecked(indexes, checked) {for (const index of indexes) {const checkbox = $(".multiple_choose_single > input")[index];$(checkbox).prop("checked", checked);const addData = JSON.parse(JSON.stringify(vue_outer_div.nowData[index]));if (checked && !JSON.stringify(vue_outer_div.multipleSelectedData).includes(JSON.stringify(addData))) {// 是选中vue_outer_div.multipleSelectedData.push(addData);}else if (!checked){// 取消选中vue_outer_div.multipleSelectedData = delElement(vue_outer_div.multipleSelectedData, addData);}}
}/*** 获取下拉菜单、单选按钮、多选按钮的显示值* @author liquid* @date 2022年11月18日* @param {string}str* @returns {*}*/
function getSelectDisplayValue(str) {return str.includes("|") ? str.substring(0, str.indexOf('|')) : str;
}/*** 获取下拉菜单、单选按钮、多选按钮的实际值* @author liquid* @date 2022年11月18日* @param {string}str* @returns {*}*/
function getSelectTrueValue(str) {return str.includes("|") ? str.substring(str.indexOf('|') + 1) : str;
}/*** 获取今日日期字符串* @author liquid* @date 2022年11月18日* @param {string}date 传入"today"获取的是今日的格式化日期字符串* @returns {null|string|*}*/
function getTodayStr(date) {if (isEmpty(date)) {return null;}return date === "today" ? xp_formatDateTime(new Date(), "Y-M-D") : date;
}/*** 下拉菜单值变化事件* @author liquid* @date 2023年2月19日* @param event*/
function dropdownChange(event) {queryClick();
}/*** 单选按钮点击事件* @author liquid* @date 2022年11月18日* @param event*/
function radioClick(event) {const elements = $("[name=" + event.target.name + "]");for (let i = 0; i < elements.length; i++) {if (i !== Number(event.target.dataset.index)) {$(elements[i]).attr("checked", false);}}queryClick();
}/*** 多选按钮点击事件* @author liquid* @date 2023年2月19日* @param event*/
function checkboxClick(event) {queryClick();
}/*** 若url传入搜索框默认值,则重设搜索框默认值* @author liquid* @date 2022年11月14日*/
function setDefaultParams(search) {const searchTemp = JSON.parse(JSON.stringify(search));for (const e1 of searchTemp[lang]) {for (const e2 of e1) {const value = inParamsWithSearch[e2.name];e2.default = isNotEmpty(value) ? value : e2.default;}}return searchTemp;
}/*** 获取搜索框中的输入值(包括隐藏的搜索参数)* @author liquid* @date 2022年11月14日*/
function getSearchValue() {const searchConfig = search[lang];const rtn = {};for(const i_value of searchConfig) {for (const j_value of i_value) {if ("text;dropdown;date".includes(j_value.type)) {let value = $("[name='"+ j_value.name +"']").val();value = isEmpty(value) ? "" : value;rtn[j_value.name] = j_value.fuzzy === "Y" ? "%" + value + "%" : value;j_value.default = value;}else if (j_value.type === "radio") {let value = $("input:radio[name='" + j_value.name + "']:checked").val();value = isEmpty(value) ? "" : value;rtn[j_value.name] = j_value.fuzzy === "Y" ? "%" + value + "%" : value;j_value.default = value;}else if (j_value.type === "checkbox") {const values = [undefined];// 放一个空值,防止传入空数组导致接口调用失败const checkboxes = $("input:checkbox[name='"+ j_value.name +"']:checked");for (const e of checkboxes) {values.push($(e).val())}rtn[j_value.name] = values;j_value.default = values.join(";");}}}for (const key in inParamsNotWithSearch) {rtn[key] = inParamsNotWithSearch[key];}return rtn;
}/*** 搜索区域键入事件* @author liquid* @date 2022年11月18日* @param event*/
function outerDivKeydown(event) {if (event.key === "Enter") {searchData(true, 0);}
}/*** 查询点击事件* @author liquid* @date 2022年11月18日*/
function queryClick() {searchData(true, 0);
}/*** 重置点击事件* @author liquid* @date 2022年11月18日*/
function resetClick() {// 清空本次的历史数据for (const key in historyData) {historyData[key] = {};}search = JSON.parse(JSON.stringify(search_copy));vue_outer_div.search = search[lang];vue_outer_div.multipleSelectedData = JSON.parse(JSON.stringify(selectedData_copy));setTimeout(function() {// 延迟搜索,避免数据还没渲染完就去拿值searchData(true, 0);}, 200)
}/*** 确定点击事件* @author liquid* @date 2022年11月18日*/
function confirmClick() {/* 非多选,不执行 */if (winType !== "multiple") {return;}const sqlData = {arr: vue_outer_div.multipleSelectedData, json: {}, arr_str: [], json_str: {}, json_arr: []};/* sqlData.json & sqlData.json_str & json_arr */const titlesArr = titles["ZH-CN"];for (let i = 0; i < sqlData.arr.length; i++) {for (let j = 0; j < titlesArr.length; j++) {const valueKey = titlesArr[j].valueKey;const arr = sqlData.json[valueKey] || [];arr.push(sqlData.arr[i][j]);sqlData.json[valueKey] = arr;sqlData.json_str[valueKey] = arr.join(";");}}// sqlData.arr_strfor (let i = 0; i < sqlData.arr.length; i++) {for (let j = 0; j < sqlData.arr[i].length; j++) {sqlData.arr_str[j] = (sqlData.arr_str[j] || "") + sqlData.arr[i][j] + ";";}}for (let i = 0; i < sqlData.arr.length; i++) {sqlData.arr_str[i] = delLastChar(sqlData.arr_str[i], 1);}// json_arrlet json_arr = [];for (let i = 0; i < sqlData.arr.length; i++) {let tempArr = sqlData.arr[i];let tempJson = {};for (let j = 0; j < tempArr.length; j++) {const valueKey = titlesArr[j].valueKey;tempJson[valueKey] = tempArr[j];}json_arr.push(tempJson);}sqlData.json_arr = json_arr;/* 回传数据 */const rtnData = {sqlData: sqlData}/* 回调 */let isCloseWin = rowConfirm_callback(rtnData, "confirmClick");if (!isCloseWin) {// 不关闭开窗,以下回调不执行return;}if(window.opener){window.opener.postMessage(rtnData);}let mainCallBack = window.parent[mainCallbackName];if (mainCallBack) {mainCallBack(rtnData.sqlData);}closeWin();
}/*** 集中处理各类型回调函数* @author liquid* @date 2022年12月9日* @param rtnData 回传数据* @param clickType 点击类型(rowClick点击行\confirmClick点击确定)* @return {boolean} 开窗是否可关闭*/
function rowConfirm_callback(rtnData, clickType) {const func1 = window.opener ? window.opener[parentCallback] || "" : "";let func2 = selfCallback[sqlKey] || "";func2 = func2 ? func2[clickType] : "";const canBeClosed = (winType === "single" && clickType === "rowClick") ||(winType === "multiple" && clickType === "confirmClick");// 回调(函数在父页面)if (typeof func1 == "function") {const rtn1 = func1(rtnData);if (rtn1.code === 0) {if (isNotEmpty(rtn1.msg)) alert(rtn1.msg);}else if (canBeClosed){return true;}}else if (typeof func2 == "function") {// 回调(函数在开窗页面)const bool = func2(rtnData);if (bool && canBeClosed) {return true;}}else if (canBeClosed) {return true;}return false;
}/*** 右键菜单回调* @author liquid* @date 2022年12月14日*/
function rightMenu_callback(callbackIndex) {const funcArr = rightMenuCallback[sqlKey] || [];let callbackRtn = false;if (funcArr[callbackIndex]) {callbackRtn = funcArr[callbackIndex](rowData4RightMenu || []);}else {alert("未配置该选项的回调函数");}if (callbackRtn) {closeWin();}
}/*** 多选取消已选* @param data* @param rowIndex* @param event*/
function cancelSelectedData(data, rowIndex, event) {let selectTxt = window.getSelection().toString();if (isNotEmpty(selectTxt)) {// 避免选择文本时也触发点击事件的逻辑return;}vue_outer_div.multipleSelectedData = delElement(vue_outer_div.multipleSelectedData, data);
}/*** 关闭开窗* @author liquid* @date 2023年2月19日*/
function closeWin() {// 移动端window.close();// pc端let closeFunc = window.parent.closeWinCenterWithMask;if (typeof closeFunc === "function") {closeFunc();}
}function changeToWin() {window.open(document.location.href);window.onmessage = function(e) {const sqlData = e.data.sqlData;console.log(sqlData);if (sqlData !== null && sqlData !== undefined) {vue_outer_div.$data.multipleSelectedData = sqlData.arr;}}
}/*** 导出开窗数据(查询条件下的全部数据)* @author zengwenfu* @date 2022年12月13日*/
function exportData() {let searchStr = getSearchValue();let exportTitle = [];for (let i = 0; i < titles[lang].length; i++) {exportTitle.push(titles[lang][i].label);}// 调接口拿数据loading(true);ajaxActionPms("xp/modeling/app/it/actions/XpEkpSqlAction.do?method=executeQuery", {key: sqlKey,params: searchStr}).then((res)=>{if (res.status !== "success") { errorHandler(res); return; }// 成功回调export2Excel(res.queryData, exportTitle, winTitle[lang]);loading(false);}).catch((error)=>{errorHandler(error);})
}/*** 获取第一页数据* @author liquid* @date 2022年11月14日*/
function firstPageClick() {searchData(true, 0);
}/*** 获取上一页数据* @author liquid* @date 2022年11月14日*/
function pageUpClick() {const index = firstResult - maxResults;if (index >= 0) {searchData(false, index);}
}/*** 获取下一页数据* @author liquid* @date 2022年11月14日*/
function pageDownCLick() {const index = firstResult + maxResults;if (index < vue_outer_div.total) {searchData(false, index);}
}/*** 获取最后一页数据* @author liquid* @date 2022年11月14日*/
function lastPageClick() {const lastLeft = vue_outer_div.total % maxResults;let index = vue_outer_div.total - (lastLeft === 0 ? maxResults : lastLeft);searchData(false, index);
}/*** 多选时点击[全选]触发事件* @author liquid* @date 2022年11月21日*/
function multipleChooseAll() {const multipleCheck = $("#multiple_choose_all > input:checked");setChecked(new Array(maxResults).keys(), multipleCheck.length > 0);
}/*** 判断是否需要隐藏列* @author liquid* @date 2022年11月18日*/
function hideColumn(index) {const width = titles["ZH-CN"][index].width;return "0;0px;0PX;0px;0Px;0pX;0vw;0VW;0Vw;0vW;0%".includes(width);
}/*** 判断是否已全选* @author liquid* @date 2022年11月22日* @returns {boolean} 是否已全选*/
function isAllSelected() {let isAllSelected = true;const selectedDataStr = JSON.stringify(vue_outer_div.multipleSelectedData);for (let i = 0; i < vue_outer_div.nowData.length && isAllSelected; i++) {const nowDataRowStr = JSON.stringify(vue_outer_div.nowData[i]);isAllSelected = selectedDataStr.includes(nowDataRowStr);}return vue_outer_div.multipleSelectedData.length !== 0 && isAllSelected;
}/*** 判断本行是否已选* @author liquid* @date 2022年11月22日* @param value 本行数据* @returns {boolean} 是否已选*/
function isSelected(value) {return JSON.stringify(vue_outer_div.multipleSelectedData).includes(JSON.stringify(value));
}/*** (多选)左边checkbox的点击事件* @author liquid* @date 2022年11月22日* @param rowIndex*/
function multipleChooseSingleClick(rowIndex) {const checked = $(".multiple_choose_single > input")[rowIndex].checked;setChecked([rowIndex], checked);
}/*** 执行搜索* @author liquid* @date 2022年11月15日* @param renewSearch 是否重新以搜索框值作为条件值* @param index 从第index个记录开始返回*/
function searchData(renewSearch = true, index = 0) {let queryData;// 查询结果集let queryMaxCount;// 查询结果最大记录数// 重新以搜索框值作为条件值if (renewSearch) {index = 0;searchValue = getSearchValue();}firstResult = index;searchValue._fixed = {firstResult: firstResult,// 从第firstResult条记录开始查询maxResults: maxResults// 限制查询pageRowCount个结果}console.log("查询参数", searchValue);// 执行查询// 若存在历史记录则直接返回const paramsStr = JSON.stringify(searchValue);if (historyData.ekp[paramsStr]) {const data = historyData.ekp[paramsStr];renewData(data.queryData, data.queryMaxCount);return;}// 无历史记录则向后台查询loading(true);ajaxActionPms("xp/modeling/app/it/actions/XpEkpSqlAction.do?method=executeQuery", {key: sqlKey,params: searchValue}).then((res)=>{console.log({res})if (res.status !== "success") { errorHandler(res); return; }// 成功回调queryData = res.queryData;queryMaxCount = res.queryMaxCount;renewData(queryData, queryMaxCount);historyData.ekp[JSON.stringify(searchValue)] = res;// 保存历史记录loading(false);}).catch((error)=>{errorHandler(error);})
}/*** 重新选择页面数据* @author liquid* @date 2022年11月18日* @param queryData* @param queryMaxCount*/
function renewData(queryData, queryMaxCount) {// 重新渲染页面数据vue_outer_div.nowData = queryData;vue_outer_div.total = queryMaxCount;vue_outer_div.nowPage = queryMaxCount === 0 ? 0 : Math.ceil((firstResult + 1) / maxResults);vue_outer_div.lastPageIndex = Math.ceil(queryMaxCount / maxResults);
}/*** 转圈圈* @author liquid* @date 2022年11月18日* @param {boolean}open 是否转圈圈* @return {void}*/
function loading(open) {if (open) {vue_outer_div.noDataShow = false;$("#loading_div").css("display", "flex")} else {vue_outer_div.noDataShow = true;$("#loading_div").hide();}
}/*** 前往sql定义* @author liquid* @date 2023年4月17日* @return {void}*/
function gotoSqlDefinition() {if (isEmpty(sqlDefinitionFdId)) {return;}let url = Com_Parameter.ContextPath +"sys/modeling/main/modelingAppSimpleMain.do?method=edit" +"&fdId=" + sqlDefinitionFdId;window.open(url);
}function getLang(){let langStr = window.opener == null ? parent.window.Com_Parameter.Lang : window.opener.Com_Parameter.Lang;return langStr.toUpperCase();
}
3、具体实现 - 后端
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//package com.landray.kmss.xp.xform.base.service.controls.relationchoose;import com.landray.kmss.sys.xform.base.service.ISysFormTemplateControl;
import com.landray.kmss.sys.xform.base.service.ISysFormTemplateDetailsTableControl;
import com.landray.kmss.sys.xform.base.service.controls.FilterAction;
import com.landray.kmss.sys.xform.base.service.controls.LoopAction;
import com.landray.kmss.sys.xform.base.service.controls.TagNodeUtils;
import com.landray.kmss.util.StringUtil;
import org.htmlparser.Node;
import org.htmlparser.lexer.Lexer;
import org.htmlparser.nodes.TagNode;
import org.htmlparser.tags.InputTag;
import org.htmlparser.util.ParserException;import java.util.List;public class XpSysFormTemplateRelationChooseControl implements ISysFormTemplateControl, FilterAction, ISysFormTemplateDetailsTableControl {private String parentClass;public XpSysFormTemplateRelationChooseControl() {}public boolean parse(Node node, Lexer lexer, StringBuilder jsp, List controls) throws Exception {if (node instanceof TagNode) {TagNode tagNode = (TagNode)node;if (TagNodeUtils.isType("xpRelationChoose", tagNode)) {TagNodeUtils.fixRequired(tagNode);TagNodeUtils.filterNode(tagNode, lexer, jsp, this);return true;}}return false;}private void doParse(Node node, StringBuilder jsp) throws ParserException {if (node instanceof InputTag) {TagNode tagNode = (TagNode)node;String id = tagNode.getAttribute("id");String bindEvent = "click";String required = tagNode.getAttribute("_required");String style = tagNode.getAttribute("style");String freeEdit = tagNode.getAttribute("freeEdit");String editCallbackFunName = tagNode.getAttribute("editCallbackFunName");String openWinFunName = tagNode.getAttribute("openWinFunName");String notNullCheck = tagNode.getAttribute("notNullCheck");String clearCallbackFunName = tagNode.getAttribute("clearCallbackFunName");String clearFieldId = tagNode.getAttribute("clearFieldId");String params = "{" +"'freeEdit':'" + freeEdit + "'," +"'editCallbackFunName':'" + editCallbackFunName + "'," +"'openWinFunName':'" + openWinFunName + "'," +"'clearCallbackFunName':'" + clearCallbackFunName + "'," +"'clearFieldId':'" + clearFieldId + "'," +"'notNullCheck':'" + notNullCheck + "'" +"}";params = params.replaceAll("'", "quot;");jsp.append("\r\n").append(TagNodeUtils.getElementTab()).append(TagNodeUtils.buildControlWrapHTMLBegin(tagNode.getAttribute("id"), "xform_relation_choose", "relationChoose"));jsp.append("\r\n").append(TagNodeUtils.getElementTab()).append("");jsp.append("").append(" ").append(" ").append(" ").append(" ").append(" ").append(" ").append(" ");jsp.append(" ");jsp.append("");jsp.append(TagNodeUtils.buildControlWrapHTMLEnd());jsp.append(TagNodeUtils.getElementTab());}}public void end(Node node, StringBuilder jsp) throws ParserException {this.doParse(node, jsp);}public void filter(Node node, StringBuilder jsp) throws ParserException {this.doParse(node, jsp);}public void start(Node node, StringBuilder jsp) throws ParserException {if (node instanceof TagNode) {TagNode tempNode = (TagNode)node;this.parentClass = tempNode.getAttribute("class");}this.doParse(node, jsp);}public boolean parseDetailsTable(Node node, Lexer lexer, StringBuilder templateJsp, final String idPrefix, List controls) throws Exception {if (node instanceof TagNode) {TagNode tagNode = (TagNode)node;if (TagNodeUtils.isType("xpRelationChoose", tagNode)) {TagNodeUtils.loopForDetailsTable(this, tagNode, lexer, templateJsp, idPrefix, controls, new LoopAction() {public boolean action(Node aTagNode, Lexer lexer, StringBuilder jsp, List controls) throws Exception {if (aTagNode instanceof TagNode) {TagNode tagNode = (TagNode)aTagNode;TagNodeUtils.setDetailsTableId(idPrefix, tagNode);if (!(tagNode instanceof InputTag)) {return false;} else {XpSysFormTemplateRelationChooseControl.this.doParse(tagNode, jsp);return true;}} else {return false;}}});return true;}}return false;}
}
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
