tfp
Version:
A Web UI framework for TaskBuilder
1,570 lines (1,469 loc) • 46.8 kB
JavaScript
/**
* 动态引用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);
});
}
}
}