UNPKG

tfp

Version:

A Web UI framework for TaskBuilder

1,570 lines (1,469 loc) 46.8 kB
/** * 动态引用js文件 * @param {[type]} url [description] * @return {[type]} [description] */ function importJsFile(url) { return new Promise((resolve, reject) => { var script = document.createElement("script"); script.type = "text/javascript"; if (script.readyState) { script.onreadystatechange = function () { if (script.readyState == "loaded" || script.readyState == "complete") { script.onreadystatechange = null; resolve(); } }; } else { script.onload = function () { resolve(); }; } script.src = url; document.body.appendChild(script); }); } /** * 引用ES6模块文件 * @param {[type]} files [description] * @param {Function} cb [description] * @return {[type]} [description] */ async function importModules(files, cb) { let arrIn = files; let arrOut = []; if (typeof (arrIn) == "string") arrIn = [arrIn]; for (let i = 0; i < arrIn.length; i++) { arrOut.push(await import(arrIn[i])); } if (cb) cb(arrOut); } /** * 获得需要导入的组件类型 * @return {[type]} [description] */ function getNeedImportCptType(tfp, cptTypeName, needImportCptTypes) { let metadata = tfp.metaDatas[cptTypeName]; if (!metadata) return; //如果有依赖项,则需要优先加载 let dependencies = []; if (metadata.dependencies) { if (typeof (metadata.dependencies) == "string") { dependencies.push(metadata.dependencies); } else if (Array.isArray(metadata.dependencies)) { dependencies.push.apply(dependencies, metadata.dependencies); } } if (dependencies.length > 0) { for (let i = 0; i < dependencies.length; i++) { getNeedImportCptType(tfp, dependencies[i], needImportCptTypes); } } if (!needImportCptTypes.includes(cptTypeName)) needImportCptTypes.push(cptTypeName); } /** * 添加组件相关文件的引用 * @param {[type]} tfp [description] * @param {[type]} pageDataModel [description] * @param {[type]} cptTypes [description] * @param {Function} cb [description] * @return {[type]} [description] */ async function importCptFiles(tfp, pageDataModel, cptTypes, cb) { //获得所有需要导入的组件类型,包括相关依赖组件 let needImportCptTypes = []; for (let i = 0; i < cptTypes.length; i++) { getNeedImportCptType(tfp, cptTypes[i], needImportCptTypes); } for (let i = 0; i < needImportCptTypes.length; i++) { let cptTypeName = needImportCptTypes[i]; let metadata = tfp.metaDatas[cptTypeName]; if (!metadata) continue; let metadataFile = "./components/" + cptTypeName.toLowerCase() + "/metadata"; let controllerFile = "./components/" + cptTypeName.toLowerCase() + "/controller"; let renderFile = "./components/" + cptTypeName.toLowerCase() + "/render"; let clientType = pageDataModel.client; if (clientType == "tb") clientType = "pc"; if (!metadata.matchAllClient) { metadataFile += "." + clientType; controllerFile += "." + clientType; renderFile += "." + clientType; } metadataFile += ".js"; controllerFile += ".js"; renderFile += ".js"; if (!metadata.isLoaded) { let matchAllClient = metadata.matchAllClient; let isInvisible = metadata.isInvisible; let dependencies = null; if (metadata.dependencies) dependencies = metadata.dependencies; let metaModule = await import(metadataFile); metadata = metaModule.default; metadata.isLoaded = true; if (matchAllClient) metadata.matchAllClient = matchAllClient; if (isInvisible) metadata.isInvisible = isInvisible; if (dependencies) metadata.dependencies = dependencies; tfp.metaDatas[cptTypeName] = metadata; } if (!tfp.controllers[cptTypeName]) { let controllerModule = await import(controllerFile); tfp.controllers[cptTypeName] = controllerModule.default; } if (!tfp.renders[cptTypeName]) { let renderModule = await import(renderFile); tfp.renders[cptTypeName] = renderModule.default; } if (typeof (window) != "undefined") { let tfpPath = tfp.rootPath + "/src/components/"; let cssFiles = []; if (metadata.cssFiles) { if (typeof (metadata.cssFiles) == "string") { cssFiles = [metadata.cssFiles]; } else if (Array.isArray(metadata.cssFiles)) { cssFiles = metadata.cssFiles; } } let bgColorMode = "light"; if (pageDataModel.bgColorMode == "dark") bgColorMode = "dark"; for (let j = 0; j < cssFiles.length; j++) { let styleFile = cssFiles[j]; if (styleFile.onlyRuntime) { if (tfp.isDesigning) continue; styleFile = styleFile.src; } styleFile = styleFile.replace("{client}", clientType); styleFile = styleFile.replace("{bgColorMode}", bgColorMode); styleFile = tfp.getCptIncludeFile(styleFile, cptTypeName); if ($("link[href='" + styleFile + "']").length == 0) { if (styleFile.endsWith(".less")) { $("head").append("<link href=\"" + styleFile + "\" rel=\"stylesheet/less\" type=\"text/css\" />"); } else { $("head").append("<link href=\"" + styleFile + "\" rel=\"stylesheet\" type=\"text/css\" />"); } } } let jsFiles = []; if (metadata.jsFiles) { if (typeof (metadata.jsFiles) == "string") { jsFiles = [metadata.jsFiles]; } else if (Array.isArray(metadata.jsFiles)) { jsFiles = metadata.jsFiles; } } for (let j = 0; j < jsFiles.length; j++) { let jsFile = jsFiles[j]; if (jsFile.onlyRuntime) { if (tfp.isDesigning) continue; jsFile = jsFile.src; } jsFile = tfp.getCptIncludeFile(jsFile, cptTypeName); if ($("script[src='" + jsFile + "']").length == 0) { await importJsFile(jsFile); } } } } if (cb) cb(); } export default class TaskFrontPage { constructor() { this.metaDatas = {}; //当前页面注册的组件定义信息 this.controllers = {}; //当前页面注册的组件类 this.renders = {}; //当前页面注册的组件渲染器类 this.curPage = null; //当前页面对象 this.components = {}; //当前页面的组件集合 this.cbOpenDialog = null; this.rootPath = "/node_modules/tfp"; } /** * 扩展系统对象 * @return {[type]} [description] */ extendSysObj() { if (typeof (String.prototype.startsWith) == "undefined") { /** * 判断字符串是否以指定的子字符串开头 * @param {[type]} prefix [description] * @return {[type]} [description] */ String.prototype.startWith = String.prototype.startsWith = function (prefix) { return this.indexOf(prefix) === 0; } } if (typeof (String.prototype.endsWith) == "undefined") { /** * 判断字符串是否以指定的子字符串结尾 * @param {[type]} suffix [description] * @return {[type]} [description] */ String.prototype.endWith = String.prototype.endsWith = function (suffix) { return this.match(suffix + "$") == suffix; } } if (typeof (String.prototype.replaceAll) == "undefined") { /** * 全部替换 * @param {[type]} s1 [description] * @param {[type]} s2 [description] * @return {[type]} [description] */ String.prototype.replaceAll = function (s1, s2) { return this.replace(new RegExp(s1, "gm"), s2); } } if (typeof (String.prototype.trim) == "undefined") { /** * 删除字符串两端的空格 * @return {[type]} [description] */ String.prototype.trim = function () { return this.replace(/(^\s*)|(\s*$)/g, ""); } } if (typeof (String.prototype.toDate) == "undefined") { /** * 将字符串转换为日期 * @return {[type]} [description] */ String.prototype.toDate = function () { return new Date(this.replace(/-/g, '/')); } } /** * 计算字符串长度,英文字母算一个,汉字算两个 * @return {[type]} [description] */ String.prototype.gblen = function () { var len = 0; for (var i = 0; i < this.length; i++) { if (this.charCodeAt(i) > 127 || this.charCodeAt(i) == 94) { len += 2; } else { len++; } } return len; } if (typeof (Date.prototype.format) == "undefined") { /** * 将日期格式化为字符串 * @param {[type]} style [description] * @return {[type]} [description] */ Date.prototype.format = function (style) { var y = this.getFullYear(); var M = "0" + (this.getMonth() + 1); M = M.substring(M.length - 2); var d = "0" + this.getDate(); d = d.substring(d.length - 2); var H = "0" + this.getHours(); H = H.substring(H.length - 2); var h = this.getHours(); if (h >= 12) h = h - 12; h = "0" + h; h = h.substring(h.length - 2); var m = "0" + this.getMinutes(); m = m.substring(m.length - 2); var s = "0" + this.getSeconds(); s = s.substring(s.length - 2); var ms = "00" + this.getMilliseconds(); ms = ms.substring(ms.length - 3); var ret = (style + "").replaceAll('yyyy', y); ret = ret.replaceAll('yy', (y + '').substring(2)); ret = ret.replaceAll('MM', M); ret = ret.replaceAll('dd', d); ret = ret.replaceAll('HH', H); ret = ret.replaceAll('hh', h); ret = ret.replaceAll('mm', m); ret = ret.replaceAll('ss', s); ret = ret.replaceAll('SSS', ms); return ret; } } if (typeof (Date.prototype.toJSON) == "undefined") { /** * 日期对象转换为JSON值 * @return {[type]} [description] */ Date.prototype.toJSON = function () { return this.format('yyyy-MM-dd HH:mm:ss'); } } if (typeof (Array.prototype.remove) == "undefined") { /** * 删除数组中指定的元素 * @param {[type]} obj [description] * @return {[type]} [description] */ Array.prototype.remove = function (obj) { for (var i = 0; i < this.length; i++) { if (this[i] === obj) { this.splice(i, 1); return; } } } } if (typeof (Array.prototype.contains) == "undefined") { /** * 判断数组中是否存在指定的元素 * @param {[type]} obj [description] * @return {[type]} [description] */ Array.prototype.contains = function (obj) { var i = this.length; while (i--) { if (this[i] === obj) { return true; } } return false; } } if (typeof (window.isNull) == "undefined") { /** * 是否为空值 * @param {[type]} val [description] * @return {Boolean} [description] */ window.isNull = function (val) { return val == null || val == undefined || (typeof val == "string" && val.trim() == ""); } } if (typeof (window.isInt) == "undefined") { /** * 判断是否是整数 * @param {[type]} i [description] * @return {Boolean} [description] */ window.isInt = function (i) { return i == parseInt(i); } } if (typeof (window.isObj) == "undefined") { /** * 是否是对象 * @param {[type]} obj [description] * @return {Boolean} [description] */ window.isObj = function (obj) { return Object.prototype.toString.call(obj) === '[object Object]'; } } } /** * 是否是设计时 * @return {Boolean} [description] */ get isDesigning() { //为了防止嵌入到第三方系统时发生跨域错误,需要将对window.parent的访问放在try catch里 let isDesigning = false; try { isDesigning = window.parent && typeof window.parent.uiDesigner != "undefined"; } catch (err) { } return typeof window != "undefined" && isDesigning; } /** * 是否是在前端浏览器内运行时 * @return {Boolean} [description] */ get isRuntime() { return typeof window != "undefined" && !this.isDesigning; } /** * 是否为空,包括null、undefined、空字符串 * @param {[type]} val [description] * @return {Boolean} [description] */ isNull(val) { return val == null || val == undefined || (typeof val == "string" && val.trim() == ""); } /** * 是否是整数 * @param {[type]} i [description] * @return {Boolean} [description] */ isInt(i) { return i == parseInt(i); } /** * 是否是移动端 * @return {Boolean} [description] */ isMobile() { return /Android|webOS|iPhone|iPad|Windows Phone|iPod|BlackBerry|SymbianOS|Nokia|Mobile/i.test(navigator.userAgent); } /** * 数字前面补零 * @param {[type]} num [description] * @param {[type]} n [description] * @return {[type]} [description] */ prefixInteger(num, n) { return (Array(n).join(0) + num).slice(-n); } /** * 格式化金额 * @param {[type]} s 输入值 * @param {[type]} n 小数点位数 * @param {[type]} t 是否显示千分位 * @return {[type]} 返回值 */ formatMoney(s, n, t) { n = n > 0 && n <= 20 ? n : 2; s = parseFloat((s + "").replace(/[^\d\.-]/g, "")).toFixed(n) + ""; if (!t) return s; var l = s.split(".")[0].split("").reverse(); var r = s.split(".")[1]; var t = ""; for (var i = 0; i < l.length; i++) { t += l[i] + ((i + 1) % 3 === 0 && i + 1 != l.length ? "," : ""); } return t.split("").reverse().join("") + "." + r; } /** * 格式化小数 * @param {[type]} val [description] * @param {[type]} type [description] * @param {[type]} len [description] * @return {[type]} [description] */ formatDecimal(val, type, len) { if (!val && val != 0) return val; let decVal = parseFloat(val); if (!len && len != 0) return decVal; let decLen = parseInt(len); if (decLen == 0) return parseInt(decVal); if (type == "trunc") { decVal = Math.trunc(decVal); } else if (type == "toFixed") { decVal = decVal.toFixed(decLen); } else if (type == "toPrecision") { decVal = decVal.toPrecision(decLen); } else if (type == "ceil") { decVal = Math.ceil(decVal); } else if (type == "floor") { decVal = Math.floor(decVal); } else if (type == "abs") { decVal = Math.abs(decVal); } else if (type == "round") { let numPow = Math.pow(10, decLen); decVal = decVal * numPow; decVal = Math.round(decVal); decVal = decVal / numPow; decVal = decVal.toFixed(decLen); } return decVal; } /** * 格式化日期 * @param {[type]} d 输入值 * @param {[type]} f 格式 * @return {[type]} 返回值 */ formatDate(d, f) { if (typeof d == "number") return new Date(d).format(f); return new Date(Date.parse(d.replace("T", " ").replace("+08:00", " ").replace(/-/g, "/"))).format(f); } /** * 格式化文件大小 * @param {[type]} bytes [description] * @return {[type]} [description] */ formatFileSize(bytes) { if (bytes === 0) return '0 B'; var k = 1000, // or 1024 sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'], i = Math.floor(Math.log(bytes) / Math.log(k)); return (bytes / Math.pow(k, i)).toPrecision(3) + ' ' + sizes[i]; } /** * 获得样式中的像素值,将px字母删掉,转换为整数 * @param {[type]} value [description] * @return {[type]} [description] */ formatPx(value) { if (this.isNull(value)) return ""; return (value + "").indexOf("px") < 0 ? value + "px" : value; } /** * 获得样式中的像素值,将px字母删掉,转换为整数 * @param {[type]} value [description] * @return {[type]} [description] */ getPixel(value) { return this.getPx(value); } getPx(value) { if (this.isNull(value)) return 0; return parseInt(new String(value + "").replace("px", "")); } /** * 格式化RGB颜色值 * @param {[type]} color [description] * @return {[type]} [description] */ rgbToHex(color) { let arr = color.split(','); let r = +arr[0].split('(')[1]; let g = +arr[1]; let b = +arr[2].split(')')[0]; let value = (1 << 24) + r * (1 << 16) + g * (1 << 8) + b; value = value.toString(16); return '#' + value.slice(1); }; /** * 获得URL中的所有参数 * @param {[type]} url [description] * @return {[type]} [description] */ getUrlArgs(url) { var args = {}; var start = url.indexOf("?"); if (start < 0) return args; var str = url.substr(start + 1); var strArr = str.split("&"); for (var i = 0; i < strArr.length; i++) { var argName = strArr[i].substr(0, strArr[i].indexOf("=")); var argValue = strArr[i].substr(strArr[i].indexOf("=") + 1); args[argName] = argValue; } return args; } /** * 获得URL中的指定参数的值 * @param {[type]} argName [description] * @return {[type]} [description] */ getUrlArg(argName) { var url = window.location.href; var start = url.indexOf("?"); if (start < 0) return null; var str = url.substr(start + 1); var strArr = str.split("&"); for (var i = 0; i < strArr.length; i++) { var aname = strArr[i].substr(0, strArr[i].indexOf("=")); if (aname == argName) return decodeURIComponent(strArr[i].substr(strArr[i].indexOf("=") + 1)); } return null; } /** * 替换数据绑定字段 * @param {[type]} obj [description] * @param {[type]} str [description] * @return {[type]} [description] */ replaceDataField(obj, str) { if (!obj || (!str && str != 0)) return ""; //为了忽略大小写,需要将数据对象的属性名变成小写 let objTmp = {}; for (let p in obj) { objTmp[p.toLowerCase()] = obj[p]; } var patt = new RegExp("{([\\w|\.|\\u4E00-\\u9FA5]*)}", "ig"); var result = patt.exec(str); while (result != null) { let fieldStr = result[0]; fieldStr = fieldStr.substring(1, fieldStr.length - 1); var fieldName = fieldStr; var format = ""; if (fieldStr.indexOf(",") > 0) { format = fieldStr.substr(fieldStr.indexOf(",") + 1); fieldName = fieldStr.substr(0, fieldStr.indexOf(",")); } fieldName = fieldName.replace(/ /g, "").toLowerCase(); let fieldVal = objTmp[fieldName]; if (fieldVal || fieldVal == 0) { if (typeof (fieldVal) == "object") { if (str == "{" + fieldName + "}") { return fieldVal; } else { str = str.replace("{" + fieldStr + "}", JSON.stringify(fieldVal)); } } else if (format == "datetime") { str = str.replace("{" + fieldStr + "}", new Date(fieldVal).format("yyyy-MM-dd HH:mm:ss")); } else if (format == "date") { str = str.replace("{" + fieldStr + "}", new Date(fieldVal).format("yyyy-MM-dd")); } else if (format == "time") { str = str.replace("{" + fieldStr + "}", new Date(fieldVal).format("HH:mm:ss")); } else if ((format.indexOf("\"") >= 0 || format.indexOf("'") >= 0) && (format.indexOf("yy") >= 0 || format.indexOf("MM") >= 0 || format.indexOf("dd") >= 0 || format.indexOf("HH") >= 0 || format.indexOf("hh") >= 0 || format.indexOf("ss") >= 0)) { format = format.replace(/"/g, "").replace(/'/g, ""); var dateStr = fieldVal + ''; //if (dateStr.indexOf("T") < 0) dateStr = dateStr.replace(/-/g, '/'); str = str.replace("{" + fieldStr + "}", new Date(dateStr).format(format)); } else if (format == "money") { str = str.replace("{" + fieldStr + "}", this.formatMoney(fieldVal, 2)); } else if (format == "filesize") { str = str.replace("{" + fieldStr + "}", this.formatFileSize(fieldVal)); } else { str = str.replace("{" + fieldStr + "}", (fieldVal + "").replace(/\{/g, "`(`").replace(/\}/g, "`)`")); } } else { str = str.replace("{" + fieldStr + "}", ""); } patt = new RegExp("{([\\w|\.|\\u4E00-\\u9FA5]*)}", "ig"); result = patt.exec(str); } return str; } /** * 执行表达式 * @param {[type]} str [description] * @return {[type]} [description] */ exeExpress(str) { if (isNull(str) || typeof (str) != "string") return str; var start = str.indexOf("#["); if (start < 0) return str.replace(/\`\(\`/g, "{").replace(/\`\)\`/g, "}"); var end = str.indexOf("]", start); if (end < 0) return str; var express = str.substr(start + 2, end - start - 2); var val = ""; try { val = eval(express); } catch (err) { } var newStr = ""; if (start > 0) newStr += str.substr(0, start); newStr += val; if (end < str.length - 1) newStr += str.substr(end + 1); return this.exeExpress(newStr); } /** * 在iframe页面内获得顶部窗口对象 * @return {[type]} [description] */ get topWin() { let topWin = window; //在嵌入第三方系统时,调用top和window.parent都会产生跨域错误,需要捕获一下 try { if ("undefined" != typeof top && top.location.href != location.href) { topWin = top; } } catch (err) { try { if (window.parent) { topWin = window.parent; } } catch (err2) { } } return topWin; } /** * 显示提示消息 * @param {[type]} msg [description] * @return {[type]} [description] */ showMsg(msg, cb) { if (typeof window != "undefined") { if (this.topWin.showMsg) { this.topWin.showMsg(msg, cb); } else { alert(msg); } } else { console.log(msg); } } /** * 显示确认消息 * @param {[type]} msg [description] * @return {[type]} [description] */ showConfirm(msg, cb) { if (typeof window != "undefined") { if (this.topWin.showConfirm) { this.topWin.showConfirm(msg, cb); } else { cb(confirm(msg)); } } else { console.log(msg); } } /** * 跳转到系统首页 * @return {[type]} [description] */ gotoHome() { if (typeof (this.topWin.gotoHome) != "undefined") { this.topWin.gotoHome(); } else { location = "/"; } } /** * 跳转到指定页面 * @param {[type]} url [description] * @return {[type]} [description] */ gotoPage(url) { location = url; } /** * 打开图片查看器 * @param {[type]} url [description] * @return {[type]} [description] */ openImage(url) { let u = url; if(!u) return; u += ""; if(u.indexOf("/Download?")==0 && u.indexOf("showImage")<0) u += "&showImage=true"; this.openPage("查看图片", "/app/sys/tool/imageViewer.tfp?url="+u); } /** * 打开指定页面 * @param {[type]} title [description] * @param {[type]} url [description] * @return {[type]} [description] */ openPage(title, url) { if (typeof (this.topWin.openTabPage) != "undefined") { this.topWin.openTabPage(title, url); } else if (typeof (this.topWin.openPage) != "undefined") { this.topWin.openPage(title, url); } else { location = url; } } /** * 显示指定页面 * @param {[type]} id [description] * @return {[type]} [description] */ showPage(id) { if (typeof (this.topWin.showTabPage) != "undefined") { this.topWin.showTabPage(id); } else if (typeof (this.topWin.showPage) != "undefined") { this.topWin.showPage(id); } } /** * 隐藏指定页面 * @param {[type]} id [description] * @return {[type]} [description] */ hidePage(id) { if (typeof (this.topWin.hideTabPage) != "undefined") { this.topWin.hideTabPage(id); } else if (typeof (this.topWin.hidePage) != "undefined") { this.topWin.hidePage(id); } } /** * 获得当前页面 * @return {[type]} [description] */ getCurPage() { if (typeof (this.topWin.getCurTabPage) != "undefined") { return this.topWin.getCurTabPage(); } else if (typeof (this.topWin.getCurPage) != "undefined") { return this.topWin.getCurPage(); } } /** * 关闭指定页面 * @param {[type]} id [description] * @return {[type]} [description] */ closePage(id) { if (typeof (this.topWin.closeTabPage) != "undefined") { this.topWin.hideTabPage(id); } else if (typeof (this.topWin.closePage) != "undefined") { this.topWin.hidePage(id); } } /** * 关闭当前页面 * @return {[type]} [description] */ closeCurPage() { if (typeof (this.topWin.closeCurTabPage) != "undefined") { this.topWin.closeCurTabPage(); } else if (typeof (this.topWin.closeCurPage) != "undefined") { this.topWin.closeCurPage(); } } /** * 打开对话框 * @param {[type]} title [description] * @param {[type]} url [description] * @param {[type]} icon [description] * @param {[type]} width [description] * @param {[type]} height [description] * @param {[type]} srcElement [description] * @param {[type]} opener [description] * @return {[type]} [description] */ openDialog(title, url, width, height, args, cb) { if (typeof (this.topWin.openDialog) != "undefined") { let srcElement = null; if (window.event) srcElement = window.event.srcElement; this.topWin.openDialog(title, url, width, height, srcElement, window, args, cb); } else { location = url; } } /** * 关闭对话框 * @return {[type]} [description] */ closeDialog(id) { if (typeof (this.topWin.closeDialog) != "undefined") { this.topWin.closeDialog(id); } } /** * 关闭当前对话框 * @return {[type]} [description] */ closeCurDialog(ret) { if (typeof (this.topWin.closeCurDialog) != "undefined") { if (ret) this.onDialogOK(ret); this.topWin.closeCurDialog(); } } /** * 获得当前对话框 * @return {[type]} [description] */ getCurDialog() { if (typeof (this.topWin.getCurDialog) != "undefined") { return this.topWin.getCurDialog(); } return null; } /** * 获得当前对话框ID * @return {[type]} [description] */ getCurDialogId() { if (typeof (this.topWin.getCurDialogId) != "undefined") { return this.topWin.getCurDialogId(); } return null; } /** * 获得对话框请求参数 * @return {[type]} [description] */ getDialogArgs() { return sessionStorage.getItem("_OpenDialogArgs"); } /** * 点击对话框确定按钮后 * @param {[type]} ret [description] * @return {[type]} [description] */ onDialogOK(ret) { if (typeof (this.topWin.onDialogOK) != "undefined") { this.topWin.onDialogOK(ret); } } /** * 获得打开当前页面的父页面或前置页面 * @return {[type]} [description] */ getOpener() { if (this.curPage.pageType == "dialog") { return this.getCurDialog().opener; } else { return this.topWin.getCurTabPageOpener(); } } /** * 打开指定报表 * @param {[type]} title [description] * @param {[type]} url [description] * @return {[type]} [description] */ openReport(url) { if (!url) return; url = url.replace("?", "&"); window.open("/node_modules/taskreport/index.html?url=" + url); } /** * 获得URL的实际路径 * @param {[type]} url [description] * @return {[type]} [description] */ getUrlRealPath(url) { if (!url) return ""; var realPath = ""; if (this.curPage.client == "tb") { realPath = url; if (realPath.indexOf("/") == 0) realPath = ".." + realPath; } else { if (this.isDesigning && url.indexOf("http:") != 0 && url.indexOf("https:") != 0) { var curServer = top.taskBuilder.getCurServer(); realPath = "http://"; if (curServer.userHttps) realPath = "https://"; realPath += curServer.address; if (curServer.port) realPath += ":" + curServer.port; if (url.indexOf("/") == 0) { realPath += url; } else { var curPath = window.parent.tfpDesigner.curTFPFilePath.substring( window.parent.tfpDesigner.curTFPFilePath.indexOf("/web/") + 4, window.parent.tfpDesigner.curTFPFilePath.lastIndexOf("/") + 1); if (url.indexOf("../") == 0) { while (url.indexOf("../") == 0) { url = url.substring(3); if (curPath != "/") curPath = curPath.substring(0, curPath.lastIndexOf("/", curPath.length - 2) + 1); } realPath += curPath + url; } else if (url.indexOf("./") == 0) { realPath += curPath + url.substring(2); } else { realPath += curPath + url; } } } else { realPath = url; } } return realPath; } getCptIncludeFile(_filePath, cptTypeName) { let tfpPath = this.rootPath + "/src/components"; let filePath = _filePath; if (filePath.indexOf("http://") != 0 && filePath.indexOf("https://") != 0) { if (filePath.indexOf("/") == 0) { if (this.isDesigning || this.curPage.client == "tb") { if (filePath.startsWith("/node_modules/")) { filePath = filePath.substr(13); } filePath = ".." + filePath; } } else if (filePath.indexOf("/") < 0) { filePath = tfpPath + "/" + cptTypeName.toLowerCase() + "/" + filePath; } else if (filePath.indexOf("../") == 0) { filePath = tfpPath + "/" + filePath.replaceAll("../", ""); } } return filePath; } /** * 为URL设置身份验证信息 * @param {[type]} url [description] */ setUrlAuthData(url) { if (!url) return; try { if (typeof top != "undefined" && top.taskMsgAuthObj) { return top.taskMsgAuthObj.getAuthUrl(url); } } catch (err) { try { if (typeof window.parent != "undefined" && window.parent.taskMsgAuthObj) { return window.parent.taskMsgAuthObj.getAuthUrl(url); } } catch (err2) { var _auth_org = void 0; var _auth_ts = void 0; var _auth_data = void 0; if (typeof tmClient != "undefined" && (tmClient.clientOSType == "iOS" && typeof TMiOSClient != "undefined" || tmClient.clientOSType == "Android" && typeof TMAndroidClient != "undefined")) { var authData = JSON.parse(tmClient.getAuthData()); _auth_org = authData._auth_org; _auth_ts = authData._auth_ts; _auth_data = authData._auth_data; } else { if (this.getUrlArg("_auth_org")) _auth_org = this.getUrlArg("_auth_org"); if (this.getUrlArg("_auth_ts")) _auth_ts = this.getUrlArg("_auth_ts"); if (this.getUrlArg("_auth_data")) _auth_data = this.getUrlArg("_auth_data"); } if (!_auth_org && !_auth_ts && !_auth_data) return url; var ret = url; if (ret.indexOf('?') < 0) ret += "?"; if (_auth_org) { if (!ret.endsWith("?")) ret += "&"; ret += "_auth_org=" + _auth_org; } if (_auth_ts) { if (!ret.endsWith("?")) ret += "&"; ret += "_auth_ts=" + _auth_ts; } if (_auth_data) { if (!ret.endsWith("?")) ret += "&"; ret += "_auth_data=" + _auth_data; } return ret; } } return url; } /** * 获得指定id的组件 * @param {[type]} cptId [description] * @return {[type]} [description] */ get(cptId) { return this.components[cptId]; } /** * 获得指定类型组件的新ID * @param {[type]} ctype [description] * @return {[type]} [description] */ getNewCptIndex(ctype) { var index = 1; while (this.components[ctype.substr(0, 1).toLowerCase() + ctype.substr(1) + index]) { index++; } return index; } /** * 使用默认属性和样式创建新的组件 * @param {[type]} typeName [description] * @param {[type]} parent [description] * @return {[type]} [description] */ new(typeName, parent) { if (!typeName) { throw new Error("请提供组件类型!"); return null; } var cptTypeInfo = this.type(typeName); if (!cptTypeInfo) { throw new Error("未找到名为[" + typeName + "]的组件类型定义信息!"); return null; } var cptClass = this.controllers[typeName]; if (!cptClass) { throw new Error("未找到名为[" + typeName + "]的组件类!"); return; } var cpt = new cptClass(this, null, parent); if (parent) cpt.render(); return cpt; } /** * 根据指定的数据模型创建并渲染组件 * @param {[type]} dataModel [description] * @param {[type]} parent [description] * @return {[type]} [description] */ render(dataModel, parent) { if (!dataModel) { console.error("请提供组件的数据模型!"); return null; } if (!dataModel.type) { console.error("请提供组件类型!"); return null; } if (!parent && dataModel.type != "Page") { console.error("请提供父组件!"); return; } var cptTypeInfo = this.type(dataModel.type); if (!cptTypeInfo) { throw new Error("未找到名为[" + dataModel.type + "]的组件类型定义信息!"); return null; } var cptClass = this.controllers[dataModel.type]; if (!cptClass) { throw new Error("未找到名为[" + dataModel.type + "]的组件控制器!"); return; } var cpt = new cptClass(this, dataModel, parent); cpt.render(); return cpt; } remove(_cpt) { if (!_cpt) return; let cpt; if (typeof (_cpt) == "string") { cpt = this.components[_cpt]; } else if (_cpt.dataModel) { cpt = _cpt; } else { cpt = this.components[_cpt.id]; } if (cpt.dataModel.components) { for (var i = 0; i < cpt.dataModel.components.length; i++) { let cdmChild = cpt.dataModel.components[i]; if (!cdmChild) { continue; } this.remove(cdmChild.id); } cpt.dataModel.components = null; } if (cpt._jqObj) cpt._jqObj.remove(); delete this.components[cpt.id]; cpt.dataModel = null; cpt = null; } /** * 获得组件属性定义 * @param {[type]} cptType [description] * @param {[type]} attrName [description] * @return {[type]} [description] */ attrType(cptType, attrName) { if (!cptType.attrs) return null; for (var i = 0; i < cptType.attrs.length; i++) { if (cptType.attrs[i].name == attrName) return cptType.attrs[i]; } return null; } /** * 获得为组件设置的事件处理函数的名称 * @param {[type]} eventSetting [description] * @return {[type]} [description] */ getCptEventFuncName(eventSetting) { var eventName = eventSetting; if (eventName.indexOf("(") > 0) eventName = eventName.substr(0, eventName.indexOf("(")); return eventName; } /** * 获得Html标签样式属性名,删掉-号,并把-号后面的一个字母转换为大写 * @param {[type]} styleName [description] * @return {[type]} [description] */ getStyleAttrName(styleName) { var saName = styleName; while (saName.indexOf("-") > 0) { saName = saName.substr(0, saName.indexOf("-")) + saName.substr(saName.indexOf("-") + 1, 1).toUpperCase() + saName.substr(saName.indexOf("-") + 2); } return saName; } /** * 加载组件分类 * @param {[type]} pageData [description] * @param {[type]} cb [description] * @return {[type]} [description] */ loadComponentCategorys(pageData, cb) { let that = this; let clientType = pageData.client; if (clientType == "tb") clientType = "pc"; let componentsFilePath = "components." + clientType + ".js"; //如果是设计时,或者是在IDE内加载,则使用tb本地的tfp文件(不包括预览) if (tfp.isDesigning || (window.parent && window.parent.taskBuilder)) { componentsFilePath = "./" + componentsFilePath; } else if (window) { componentsFilePath = tfp.rootPath + "/lib/" + componentsFilePath; } importModules(componentsFilePath, function (modules) { let categorys = modules[0].default; that.setComponentMetaDatas(categorys); /*for(let i=0;i<categorys.length;i++) { let category = categorys[i]; for(let j=0;j<category.components.length;j++) { let cptMetaData = category.components[j]; cptMetaData.isLoaded = false; that.metaDatas[cptMetaData.name] = cptMetaData; } }*/ if (cb) cb(categorys); }); } setComponentMetaDatas(categorys) { for (let i = 0; i < categorys.length; i++) { let category = categorys[i]; for (let j = 0; j < category.components.length; j++) { let cptMetaData = category.components[j]; cptMetaData.isLoaded = false; this.metaDatas[cptMetaData.name] = cptMetaData; } } } /** * 添加组件相关文件的引用 * @param {[type]} cptTypes [description] * @param {Function} cb [description] * @return {[type]} [description] */ use(cptTypes, cb) { let arrTypes = cptTypes; if (typeof (arrTypes) == "string") arrTypes = [arrTypes]; importCptFiles(this, this.curPage.dataModel, arrTypes, function () { if (cb) cb(); }); } /** * 解析组件类型 * @param {[type]} dataModel [description] * @param {[type]} cptTypes [description] * @return {[type]} [description] */ parseCptTypes(dataModel, cptTypes) { if (!this.metaDatas[dataModel.type]) return; if (dataModel.type != "Page" && !cptTypes.includes(dataModel.type)) cptTypes.push(dataModel.type); if (dataModel.components) { for (let i = 0; i < dataModel.components.length; i++) { this.parseCptTypes(dataModel.components[i], cptTypes); } } } /** * 解析组件数据模型 * @param {[type]} dataModel [description] * @param {[type]} parent [description] * @return {[type]} [description] */ parseCpt(dataModel, parent) { if (!dataModel) { console.error("请提供组件的数据模型!"); return null; } if (!dataModel.type) { console.error("请提供组件类型!"); return null; } if (!parent && dataModel.type != "Page") { console.error("请提供父组件!"); return; } var cptClass = this.controllers[dataModel.type]; if (!cptClass) { throw new Error("未找到名为[" + dataModel.type + "]的组件控制器!"); return; } var cpt = new cptClass(this, dataModel, parent); if (dataModel.type == "Page") this.curPage = cpt; //如果不是TaskBuilder的本地页面,则需要绑定组件的html元素 //因为TaskBuilder的本地页面在渲染时已经绑定,不需要再绑定 //而普通tfp页面的HTML代码是由服务器事先编译好的,需要在运行时绑定 if (this.curPage.client != "tb") { //将组件id设置为全局变量并指向组件,以便在代码中访问 window[cpt.id] = cpt; //如果是可视组件,则设置组件的jQuery对象 if (!cpt.isInvisible) { if (cpt.type == "Page") { cpt._jqObj = $("body"); } else { cpt._jqObj = $("#" + cpt.id); } if (cpt._jqObj.length > 0) cpt.el = cpt._jqObj[0]; } } if (dataModel.components) { for (let i = 0; i < dataModel.components.length; i++) { let cdmChild = dataModel.components[i]; this.parseCpt(cdmChild, cpt); } } } /** * 输入项值改变时 * @param {[type]} iptSrc [description] * @return {[type]} [description] */ iptValueOnChange(iptSrc) { //判断有没有组件设置了计算表达式并关联了当前组件 if (!iptSrc.formulaIpts || iptSrc.formulaIpts.length == 0) return; for (let i = 0; i < iptSrc.formulaIpts.length; i++) { let iptF = this.components[iptSrc.formulaIpts[i]]; if (!iptF) continue; //如果是关联的后台服务组件,则重新发起请求,并重载相关组件的数据 if (iptF.type == "Service") { if (iptF.bindCpts && iptF.bindCpts.length > 0) { for (let j = 0; j < iptF.bindCpts.length; j++) { let cptBind = this.components[iptF.bindCpts[j]]; if (!cptBind) continue; if (cptBind.loadData) cptBind.loadData(); } } if (iptF.dataModel.onResponse) { iptF.request(); } return; } if (!iptF.dataModel.formula) continue; iptF.exeFormula(); } } /** * 初始化组件运行时 * @param {[type]} cpt [description] * @return {[type]} [description] */ initCptRuntime(cpt) { //如果组件定义了初始化运行时的方法,则在此执行 if (cpt["initRuntime"]) cpt.initRuntime(); //如果组件设置了计算表达式,则在关联的组件控制器上注册事件钩子 if (cpt.dataModel.formula) { let ipts = cpt.dataModel.formula.match(/\$\{[\w]+\}/g); for (let i = 0; i < ipts.length; i++) { let iptId = ipts[i].substr(2, ipts[i].length - 3); let cptMatched = this.components[iptId]; if (!cptMatched) continue; if (!cptMatched.formulaIpts) cptMatched.formulaIpts = []; if (!cptMatched.formulaIpts.contains(cpt.id)) cptMatched.formulaIpts.push(cpt.id); } } if (cpt.dataModel.components) { for (let i = 0; i < cpt.dataModel.components.length; i++) { let cdmChild = cpt.dataModel.components[i]; this.initCptRuntime(this.components[cdmChild.id]); } } } /** * 运行时解析页面 * @param {[type]} pageData [description] * @return {[type]} [description] */ parsePage(pageData) { //先解析所有组件并绑定其HTML元素 this.parseCpt(pageData); //再执行各个组件的初始化 //不能在解析组件时直接执行初始化 //因为关联的组件可能还未解析,会导致初始化出错 //例如Grid组件初始化时需要调用关联的Service组件 //如果该Service组件未解析,则就会出错 this.initCptRuntime(this.curPage); } /** * 设计时或编译时加载页面 * @param {[type]} pageData [description] * @return {[type]} [description] */ loadPage(pageData, cb) { if (!pageData) return; pageData.type = "Page"; let that = this; this.isLoadingPage = true; this.components = {}; this.loadComponentCategorys(pageData, function (categorys) { if (that.isDesigning) window.parent.uiDesigner.createCptLib(categorys); //先解析当前页面都有哪些类型的组件 let cptTypes = []; that.parseCptTypes(pageData, cptTypes); //加载TFP页面通用CSS $("head").append("<link rel=\"stylesheet\" type=\"text/css\" href=\"" + that.rootPath + "/src/tfp." + pageData.bgColorMode + ".css\"><\/link>"); if (pageData.client == "mini"){ $("head").append("<link rel=\"stylesheet\" type=\"text/css\" href=\"" + that.rootPath + "/src/wxfpfont.css\"></link>"); $("head").append("<link rel=\"stylesheet\" type=\"text/css\" href=\"" + that.rootPath + "/src/wx.css\"></link>"); } //然后动态加载这些组件的元数据和类 importCptFiles(that, pageData, cptTypes, function () { //加载页面引用的CSS if (pageData.cssFiles) { let cssFiles = pageData.cssFiles; if (typeof (cssFiles) == "string") cssFiles = [cssFiles]; for (let i = 0; i < cssFiles.length; i++) { $("head").append("<link rel=\"stylesheet\" type=\"text/css\" href=\"" + cssFiles[i] + "\"><\/link>"); } } that.render(pageData); if (that.isDesigning) { window.parent.uiDesigner.selectCpt(tfp.curPage.id); } that.isLoadingPage = false; if (cb) cb(); }); }); } /** * 绑定输入项数据 * @param {[type]} cdm [description] * @param {[type]} data [description] * @return {[type]} [description] */ bindCptData(cdm, data) { var cpt = this.get(cdm.id); //判断组件的各个属性,如果属性值是字符串类型,且属性值中有{}或#[],则进行数据绑定 for (let attrId in cpt.dataModel) { if (attrId == "id" || attrId == "type" || attrId == "formula") continue; let attrVal = cpt.dataModel[attrId]; if (attrVal && typeof (attrVal) == "string" && ((attrVal.indexOf("{") >= 0 && attrVal.indexOf("}") > 0) || (attrVal.indexOf("#[") >= 0 && attrVal.indexOf("]") > 0))) { let val = null; try { val = this.replaceDataField(data, attrVal); if (!isNull(val)) val = this.exeExpress(val); } catch (e) { console.log(e); } if (!isNull(val)) { //如果是数据绑定表达式,则设置组件的值 if (attrId == "dataBindingFormat") { cpt.value = val; } else if (attrId == "class") { val = val + ""; let arrClass = val.split(" "); for (let i = 0; i < arrClass.length; i++) { let strClass = arrClass[i]; if (strClass.trim() == "") continue; cpt._jqObj.addClass(strClass.trim()); } } else if (attrId == "style") { val = val + ""; let arrStyles = val.split(";"); for (let i = 0; i < arrStyles.length; i++) { let strStyle = arrStyles[i]; if (strStyle.trim() == "" || strStyle.indexOf(":") < 0) continue; let arrStyle = strStyle.split(":"); cpt._jqObj.css(arrStyle[0].trim(), arrStyle[1].trim()); } } else { cpt[attrId] = val; } } } } if (cpt.dataModel.components) { for (var i = 0; i < cpt.dataModel.components.length; i++) { this.bindCptData(cpt.dataModel.components[i], data); } } } /** * 获得组件类型定义信息(元数据) * @param {[type]} typeName [description] * @return {[type]} [description] */ type(typeName) { return this.metaDatas[typeName]; } /** * 初始化组件设计时相关设置 * 1、组件列表中添加组件节点 * 2、为组件设置点击事件处理器 * 3、禁止选中 * 4、设置鼠标按下和经过事件处理器 * @param {[type]} cpt [description] * @return {[type]} [description] */ initCptDesignSetting(cpt) { var node = window.parent.$("#cptTreeNode_" + cpt.id); if (node.length == 0) window.parent.uiDesigner.addCptTreeNode(cpt); cpt._jqObj.click(function () { if (cpt.isInvisible) { window.parent.uiDesigner.cptOnClick(window.parent.event, cpt.id); } else { window.parent.uiDesigner.cptOnClick(window.event, cpt.id); } }); cpt._jqObj.bind('selectstart', function () { return false; }); if (!cpt.isInvisible) { if (this.curPage.positionType == "absolute") { //鼠标按下时,准备移动组件 cpt._jqObj.mousedown(function () { window.parent.uiDesigner.cptOnMouseDown(cpt, window.event); }); } cpt._jqObj.mouseover(function () { window.parent.uiDesigner.cptOnMouseOver(cpt, window.event); }); } } }