libf 2 anos atrás
pai
commit
c9f1992aea

+ 36 - 0
cncc_serverjs/script/cncc/API/sample1.js

@@ -0,0 +1,36 @@
+// 输入输出参数格式化
+input = INPUT;
+output = {};
+try {
+    input = decodeURIComponent(input);
+} catch (e) { }
+try {
+    input = base64.decode(input);
+} catch (e) { }
+try {
+    input = JSON.parse(input);
+    input = JSON.parse(input); // 解析可能存在的重复编码
+} catch (e) { }
+// 主执行阶段
+try {
+    // 示例处理过程,返回输入信息
+    output.sampledata = {
+        input: input,
+    };
+} catch (e) {
+    // 错误信息输出处理,抛出 ok 表示正常结束    
+    if (e != "ok") {
+        if (typeof (e) == "object") {
+            output.error = e;
+        } else if (typeof (e) == "string") {
+            output.error = "错误:" + e;
+        } else {
+            output.error = JSON.stringify(e);
+        }
+        log.error(output.error);
+        STATUS = "error";
+    }
+}
+// 返回输出信息
+OUTPUT = output;
+

+ 15 - 0
cncc_serverjs/script/cncc/API/sample2.js

@@ -0,0 +1,15 @@
+
+eval(dfs.read('/script/matrix/wframe/init.js'));
+
+function main(input) {
+    try {
+        x = "test3";
+        function a(){ return x; }
+        return {
+            input: input,
+            info: a(),
+        };
+    } catch(e) {
+        throw(e);
+    }
+}

+ 261 - 261
cncc_serverjs/script/matrix/utils/AlterClassByJson.js

@@ -1,261 +1,261 @@
-// 输入输出参数格式化
-input = INPUT;
-output = {};
-try {
-    input = decodeURIComponent(input);
-} catch(e) {}
-try {
-    input = base64.decode(input);
-} catch(e) {}
-try {
-    input = JSON.parse(input);
-    input = JSON.parse(input);
-} catch(e) {}
-output.info = {input:input};
-
-// 主执行阶段
-try {
-    if (!input.classname) { // like /cncc/itil/project
-        throw ("需要指定classname");
-    }
-    if (input.classname[0] != "/") { // like /cncc/itil/project
-        throw ("classname必须以 / 开头");
-    }
-    if (!input.data || typeof(input.data)!="object") {
-        throw ("data必须指定为一个对象");
-    }
-    // 检查父类是否存在,不存在就创建
-    cns = input.classname.split("/");
-    clsname = "";
-    for (var cni = 1; cni < cns.length - 1; cni++) {
-        clsname += "/" + cns[cni];
-        odb.mql("create class if not exists " + clsname + "()");
-    }
-    pclsname = clsname;
-    clsname += "/" + cns[cns.length - 1];
-
-    // 提取现有类的字段信息
-    clsexist = false;
-    clsfields = {};
-    try {
-        fieldslist = odb.classfields(clsname);
-        for (var fi = 0; fi < fieldslist.length; fi++) {
-            fld = fieldslist[fi];
-            fname = fld.name;
-            if (/^\w+\:.*/.test(fname)) {
-                fname = fname.replace(/^\w+\:/, ""); 
-            }
-            if (fname && fld.ftype) {
-                clsfields[fname] = {
-                    iskey: fld.iskey,
-                    ftype: fld.ftype,
-                };
-            }
-        }
-        clsexist = true;
-    } catch(e) {}
-    if (!clsexist) {
-        try {
-            fieldslist = odb.classfields(pclsname);
-            for (var fi = 0; fi < fieldslist.length; fi++) {
-                fld = fieldslist[fi];
-                fname = fld.name;
-                if (/^\w+\:.*/.test(fname)) {
-                    fname = fname.replace(/^\w+\:/, ""); 
-                }
-                if (fname && fld.ftype) {
-                    clsfields[fname] = {
-                        iskey: fld.iskey,
-                        ftype: fld.ftype,
-                    };
-                }
-            }
-        } catch(e) {}
-    }
-    output.info.clsfields = clsfields;
-
-    // 通过参数确定的字段类型信息
-    fields = input.fields;
-    if (!fields) {
-        fields = {};
-    }
-    // 字段名映射,参数中指定的字段名均为JSON对象中的属性名,默认将 camelStyle 转换为 snake_style
-    fieldmap = input.fieldmap;
-    if (!fieldmap) {
-        fieldmap = {};
-    }
-    // 反向字段名映射,类中的字段名映射为JSON对象中的属性名
-    xfieldmap = {};
-    // 类中的字段名列表,用于排序
-    xfieldslist = [];
-    // 类字段类型信息
-    xfields = {};
-    xpks = [];
-    for (var jk in input.data) {
-        xk = fieldmap[jk];
-        // 通过参数确定的字段类型信息
-        if (!xk) {
-            // 默认将 camelStyle 转换为 snake_style
-            xk = "j_"; // 区别于其它字段,自动创建的字段以 j_ 开头
-            for (var i = 0; i < jk.length; i++) {
-                if (jk[i] >= 'A' && jk[i] <= 'Z') {
-                    xk += "_" + jk[i].toLowerCase();
-                } else {
-                    xk += jk[i];
-                }
-            }
-            fieldmap[jk] = xk;
-        }
-        xfieldslist.push(xk);
-        xfieldmap[xk] = jk;
-        dt = fields[jk];
-        if (dt && dt.indexOf(",key") > 0) {
-            dt = dt.replace(",key", "");
-            xpks.push(xk);
-        }
-        switch (dt) {
-        case "date":
-        case "time":
-        case "datetime":
-            dt = "timestamp";
-            break;
-        case "int":
-        case "integer":
-            dt = "bigint";
-            break;
-        case "number":
-        case "float":
-            dt = "double";
-            break;
-        case "text":
-            dt = "text";
-            break;
-        case "string":
-            dt = "varchar";
-            break;
-        case "boolean":
-            dt = "boolean";
-            break;
-        }
-        if (!dt) {
-            // 没有明确定义的字段类型
-            // 根据数据判断类型
-            dt = "varchar";
-            d = input.data[jk];
-            if (d || d == "" || d == 0 || d == false) { 
-                switch (typeof(d)) {
-                case 'object':
-                    // 转为text
-                    dt = "text"; 
-                    break;
-                case 'number':
-                    // 是否为整数
-                    if ((""+d).indexOf(".")<0) {
-                        dt = "bigint";
-                    } else {
-                        dt = "double";
-                    }
-                    break;
-                case 'boolean':
-                    dt = "boolean";
-                    break;
-                case 'string':
-                default:
-                    // 是否为日期时间
-                    if (/_time/.test(xk) || /_date/.test(xk)) {
-                        dt = "timestamp";
-                    } else {
-                        dt = "varchar";
-                    }
-                    break;
-                }
-            } else {
-                if (/_time/.test(xk) || /_date/.test(xk)) {
-                    dt = "timestamp";
-                } else {
-                    dt = "varchar";
-                }
-            }
-        }
-        xfields[xk] = dt;
-    }
-    output.info.xfields = xfields;
-    
-    if (!clsexist) {
-        // 类不存在,自动创建类
-        mql = "create class if not exists " + clsname + "(";
-        indexes = "indexes(";
-        for (var fi = 0; fi < xfieldslist.length; fi++) {
-            xk = xfieldslist[fi];
-            if (xk in {"id":"", "class":"", "name":"", "day":"", "tags":"", "vtime":""}) {
-                throw("内部使用字段名 " + xk + ",需要映射成其它名称");
-            }
-            if (clsfields[xk] && clsfields[xk].ftype != xfields[xk]) {
-                throw ("类继承字段 "+ xk +" 信息不一致,"+clsfields[xk].ftype + "!=" + xfields[xk]+",需手动干预");
-            }
-            mql += fi==0 ? "\n": ",\n";
-            mql += xk + " " + xfields[xk];
-            if (fi > 0) {
-                indexes += ",";
-            }
-            indexes += xk;
-        }
-        indexes += ")";
-        mql += ",\n" + indexes;
-        if (xpks.length > 0) {
-            mql += ",\n";
-            mql += "keys(";
-            for (var pki = 0; pki < xpks.length; pki++) {
-                if (pki > 0) {
-                    mql += ",";
-                }
-                mql += xpks[pki];
-            }
-            mql += ")";
-        }
-        mql += "\n";
-        mql += ")";
-        if (input.clsoption) {
-            mql += input.clsoption;
-        }
-        odb.mql(mql);
-        output.info = {mql:mql};
-    } else {
-        // 类已存在,检查主键信息是否存在
-        for (var pki = 0; pki < xpks.length; pki++) {
-            xk = xpks[pki];
-            if (!clsfields[xk] || !clsfields[xk].iskey) {
-                throw ("已经存在同名类主键 "+ xk +" 信息不一致,需手动干预");
-            }
-        }
-        // 追加字段
-        mql = "alter class " + clsname + " add index column";
-        addn = 0;
-        for (var fi = 0; fi < xfieldslist.length; fi++) {
-            xk = xfieldslist[fi];
-            if (!clsfields[xk]) {
-                mql += (addn == 0)?" ":", ";
-                mql += xk + " " + xfields[xk];
-                addn++;
-            } else if (clsfields[xk].ftype != xfields[xk]) {
-                throw ("已经存在同名类字段 "+ xk +" 信息不一致,需手动干预");
-            }
-        }
-        if (addn > 0) {
-            odb.mql(mql);
-            output.info = {mql:mql};
-        }
-    }
-} catch(e) {
-    if (typeof(e) == "object") {
-        output.error = e;
-    } else if (typeof(e) == "string") {
-        output.error = "错误:" + e;
-    } else {
-        output.error = JSON.stringify(e);
-    }
-}
-
-// 返回输出信息
-OUTPUT = output;
-
+// 输入输出参数格式化
+input = INPUT;
+output = {};
+try {
+    input = decodeURIComponent(input);
+} catch(e) {}
+try {
+    input = base64.decode(input);
+} catch(e) {}
+try {
+    input = JSON.parse(input);
+    input = JSON.parse(input);
+} catch(e) {}
+output.info = {input:input};
+
+// 主执行阶段
+try {
+    if (!input.classname) { // like /cncc/itil/project
+        throw ("需要指定classname");
+    }
+    if (input.classname[0] != "/") { // like /cncc/itil/project
+        throw ("classname必须以 / 开头");
+    }
+    if (!input.data || typeof(input.data)!="object") {
+        throw ("data必须指定为一个对象");
+    }
+    // 检查父类是否存在,不存在就创建
+    cns = input.classname.split("/");
+    clsname = "";
+    for (var cni = 1; cni < cns.length - 1; cni++) {
+        clsname += "/" + cns[cni];
+        odb.mql("create class if not exists " + clsname + "()");
+    }
+    pclsname = clsname;
+    clsname += "/" + cns[cns.length - 1];
+
+    // 提取现有类的字段信息
+    clsexist = false;
+    clsfields = {};
+    try {
+        fieldslist = odb.classfields(clsname);
+        for (var fi = 0; fi < fieldslist.length; fi++) {
+            fld = fieldslist[fi];
+            fname = fld.name;
+            if (/^\w+\:.*/.test(fname)) {
+                fname = fname.replace(/^\w+\:/, ""); 
+            }
+            if (fname && fld.ftype) {
+                clsfields[fname] = {
+                    iskey: fld.iskey,
+                    ftype: fld.ftype,
+                };
+            }
+        }
+        clsexist = true;
+    } catch(e) {}
+    if (!clsexist) {
+        try {
+            fieldslist = odb.classfields(pclsname);
+            for (var fi = 0; fi < fieldslist.length; fi++) {
+                fld = fieldslist[fi];
+                fname = fld.name;
+                if (/^\w+\:.*/.test(fname)) {
+                    fname = fname.replace(/^\w+\:/, ""); 
+                }
+                if (fname && fld.ftype) {
+                    clsfields[fname] = {
+                        iskey: fld.iskey,
+                        ftype: fld.ftype,
+                    };
+                }
+            }
+        } catch(e) {}
+    }
+    output.info.clsfields = clsfields;
+
+    // 通过参数确定的字段类型信息
+    fields = input.fields;
+    if (!fields) {
+        fields = {};
+    }
+    // 字段名映射,参数中指定的字段名均为JSON对象中的属性名,默认将 camelStyle 转换为 snake_style
+    fieldmap = input.fieldmap;
+    if (!fieldmap) {
+        fieldmap = {};
+    }
+    // 反向字段名映射,类中的字段名映射为JSON对象中的属性名
+    xfieldmap = {};
+    // 类中的字段名列表,用于排序
+    xfieldslist = [];
+    // 类字段类型信息
+    xfields = {};
+    xpks = [];
+    for (var jk in input.data) {
+        xk = fieldmap[jk];
+        // 通过参数确定的字段类型信息
+        if (!xk) {
+            // 默认将 camelStyle 转换为 snake_style
+            xk = "j_"; // 区别于其它字段,自动创建的字段以 j_ 开头
+            for (var i = 0; i < jk.length; i++) {
+                if (jk[i] >= 'A' && jk[i] <= 'Z') {
+                    xk += "_" + jk[i].toLowerCase();
+                } else {
+                    xk += jk[i];
+                }
+            }
+            fieldmap[jk] = xk;
+        }
+        xfieldslist.push(xk);
+        xfieldmap[xk] = jk;
+        dt = fields[jk];
+        if (dt && dt.indexOf(",key") > 0) {
+            dt = dt.replace(",key", "");
+            xpks.push(xk);
+        }
+        switch (dt) {
+        case "date":
+        case "time":
+        case "datetime":
+            dt = "timestamp";
+            break;
+        case "int":
+        case "integer":
+            dt = "bigint";
+            break;
+        case "number":
+        case "float":
+            dt = "double";
+            break;
+        case "text":
+            dt = "text";
+            break;
+        case "string":
+            dt = "varchar";
+            break;
+        case "boolean":
+            dt = "boolean";
+            break;
+        }
+        if (!dt) {
+            // 没有明确定义的字段类型
+            // 根据数据判断类型
+            dt = "varchar";
+            d = input.data[jk];
+            if (d || d == "" || d == 0 || d == false) { 
+                switch (typeof(d)) {
+                case 'object':
+                    // 转为text
+                    dt = "text"; 
+                    break;
+                case 'number':
+                    // 是否为整数
+                    if ((""+d).indexOf(".")<0) {
+                        dt = "bigint";
+                    } else {
+                        dt = "double";
+                    }
+                    break;
+                case 'boolean':
+                    dt = "boolean";
+                    break;
+                case 'string':
+                default:
+                    // 是否为日期时间
+                    if (/_time/.test(xk) || /_date/.test(xk)) {
+                        dt = "timestamp";
+                    } else {
+                        dt = "varchar";
+                    }
+                    break;
+                }
+            } else {
+                if (/_time/.test(xk) || /_date/.test(xk)) {
+                    dt = "timestamp";
+                } else {
+                    dt = "varchar";
+                }
+            }
+        }
+        xfields[xk] = dt;
+    }
+    output.info.xfields = xfields;
+    
+    if (!clsexist) {
+        // 类不存在,自动创建类
+        mql = "create class if not exists " + clsname + "(";
+        indexes = "indexes(";
+        for (var fi = 0; fi < xfieldslist.length; fi++) {
+            xk = xfieldslist[fi];
+            if (xk in {"id":"", "class":"", "name":"", "day":"", "tags":"", "vtime":""}) {
+                throw("内部使用字段名 " + xk + ",需要映射成其它名称");
+            }
+            if (clsfields[xk] && clsfields[xk].ftype != xfields[xk]) {
+                throw ("类继承字段 "+ xk +" 信息不一致,"+clsfields[xk].ftype + "!=" + xfields[xk]+",需手动干预");
+            }
+            mql += fi==0 ? "\n": ",\n";
+            mql += xk + " " + xfields[xk];
+            if (fi > 0) {
+                indexes += ",";
+            }
+            indexes += xk;
+        }
+        indexes += ")";
+        mql += ",\n" + indexes;
+        if (xpks.length > 0) {
+            mql += ",\n";
+            mql += "keys(";
+            for (var pki = 0; pki < xpks.length; pki++) {
+                if (pki > 0) {
+                    mql += ",";
+                }
+                mql += xpks[pki];
+            }
+            mql += ")";
+        }
+        mql += "\n";
+        mql += ")";
+        if (input.clsoption) {
+            mql += input.clsoption;
+        }
+        odb.mql(mql);
+        output.info = {mql:mql};
+    } else {
+        // 类已存在,检查主键信息是否存在
+        for (var pki = 0; pki < xpks.length; pki++) {
+            xk = xpks[pki];
+            if (!clsfields[xk] || !clsfields[xk].iskey) {
+                throw ("已经存在同名类主键 "+ xk +" 信息不一致,需手动干预");
+            }
+        }
+        // 追加字段
+        mql = "alter class " + clsname + " add index column";
+        addn = 0;
+        for (var fi = 0; fi < xfieldslist.length; fi++) {
+            xk = xfieldslist[fi];
+            if (!clsfields[xk]) {
+                mql += (addn == 0)?" ":", ";
+                mql += xk + " " + xfields[xk];
+                addn++;
+            } else if (clsfields[xk].ftype != xfields[xk]) {
+                throw ("已经存在同名类字段 "+ xk +" 信息不一致,需手动干预");
+            }
+        }
+        if (addn > 0) {
+            odb.mql(mql);
+            output.info = {mql:mql};
+        }
+    }
+} catch(e) {
+    if (typeof(e) == "object") {
+        output.error = e;
+    } else if (typeof(e) == "string") {
+        output.error = "错误:" + e;
+    } else {
+        output.error = JSON.stringify(e);
+    }
+}
+
+// 返回输出信息
+OUTPUT = output;
+

+ 326 - 0
cncc_serverjs/script/matrix/utils/InitByJsonData.js

@@ -0,0 +1,326 @@
+
+//默认值设置
+defaultinput = {
+    server: "http://172.23.12.228:8080",
+    author: base64.encode("meta.admin:admin"),
+    istesting: true,
+    classname: "/cncc/action/test",
+    data: null,
+    datafiledir: "/opt/cncc/ITIL/change_main",
+    datafilename: "",
+    jsfilename: "/script/cncc/ITIL/测试.js",
+    clsoption: "with ttl=10 day, version=true, nickname='test'",
+    fieldmap: {id: "jid"},
+    fields: {idUnique: "string,key"},
+    mustfield: "id,idUnique",
+};
+inputmapping = {
+    "change": {
+        classname: "/cncc/action/change_main",
+        datafiledir: "/opt/cncc/ITIL/change_main",
+        jsfilename: "/script/cncc/ITIL/变更单.js",
+        clsoption: "with ttl=10 day, version=true, nickname='change_main'",
+    },
+    "event": {
+        classname: "/cncc/action/event",
+        datafiledir: "/opt/cncc/ITIL/event",
+        jsfilename: "/script/cncc/ITIL/事件单.js",
+        clsoption: "with ttl=10 day, version=true, nickname='event'",
+    },
+    "problem": {
+        classname: "/cncc/action/problem",
+        datafiledir: "/opt/cncc/ITIL/problem",
+        jsfilename: "/script/cncc/ITIL/问题单.js",
+        clsoption: "with ttl=10 day, version=true, nickname='problem'",
+    },
+    "baobei": {
+        classname: "/cncc/action/baobei",
+        datafiledir: "/opt/cncc/ITIL/baobei",
+        jsfilename: "/script/cncc/ITIL/报备.js",
+        clsoption: "with ttl=10 day, version=true, nickname='baobei'",
+    },
+    "shebeishangxiadian": {
+        classname: "/cncc/action/shebeishangxiadian",
+        datafiledir: "/opt/cncc/ITIL/shebeishangxiadian",
+        jsfilename: "/script/cncc/ITIL/设备上下电.js",
+        clsoption: "with ttl=10 day, version=true, nickname='shebeishangxiadian'",
+    },
+    "shujuhuoqu": {
+        classname: "/cncc/action/shujuhuoqu",
+        datafiledir: "/opt/cncc/ITIL/shujuhuoqu",
+        jsfilename: "/script/cncc/ITIL/数据获取.js",
+        clsoption: "with ttl=10 day, version=true, nickname='shujuhuoqu'",
+    },
+    "yanlian": {
+        classname: "/cncc/action/yanlian",
+        datafiledir: "/opt/cncc/ITIL/yanlian",
+        jsfilename: "/script/cncc/ITIL/应急演练.js",
+        clsoption: "with ttl=10 day, version=true, nickname='yanlian'",
+    },
+    "project": {
+        classname: "/cncc/action/project",
+        datafiledir: "/opt/cncc/ITIL/project",
+        jsfilename: "/script/cncc/ITIL/项目实施或巡检.js",
+        clsoption: "with ttl=10 day, version=true, nickname='project'",
+    }
+};
+
+// 输入输出参数格式化
+input = INPUT;
+output = {};
+try {
+    input = decodeURIComponent(input);
+} catch(e) {}
+try {
+    input = base64.decode(input);
+} catch(e) {}
+try {
+    input = JSON.parse(input);
+    input = JSON.parse(input);
+} catch(e) {}
+
+// 通用函数
+function isempty(o) {
+    if (o) {
+        for (var k in o){
+            return false;
+        }
+    } 
+    return true;
+}
+
+// 主执行阶段
+function main() {
+    output.info = {};
+    output.info.p0 = {name: "确认参数"};
+    p = inputmapping[input.name];
+    if (p) {
+        for (var k in p) {
+            defaultinput[k] = p[k];
+        }
+    }
+    server = input.server;
+    if (!server) {
+        server = defaultinput.server;
+    }
+    author = input.author;
+    if (!author) {
+        author = defaultinput.author;
+    }
+    istesting = input.istesting;
+    if (!istesting) {
+        istesting = defaultinput.istesting;
+    }
+    classname = input.classname;
+    if (!classname) {
+        classname = defaultinput.classname;
+    }
+    if (classname[0] != "/") {
+        throw ("classname必须以 / 开头");
+    }
+    if (classname.substring(0,8) == "/matrix/") {
+        throw ("classname不能以 /matrix/ 开头");
+    }
+    data = input.data;
+    if (isempty(data)) {
+        data = defaultinput.data;
+        if (isempty(data)) {
+            datafilename = input.datafilename;
+            if (!datafilename) {
+                datafilename = defaultinput.datafilename;
+            }
+            if (datafilename) {
+                try {
+                    data = dfs.read(datafilename);
+                    data = JSON.parse(data);
+                } catch(e) {}
+            }
+        }
+        if (isempty(data)) {
+            datafiledir = input.datafiledir;
+            if (!datafiledir) {
+                if (classname == defaultinput.classname) {
+                    datafiledir = defaultinput.datafiledir;
+                } else {
+                    datafiledir = "/opt" + classname;
+                }
+            }
+            // 读取所有文件,综合数据
+            data = {};
+            files = dfs.readdir(datafiledir);
+            for (i = 0; i < files.length; i++) { 
+                try {
+                    adat = dfs.read(files[i].fullname);
+                    adat = JSON.parse(adat);
+                    if (typeof(adat) != "object") {
+                        throw("只接收JSON对象数据");
+                    }
+                    for (var k in adat) {
+                        if (!data[k]) {
+                            data[k] = adat[k];
+                        } else if (adat[k]) {
+                            if (typeof(adat[k]) == "object") {
+                                if (JSON.stringify(adat[k]).length > JSON.stringify(data[k]).length) {
+                                    data[k] = adat[k];
+                                }
+                            } else if (typeof(adat[k]) == "string") {
+                                if (typeof(data[k]) != "string") {
+                                    data[k] = adat[k];
+                                } else if (adat[k].length > data[k].length) {
+                                    data[k] = adat[k];
+                                }
+                            } else if (typeof(adat[k]) == "number") {
+                                if (typeof(data[k]) == "number") {
+                                    if ((""+adat[k]).indexOf(".")>=0) {
+                                        data[k] = adat[k];
+                                    }
+                                }
+                            } else if (typeof(adat[k]) == "boolean") {
+                                if (typeof(data[k]) != "boolean") {
+                                    data[k] = ""+adat[k];
+                                }
+                            }
+                        }
+                    }
+                } catch(e) {}
+            }
+        }
+    }
+    jsfilename = input.jsfilename;
+    if (!jsfilename) {
+        jsfilename = defaultinput.jsfilename;
+    }
+    clsoption = input.clsoption;
+    if (!clsoption) {
+        clsoption = defaultinput.clsoption;
+    }
+    fieldmap = input.fieldmap;
+    if (!fieldmap) {
+        fieldmap = defaultinput.fieldmap;
+    }
+    mustfield = input.mustfield;
+    if (!mustfield) {
+        mustfield = defaultinput.mustfield;
+    }
+    fields = input.fields;
+    if (!fields) {
+        fields = defaultinput.fields;
+    }
+    reqinput = {
+        istesting: istesting,
+        classname: classname, 
+        jsfilename: jsfilename,
+        clsoption: clsoption, 
+        fieldmap: fieldmap,
+        fields: fields,
+        mustfield: mustfield,
+        data: data,
+    };
+    reqinput = encodeURIComponent(JSON.stringify(reqinput));
+    output.info.p1 = {name:"生成类"};
+    http.do("POST", 
+        server+"/script/exec/js?filepath=/matrix/utils/AlterClassByJson.js",
+        {
+            "Authorization": "Basic "+author,
+            "Content-Type": "application/x-www-form-urlencoded",
+            "Data-Type": "json"
+        },
+        'input='+reqinput,
+        function(response){
+            // success func
+            ret = response.data;
+            if (ret.message) {
+                output.info.p1.result = ret.message;
+            } else {
+                output.info.p1.result = ret;
+            }
+        },
+        function(response){
+            // error func
+            output.error = response.data;
+        });
+    if (output.error || output.info.p1.result.error) {
+        return;
+    }
+    output.info.p2 = {name:"生成脚本"};
+    http.do("POST", 
+        server+"/script/exec/js?filepath=/matrix/utils/JsonImporterGen.js&input="+reqinput,
+        {"Authorization": "Basic "+author},
+        '',
+        function(response){
+            // success func
+            ret = response.data;
+            if (ret.message) {
+                output.info.p2.result = ret.message;
+            } else {
+                output.info.p2.result = ret;
+            }
+        },
+        function(response){
+            // error func
+            output.error = response.data;
+        });
+    if (output.error || output.info.p2.result.error) {
+        return;
+    }
+    output.info.p2x = {name:"激活脚本"};
+    calljsfp = encodeURIComponent(jsfilename.replace(/\/script/, ""));
+    http.do("POST", 
+        server+"/fs/tolocal/script"+calljsfp+"?issys=true",
+        {"Authorization": "Basic "+author},
+        '',
+        function(response){
+            // success func
+            ret = response.data;
+            if (ret.message) {
+                output.info.p2x.result = ret.message;
+            } else {
+                output.info.p2x.result = ret;
+            }
+        },
+        function(response){
+            // error func
+            output.error = response.data;
+        });
+    if (output.error || output.info.p2x.result.error) {
+        return;
+    }
+    output.info.p3 = {name:"插入数据"};
+    reqinput = encodeURIComponent(base64.encode(JSON.stringify(data)));
+    calljsfp = encodeURIComponent(jsfilename.replace(/\/script/, ""));
+    http.do("POST", 
+        server+"/script/exec/js?filepath="+calljsfp+"&input="+reqinput,
+        {"Authorization": "Basic "+author},
+        '',
+        function(response){
+            // success func
+            ret = response.data;
+            if (ret.message) {
+                output.info.p3.result = ret.message;
+            } else {
+                output.info.p3.result = ret;
+            }
+        },
+        function(response){
+            // error func
+            output.error = response.data;
+        });
+    if (output.error || output.info.p3.result.error) {
+        return;
+    }
+    output.info.p4 = {name:"完成"};
+}
+try {
+    main();
+} catch(e) {
+    if (typeof(e) == "object") {
+        output.error = e;
+    } else if (typeof(e) == "string") {
+        output.error = "错误:" + e;
+    } else {
+        output.error = JSON.stringify(e);
+    }
+}
+
+// 返回输出信息
+OUTPUT = output;

+ 326 - 1
cncc_serverjs/script/matrix/utils/InitJsonImporter.js

@@ -1 +1,326 @@
-null
+
+//默认值设置
+defaultinput = {
+    server: "http://172.23.12.228:8080",
+    author: base64.encode("meta.admin:admin"),
+    istesting: true,
+    classname: "/cncc/action/test",
+    data: null,
+    datafiledir: "/opt/cncc/ITIL/change_main",
+    datafilename: "",
+    jsfilename: "/script/cncc/ITIL/测试.js",
+    clsoption: "with ttl=10 day, version=true, nickname='test'",
+    fieldmap: {id: "jid"},
+    fields: {idUnique: "string,key"},
+    mustfield: "id,idUnique",
+};
+inputmapping = {
+    "change": {
+        classname: "/cncc/action/change_main",
+        datafiledir: "/opt/cncc/ITIL/change_main",
+        jsfilename: "/script/cncc/ITIL/变更单.js",
+        clsoption: "with ttl=10 day, version=true, nickname='change_main'",
+    },
+    "event": {
+        classname: "/cncc/action/event",
+        datafiledir: "/opt/cncc/ITIL/event",
+        jsfilename: "/script/cncc/ITIL/事件单.js",
+        clsoption: "with ttl=10 day, version=true, nickname='event'",
+    },
+    "problem": {
+        classname: "/cncc/action/problem",
+        datafiledir: "/opt/cncc/ITIL/problem",
+        jsfilename: "/script/cncc/ITIL/问题单.js",
+        clsoption: "with ttl=10 day, version=true, nickname='problem'",
+    },
+    "baobei": {
+        classname: "/cncc/action/baobei",
+        datafiledir: "/opt/cncc/ITIL/baobei",
+        jsfilename: "/script/cncc/ITIL/报备.js",
+        clsoption: "with ttl=10 day, version=true, nickname='baobei'",
+    },
+    "shebeishangxiadian": {
+        classname: "/cncc/action/shebeishangxiadian",
+        datafiledir: "/opt/cncc/ITIL/shebeishangxiadian",
+        jsfilename: "/script/cncc/ITIL/设备上下电.js",
+        clsoption: "with ttl=10 day, version=true, nickname='shebeishangxiadian'",
+    },
+    "shujuhuoqu": {
+        classname: "/cncc/action/shujuhuoqu",
+        datafiledir: "/opt/cncc/ITIL/shujuhuoqu",
+        jsfilename: "/script/cncc/ITIL/数据获取.js",
+        clsoption: "with ttl=10 day, version=true, nickname='shujuhuoqu'",
+    },
+    "yanlian": {
+        classname: "/cncc/action/yanlian",
+        datafiledir: "/opt/cncc/ITIL/yanlian",
+        jsfilename: "/script/cncc/ITIL/应急演练.js",
+        clsoption: "with ttl=10 day, version=true, nickname='yanlian'",
+    },
+    "project": {
+        classname: "/cncc/action/project",
+        datafiledir: "/opt/cncc/ITIL/project",
+        jsfilename: "/script/cncc/ITIL/项目实施或巡检.js",
+        clsoption: "with ttl=10 day, version=true, nickname='project'",
+    }
+};
+
+// 输入输出参数格式化
+input = INPUT;
+output = {};
+try {
+    input = decodeURIComponent(input);
+} catch(e) {}
+try {
+    input = base64.decode(input);
+} catch(e) {}
+try {
+    input = JSON.parse(input);
+    input = JSON.parse(input);
+} catch(e) {}
+
+// 通用函数
+function isempty(o) {
+    if (o) {
+        for (var k in o){
+            return false;
+        }
+    } 
+    return true;
+}
+
+// 主执行阶段
+function main() {
+    output.info = {};
+    output.info.p0 = {name: "确认参数"};
+    p = inputmapping[input.name];
+    if (p) {
+        for (var k in p) {
+            defaultinput[k] = p[k];
+        }
+    }
+    server = input.server;
+    if (!server) {
+        server = defaultinput.server;
+    }
+    author = input.author;
+    if (!author) {
+        author = defaultinput.author;
+    }
+    istesting = input.istesting;
+    if (!istesting) {
+        istesting = defaultinput.istesting;
+    }
+    classname = input.classname;
+    if (!classname) {
+        classname = defaultinput.classname;
+    }
+    if (classname[0] != "/") {
+        throw ("classname必须以 / 开头");
+    }
+    if (classname.substring(0,8) == "/matrix/") {
+        throw ("classname不能以 /matrix/ 开头");
+    }
+    data = input.data;
+    if (isempty(data)) {
+        data = defaultinput.data;
+        if (isempty(data)) {
+            datafilename = input.datafilename;
+            if (!datafilename) {
+                datafilename = defaultinput.datafilename;
+            }
+            if (datafilename) {
+                try {
+                    data = dfs.read(datafilename);
+                    data = JSON.parse(data);
+                } catch(e) {}
+            }
+        }
+        if (isempty(data)) {
+            datafiledir = input.datafiledir;
+            if (!datafiledir) {
+                if (classname == defaultinput.classname) {
+                    datafiledir = defaultinput.datafiledir;
+                } else {
+                    datafiledir = "/opt" + classname;
+                }
+            }
+            // 读取所有文件,综合数据
+            data = {};
+            files = dfs.readdir(datafiledir);
+            for (i = 0; i < files.length; i++) { 
+                try {
+                    adat = dfs.read(files[i].fullname);
+                    adat = JSON.parse(adat);
+                    if (typeof(adat) != "object") {
+                        throw("只接收JSON对象数据");
+                    }
+                    for (var k in adat) {
+                        if (!data[k]) {
+                            data[k] = adat[k];
+                        } else if (adat[k]) {
+                            if (typeof(adat[k]) == "object") {
+                                if (JSON.stringify(adat[k]).length > JSON.stringify(data[k]).length) {
+                                    data[k] = adat[k];
+                                }
+                            } else if (typeof(adat[k]) == "string") {
+                                if (typeof(data[k]) != "string") {
+                                    data[k] = adat[k];
+                                } else if (adat[k].length > data[k].length) {
+                                    data[k] = adat[k];
+                                }
+                            } else if (typeof(adat[k]) == "number") {
+                                if (typeof(data[k]) == "number") {
+                                    if ((""+adat[k]).indexOf(".")>=0) {
+                                        data[k] = adat[k];
+                                    }
+                                }
+                            } else if (typeof(adat[k]) == "boolean") {
+                                if (typeof(data[k]) != "boolean") {
+                                    data[k] = ""+adat[k];
+                                }
+                            }
+                        }
+                    }
+                } catch(e) {}
+            }
+        }
+    }
+    jsfilename = input.jsfilename;
+    if (!jsfilename) {
+        jsfilename = defaultinput.jsfilename;
+    }
+    clsoption = input.clsoption;
+    if (!clsoption) {
+        clsoption = defaultinput.clsoption;
+    }
+    fieldmap = input.fieldmap;
+    if (!fieldmap) {
+        fieldmap = defaultinput.fieldmap;
+    }
+    mustfield = input.mustfield;
+    if (!mustfield) {
+        mustfield = defaultinput.mustfield;
+    }
+    fields = input.fields;
+    if (!fields) {
+        fields = defaultinput.fields;
+    }
+    reqinput = {
+        istesting: istesting,
+        classname: classname, 
+        jsfilename: jsfilename,
+        clsoption: clsoption, 
+        fieldmap: fieldmap,
+        fields: fields,
+        mustfield: mustfield,
+        data: data,
+    };
+    reqinput = encodeURIComponent(JSON.stringify(reqinput));
+    output.info.p1 = {name:"生成类"};
+    http.do("POST", 
+        server+"/script/exec/js?filepath=/matrix/utils/AlterClassByJson.js",
+        {
+            "Authorization": "Basic "+author,
+            "Content-Type": "application/x-www-form-urlencoded",
+            "Data-Type": "json"
+        },
+        'input='+reqinput,
+        function(response){
+            // success func
+            ret = response.data;
+            if (ret.message) {
+                output.info.p1.result = ret.message;
+            } else {
+                output.info.p1.result = ret;
+            }
+        },
+        function(response){
+            // error func
+            output.error = response.data;
+        });
+    if (output.error || output.info.p1.result.error) {
+        return;
+    }
+    output.info.p2 = {name:"生成脚本"};
+    http.do("POST", 
+        server+"/script/exec/js?filepath=/matrix/utils/JsonImporterGen.js&input="+reqinput,
+        {"Authorization": "Basic "+author},
+        '',
+        function(response){
+            // success func
+            ret = response.data;
+            if (ret.message) {
+                output.info.p2.result = ret.message;
+            } else {
+                output.info.p2.result = ret;
+            }
+        },
+        function(response){
+            // error func
+            output.error = response.data;
+        });
+    if (output.error || output.info.p2.result.error) {
+        return;
+    }
+    output.info.p2x = {name:"激活脚本"};
+    calljsfp = encodeURIComponent(jsfilename.replace(/\/script/, ""));
+    http.do("POST", 
+        server+"/fs/tolocal/script"+calljsfp+"?issys=true",
+        {"Authorization": "Basic "+author},
+        '',
+        function(response){
+            // success func
+            ret = response.data;
+            if (ret.message) {
+                output.info.p2x.result = ret.message;
+            } else {
+                output.info.p2x.result = ret;
+            }
+        },
+        function(response){
+            // error func
+            output.error = response.data;
+        });
+    if (output.error || output.info.p2x.result.error) {
+        return;
+    }
+    output.info.p3 = {name:"插入数据"};
+    reqinput = encodeURIComponent(base64.encode(JSON.stringify(data)));
+    calljsfp = encodeURIComponent(jsfilename.replace(/\/script/, ""));
+    http.do("POST", 
+        server+"/script/exec/js?filepath="+calljsfp+"&input="+reqinput,
+        {"Authorization": "Basic "+author},
+        '',
+        function(response){
+            // success func
+            ret = response.data;
+            if (ret.message) {
+                output.info.p3.result = ret.message;
+            } else {
+                output.info.p3.result = ret;
+            }
+        },
+        function(response){
+            // error func
+            output.error = response.data;
+        });
+    if (output.error || output.info.p3.result.error) {
+        return;
+    }
+    output.info.p4 = {name:"完成"};
+}
+try {
+    main();
+} catch(e) {
+    if (typeof(e) == "object") {
+        output.error = e;
+    } else if (typeof(e) == "string") {
+        output.error = "错误:" + e;
+    } else {
+        output.error = JSON.stringify(e);
+    }
+}
+
+// 返回输出信息
+OUTPUT = output;

+ 72 - 72
cncc_serverjs/script/matrix/utils/JsonImporter.template.js

@@ -1,72 +1,72 @@
-// ___classname___ JSON数据导入程序
-// ___datetime_now___ 由 JsonImportGen.js 自动生成,请勿手动修改
-    
-// 输入输出参数格式化
-input = INPUT;
-try {
-    input = decodeURIComponent(input);
-} catch(e) {}
-try {
-    input = base64.decode(input);
-} catch(e) {}
-try {
-    input = JSON.parse(input);
-    input = JSON.parse(input);
-} catch(e) {}
-output = {};
-
-istesting = ___istesting___;
-function teststore() {
-    // 输入JSON临时存入DFS
-    dir = "/opt___classname___";
-    dtm = new Date().toJSON().replace(/[\-\:\.TZ ]/mg, "");
-    fn = dir + "/" + dtm;
-    if (input.id) {
-        fn += "." + input.id;
-    } else {
-        fn += "_" + _.random(0, 1000000);
-    }
-    fn += ".json";
-    dfs.write(fn, JSON.stringify(input, " ", 4));
-    output.filename = fn;
-    // 刪除旧交件
-    files = dfs.readdir(dir);
-    dt = Date.now() - 1000 * 3600 * 24 * 10;
-    for (i = 0; i < files.length; i++) {
-        if (files[i].mtime < dt) {
-            dfs.remove(files[i].fullname);
-        }
-    }
-    // 留最后10个
-    files.sort(function(a,b){ return a.mtime-b.mtime; });
-    for (i = 0; i < files.length-10; i++) {
-        dfs.remove(files[i].fullname);
-    }
-}
-// 主执行阶段
-try {
-    if (istesting) {
-        teststore();
-    }
-    // 数据合法性检查
-    if (___datacheck___) {}
-    // mql定义
-    mql = `___mql___`;
-    // 执行mql
-    ret = odb.mql(mql, ___values___);
-    // 打印完成信息
-    output.info=___datainfo___;
-    log.info(output.info);
-} catch(e) {
-    if (typeof(e) == "object") {
-        output.error = e;
-    } else if (typeof(e) == "string") {
-        output.error = "插库错误:" + e;
-    } else {
-        output.error = JSON.stringify(e);
-    }
-    log.error(output.error);
-}
-
-// 返回输出信息
-OUTPUT = output;
+// ___classname___ JSON数据导入程序
+// ___datetime_now___ 由 JsonImportGen.js 自动生成,请勿手动修改
+    
+// 输入输出参数格式化
+input = INPUT;
+try {
+    input = decodeURIComponent(input);
+} catch(e) {}
+try {
+    input = base64.decode(input);
+} catch(e) {}
+try {
+    input = JSON.parse(input);
+    input = JSON.parse(input);
+} catch(e) {}
+output = {};
+
+istesting = ___istesting___;
+function teststore() {
+    // 输入JSON临时存入DFS
+    dir = "/opt___classname___";
+    dtm = new Date().toJSON().replace(/[\-\:\.TZ ]/mg, "");
+    fn = dir + "/" + dtm;
+    if (input.id) {
+        fn += "." + input.id;
+    } else {
+        fn += "_" + _.random(0, 1000000);
+    }
+    fn += ".json";
+    dfs.write(fn, JSON.stringify(input, " ", 4));
+    output.filename = fn;
+    // 刪除旧交件
+    files = dfs.readdir(dir);
+    dt = Date.now() - 1000 * 3600 * 24 * 10;
+    for (i = 0; i < files.length; i++) {
+        if (files[i].mtime < dt) {
+            dfs.remove(files[i].fullname);
+        }
+    }
+    // 留最后10个
+    files.sort(function(a,b){ return a.mtime-b.mtime; });
+    for (i = 0; i < files.length-10; i++) {
+        dfs.remove(files[i].fullname);
+    }
+}
+// 主执行阶段
+try {
+    if (istesting) {
+        teststore();
+    }
+    // 数据合法性检查
+    if (___datacheck___) {}
+    // mql定义
+    mql = `___mql___`;
+    // 执行mql
+    ret = odb.mql(mql, ___values___);
+    // 打印完成信息
+    output.info=___datainfo___;
+    log.info(output.info);
+} catch(e) {
+    if (typeof(e) == "object") {
+        output.error = e;
+    } else if (typeof(e) == "string") {
+        output.error = "插库错误:" + e;
+    } else {
+        output.error = JSON.stringify(e);
+    }
+    log.error(output.error);
+}
+
+// 返回输出信息
+OUTPUT = output;

+ 160 - 160
cncc_serverjs/script/matrix/utils/JsonImporterGen.js

@@ -1,160 +1,160 @@
-// 输入输出参数格式化
-input = INPUT;
-try {
-    input = decodeURIComponent(input);
-} catch(e) {}
-try {
-    input = base64.decode(input);
-} catch(e) {}
-try {
-    input = JSON.parse(input);
-    input = JSON.parse(input);
-} catch(e) {}
-output = {};
-
-// 主执行阶段
-try {
-    if (!input.classname) { // like /cncc/itil/project
-        throw ("需要指定classname");
-    }
-    if (input.classname[0] != "/") { // like /cncc/itil/project
-        throw ("classname必须以 / 开头");
-    }
-    sjsfn = input.jsfilename;
-    if (!sjsfn) {
-        sjsfn = "/script" + input.classname; // like /script/cncc/itil/project
-    }
-    if (sjsfn.substring(0, 8) != "/script/") {
-        throw ("jsfilename必须以 /script/ 开头");
-    }
-    sjsfn = sjsfn.replace(/\.js$/, "");
-    output.file = sjsfn;
-
-    dtm = new Date().toJSON();
-    mql = "insert into " + input.classname + " (\n";
-    mql_values = ") values (\n";
-    mql_end = ")";
-    values = "";
-    fieldmap = input.fieldmap;
-    if (!fieldmap) {
-        fieldmap = {};
-    }
-    xfieldmap = {};
-    xfields = [];
-    clsfields = {};
-    try {
-        fieldslist = odb.classfields(input.classname);
-        for (var fi = 0; fi < fieldslist.length; fi++) {
-            fld = fieldslist[fi];
-            fname = fld.name;
-            if (/^\w+\:.*/.test(fname)) {
-                fname = fname.replace(/^\w+\:/, ""); 
-            }
-            if (fname && fld.ftype) {
-                clsfields[fname] = {
-                    iskey: fld.iskey,
-                    ftype: fld.ftype,
-                };
-            }
-        }
-    } catch(e) {}
-    for (var k in input.data) {
-        xk = fieldmap[k];
-        if (!xk) {
-            xk = "j_"; // 区别于其它字段,自动创建的字段以 j_ 开头
-            for (var i = 0; i < k.length; i++) {
-                if (k[i] >= 'A' && k[i] <= 'Z') {
-                    xk += "_" + k[i].toLowerCase();
-                } else {
-                    xk += k[i];
-                }
-            }
-            fieldmap[k] = xk;
-        }
-        xfields.push(xk);
-        xfieldmap[xk] = k;
-    }
-    xfields.sort();
-    fsep = ",";
-    for (var i = 0; i < xfields.length; i++) {
-        if (i == xfields.length - 1) {
-            fsep = "";
-        }
-        xk = xfields[i];
-        k = xfieldmap[xk];
-        mql += xk + fsep + "\n";
-        mql_values += "?" + fsep + "\n";
-        values += "    ";
-        v = input.data[k];
-        if (!clsfields[xk]) {
-            throw("字段不存在", xk)
-        }
-        switch (clsfields[xk].ftype) {
-        case "text":
-        case "varchar":
-            if (typeof(v) == "object") {
-                values += "JSON.stringify(";
-                values += "input." + k + ", \" \", 4)" + fsep;
-                values += JSON.stringify(v, " ", 4).replace(/^/mg, "            // ").replace(/            /, " ");
-            } else {
-                values += "\"\"+";
-                values += "input." + k + fsep;
-                values += (""+v).replace(/^/mg, "            // ").replace(/            /, " ");
-            }
-            break;
-        default:
-            values += "input." + k + fsep;
-            values += (""+v).replace(/^/mg, "            // ").replace(/            /, " ");
-        }
-        values += "\n    ";
-    }
-    mql += mql_values + mql_end;
-    values = "\n    " + values;
-
-    datainfo = "{";
-    datacheck = "";
-    if (input.mustfield) {
-        ids = input.mustfield.split(",");
-        for (var i = 0; i < ids.length; i++) {
-            id = ids[i];
-            if (i > 0) {
-                datacheck += "\n    ";
-            }
-            datacheck += "if (!input." + id + ") {\n    ";
-            datacheck += "    throw (\"输入参数必须为对象,且指定属性" + id + "\");\n    ";
-            datacheck += "}";
-            if (i == 0) {
-                datainfo += "\n    ";
-            } else {
-                datainfo += ",\n    ";
-            }
-            datainfo += "    " + id + ": input." + id;
-        }
-    }
-    datainfo += "\n    ";
-    datainfo += "}";
-
-    importjs = dfs.read("/script/matrix/utils/JsonImporter.template.js");
-    importjs = importjs.replace(/___istesting___/mg, input.istesting);
-    importjs = importjs.replace(/___classname___/mg, input.classname);
-    importjs = importjs.replace(/___datetime_now___/mg, dtm);
-    importjs = importjs.replace(/if\s*\(\s*___datacheck___\s*\)\s*\{.*\}/mg, datacheck);
-    importjs = importjs.replace(/___mql___/mg, mql);
-    importjs = importjs.replace(/___values___/mg, values);
-    importjs = importjs.replace(/___datainfo___/mg, datainfo);
-
-    output.content = importjs;
-
-    dfs.write(sjsfn + ".js", importjs);
-} catch(e) {
-    if (typeof(e) == "object") {
-        output.error = e;
-    } else if (typeof(e) == "string") {
-        output.error = "错误:" + e;
-    } else {
-        output.error = JSON.stringify(e);
-    }
-}
-
-// 返回输出信息
-OUTPUT = output;
+// 输入输出参数格式化
+input = INPUT;
+try {
+    input = decodeURIComponent(input);
+} catch(e) {}
+try {
+    input = base64.decode(input);
+} catch(e) {}
+try {
+    input = JSON.parse(input);
+    input = JSON.parse(input);
+} catch(e) {}
+output = {};
+
+// 主执行阶段
+try {
+    if (!input.classname) { // like /cncc/itil/project
+        throw ("需要指定classname");
+    }
+    if (input.classname[0] != "/") { // like /cncc/itil/project
+        throw ("classname必须以 / 开头");
+    }
+    sjsfn = input.jsfilename;
+    if (!sjsfn) {
+        sjsfn = "/script" + input.classname; // like /script/cncc/itil/project
+    }
+    if (sjsfn.substring(0, 8) != "/script/") {
+        throw ("jsfilename必须以 /script/ 开头");
+    }
+    sjsfn = sjsfn.replace(/\.js$/, "");
+    output.file = sjsfn;
+
+    dtm = new Date().toJSON();
+    mql = "insert into " + input.classname + " (\n";
+    mql_values = ") values (\n";
+    mql_end = ")";
+    values = "";
+    fieldmap = input.fieldmap;
+    if (!fieldmap) {
+        fieldmap = {};
+    }
+    xfieldmap = {};
+    xfields = [];
+    clsfields = {};
+    try {
+        fieldslist = odb.classfields(input.classname);
+        for (var fi = 0; fi < fieldslist.length; fi++) {
+            fld = fieldslist[fi];
+            fname = fld.name;
+            if (/^\w+\:.*/.test(fname)) {
+                fname = fname.replace(/^\w+\:/, ""); 
+            }
+            if (fname && fld.ftype) {
+                clsfields[fname] = {
+                    iskey: fld.iskey,
+                    ftype: fld.ftype,
+                };
+            }
+        }
+    } catch(e) {}
+    for (var k in input.data) {
+        xk = fieldmap[k];
+        if (!xk) {
+            xk = "j_"; // 区别于其它字段,自动创建的字段以 j_ 开头
+            for (var i = 0; i < k.length; i++) {
+                if (k[i] >= 'A' && k[i] <= 'Z') {
+                    xk += "_" + k[i].toLowerCase();
+                } else {
+                    xk += k[i];
+                }
+            }
+            fieldmap[k] = xk;
+        }
+        xfields.push(xk);
+        xfieldmap[xk] = k;
+    }
+    xfields.sort();
+    fsep = ",";
+    for (var i = 0; i < xfields.length; i++) {
+        if (i == xfields.length - 1) {
+            fsep = "";
+        }
+        xk = xfields[i];
+        k = xfieldmap[xk];
+        mql += xk + fsep + "\n";
+        mql_values += "?" + fsep + "\n";
+        values += "    ";
+        v = input.data[k];
+        if (!clsfields[xk]) {
+            throw("字段不存在", xk)
+        }
+        switch (clsfields[xk].ftype) {
+        case "text":
+        case "varchar":
+            if (typeof(v) == "object") {
+                values += "JSON.stringify(";
+                values += "input." + k + ", \" \", 4)" + fsep;
+                values += JSON.stringify(v, " ", 4).replace(/^/mg, "            // ").replace(/            /, " ");
+            } else {
+                values += "\"\"+";
+                values += "input." + k + fsep;
+                values += (""+v).replace(/^/mg, "            // ").replace(/            /, " ");
+            }
+            break;
+        default:
+            values += "input." + k + fsep;
+            values += (""+v).replace(/^/mg, "            // ").replace(/            /, " ");
+        }
+        values += "\n    ";
+    }
+    mql += mql_values + mql_end;
+    values = "\n    " + values;
+
+    datainfo = "{";
+    datacheck = "";
+    if (input.mustfield) {
+        ids = input.mustfield.split(",");
+        for (var i = 0; i < ids.length; i++) {
+            id = ids[i];
+            if (i > 0) {
+                datacheck += "\n    ";
+            }
+            datacheck += "if (!input." + id + ") {\n    ";
+            datacheck += "    throw (\"输入参数必须为对象,且指定属性" + id + "\");\n    ";
+            datacheck += "}";
+            if (i == 0) {
+                datainfo += "\n    ";
+            } else {
+                datainfo += ",\n    ";
+            }
+            datainfo += "    " + id + ": input." + id;
+        }
+    }
+    datainfo += "\n    ";
+    datainfo += "}";
+
+    importjs = dfs.read("/script/matrix/utils/JsonImporter.template.js");
+    importjs = importjs.replace(/___istesting___/mg, input.istesting);
+    importjs = importjs.replace(/___classname___/mg, input.classname);
+    importjs = importjs.replace(/___datetime_now___/mg, dtm);
+    importjs = importjs.replace(/if\s*\(\s*___datacheck___\s*\)\s*\{.*\}/mg, datacheck);
+    importjs = importjs.replace(/___mql___/mg, mql);
+    importjs = importjs.replace(/___values___/mg, values);
+    importjs = importjs.replace(/___datainfo___/mg, datainfo);
+
+    output.content = importjs;
+
+    dfs.write(sjsfn + ".js", importjs);
+} catch(e) {
+    if (typeof(e) == "object") {
+        output.error = e;
+    } else if (typeof(e) == "string") {
+        output.error = "错误:" + e;
+    } else {
+        output.error = JSON.stringify(e);
+    }
+}
+
+// 返回输出信息
+OUTPUT = output;

+ 254 - 0
cncc_serverjs/script/matrix/utils/ajs/InitJsonImporter.js

@@ -0,0 +1,254 @@
+
+//默认值设置
+defaultinput = {
+    classname: "/cncc/action/test",
+    clsoption: "with ttl=10 day, version=true, nickname='test'",
+    data: null,
+    datafilename: "",
+    datafiledir: "/opt/cncc/data/test",
+    jsfilename: "/script/cncc/api/测试.js",
+    fieldmap: { id: "jid" },
+    fields: { idUnique: "string,key" },
+    mustfield: "id,idUnique",
+};
+cfgs = [
+    {
+        classname: "/cncc/action/change_main",
+        datafiledir: "/opt/cncc/action/change_main",
+        jsfilename: "/script/cncc/ITIL/变更单.js",
+        clsoption: "with ttl=10 day, version=true, nickname='change_main'",
+    },
+    {
+        classname: "/cncc/action/event",
+        datafiledir: "/opt/cncc/action/event",
+        jsfilename: "/script/cncc/ITIL/事件单.js",
+        clsoption: "with ttl=10 day, version=true, nickname='event'",
+    },
+    {
+        classname: "/cncc/action/problem",
+        datafiledir: "/opt/cncc/action/problem",
+        jsfilename: "/script/cncc/ITIL/问题单.js",
+        clsoption: "with ttl=10 day, version=true, nickname='problem'",
+    },
+    {
+        classname: "/cncc/action/report",
+        datafiledir: "/opt/cncc/action/report",
+        jsfilename: "/script/cncc/ITIL/报备.js",
+        clsoption: "with ttl=10 day, version=true, nickname='report'",
+    },
+    {
+        classname: "/cncc/action/device_power_on_off",
+        datafiledir: "/opt/cncc/action/device_power_on_off",
+        jsfilename: "/script/cncc/ITIL/设备上下电.js",
+        clsoption: "with ttl=10 day, version=true, nickname='device_power_on_off'",
+    },
+    {
+        classname: "/cncc/action/data_collect",
+        datafiledir: "/opt/cncc/action/data_collect",
+        jsfilename: "/script/cncc/ITIL/数据获取.js",
+        clsoption: "with ttl=10 day, version=true, nickname='data_collect'",
+    },
+    {
+        classname: "/cncc/action/drill",
+        datafiledir: "/opt/cncc/action/drill",
+        jsfilename: "/script/cncc/ITIL/应急演练.js",
+        clsoption: "with ttl=10 day, version=true, nickname='drill'",
+    },
+    {
+        classname: "/cncc/action/implement",
+        datafiledir: "/opt/cncc/action/implement",
+        jsfilename: "/script/cncc/ITIL/项目实施或巡检.js",
+        clsoption: "with ttl=10 day, version=true, nickname='implement'",
+    }
+];
+inputmapping = {};
+for (var i = 0; i < cfgs.length; i++) {
+    inputmapping[cfgs[i].classname] = cfgs[i];
+}
+
+// 输入输出参数格式化
+input = INPUT;
+output = {};
+try {
+    input = decodeURIComponent(input);
+} catch (e) { }
+try {
+    input = base64.decode(input);
+} catch (e) { }
+try {
+    input = JSON.parse(input);
+    input = JSON.parse(input);
+} catch (e) { }
+
+// 通用函数
+function isempty(o) {
+    if (o) {
+        for (var k in o) {
+            return false;
+        }
+    }
+    return true;
+}
+
+// 引用函数库
+eval(dfs.read("/script/matrix/utils/ajs/JsonImporterFuncs.js"));
+
+// 定义主程序
+function main() {
+    output.detail = {};
+    output.detail.p0 = { step: "确认参数" };
+    classname = input.classname;
+    if (!classname) {
+        classname = defaultinput.classname;
+    }
+    if (classname[0] != "/") {
+        throw ("classname必须以 / 开头");
+    }
+    if (classname.substring(0, 8) == "/matrix/") {
+        throw ("classname不能以 /matrix/ 开头");
+    }
+    p = inputmapping[classname];
+    if (p) {
+        for (var k in p) {
+            defaultinput[k] = p[k];
+        }
+    }
+    data = input.data;
+    if (isempty(data)) {
+        data = defaultinput.data;
+        if (isempty(data)) {
+            datafilename = input.datafilename;
+            if (!datafilename) {
+                datafilename = defaultinput.datafilename;
+            }
+            if (datafilename) {
+                try {
+                    data = dfs.read(datafilename);
+                    data = JSON.parse(data);
+                } catch (e) { }
+            }
+        }
+        if (isempty(data)) {
+            datafiledir = input.datafiledir;
+            if (!datafiledir) {
+                if (classname == defaultinput.classname) {
+                    datafiledir = defaultinput.datafiledir;
+                } else {
+                    datafiledir = "/opt" + classname;
+                }
+            }
+            // 读取所有文件,综合数据
+            data = {};
+            files = dfs.readdir(datafiledir);
+            for (i = 0; i < files.length; i++) {
+                try {
+                    adat = dfs.read(files[i].fullname);
+                    adat = JSON.parse(adat);
+                    if (typeof (adat) != "object") {
+                        throw ("只接收JSON对象数据");
+                    }
+                    for (var k in adat) {
+                        if (!data[k]) {
+                            data[k] = adat[k];
+                        } else if (adat[k]) {
+                            if (typeof (adat[k]) == "object") {
+                                if (JSON.stringify(adat[k]).length > JSON.stringify(data[k]).length) {
+                                    data[k] = adat[k];
+                                }
+                            } else if (typeof (adat[k]) == "string") {
+                                if (typeof (data[k]) != "string") {
+                                    data[k] = adat[k];
+                                } else if (adat[k].length > data[k].length) {
+                                    data[k] = adat[k];
+                                }
+                            } else if (typeof (adat[k]) == "number") {
+                                if (typeof (data[k]) == "number") {
+                                    if (("" + adat[k]).indexOf(".") >= 0) {
+                                        data[k] = adat[k];
+                                    }
+                                }
+                            } else if (typeof (adat[k]) == "boolean") {
+                                if (typeof (data[k]) != "boolean") {
+                                    data[k] = "" + adat[k];
+                                }
+                            }
+                        }
+                    }
+                } catch (e) { }
+            }
+        }
+    }
+    if (data["--testing--"]) {
+        throw("一般程序怎么会用这样的字段名:“--testing--”")
+    }
+    jsfilename = input.jsfilename;
+    if (!jsfilename) {
+        jsfilename = defaultinput.jsfilename;
+    }
+    clsoption = input.clsoption;
+    if (!clsoption) {
+        clsoption = defaultinput.clsoption;
+    }
+    fieldmap = input.fieldmap;
+    if (!fieldmap) {
+        fieldmap = defaultinput.fieldmap;
+    }
+    mustfield = input.mustfield;
+    if (!mustfield) {
+        mustfield = defaultinput.mustfield;
+    }
+    fields = input.fields;
+    if (!fields) {
+        fields = defaultinput.fields;
+    }
+    reqinput = {
+        classname: classname,
+        jsfilename: jsfilename,
+        clsoption: clsoption,
+        fieldmap: fieldmap,
+        fields: fields,
+        mustfield: mustfield,
+        data: data,
+    };
+    output.detail.p1 = { step: "生成类" };
+    output.detail.p1.result = alterClass(reqinput);
+    if (output.detail.p1.result.error) {
+        return;
+    }
+    output.detail.p2 = { step: "生成脚本" };
+    output.detail.p2.result = generateJsonImporterJS(reqinput);
+    if (output.detail.p2.result.error) {
+        return;
+    }
+    output.detail.p3 = { step: "激活脚本" };
+    output.detail.p3.result = activeServerJS(jsfilename);
+    if (output.detail.p3.result.error) {
+        return;
+    }
+    output.detail.p4 = { step: "验证测试" };
+    data["--testing--"] = true
+    output.detail.p4.result = runServerJS(jsfilename, data);
+    delete(data, "--testing--")
+    if (output.detail.p4.result.error) {
+        return;
+    }
+    output.detail.p5 = { step: "完成" };
+    for(var k in output.detail.p4.result) {
+        output[k] = output.detail.p4.result[k]
+    }
+}
+// 执行主程序
+try {
+    main();
+} catch (e) {
+    if (typeof (e) == "object") {
+        output.error = e;
+    } else if (typeof (e) == "string") {
+        output.error = "错误:" + e;
+    } else {
+        output.error = JSON.stringify(e);
+    }
+}
+
+// 返回输出信息
+OUTPUT = output;

+ 95 - 0
cncc_serverjs/script/matrix/utils/ajs/JsonImporter.template.js

@@ -0,0 +1,95 @@
+// ___classname___ JSON数据导入程序
+// ___datetime_now___ 由 JsonImportGen.js 自动生成,请勿手动修改
+
+// 输入输出参数格式化
+input = INPUT;
+try {
+    input = decodeURIComponent(input);
+} catch (e) { }
+try {
+    input = base64.decode(input);
+} catch (e) { }
+try {
+    input = JSON.parse(input);
+    input = JSON.parse(input);
+} catch (e) { }
+output = {};
+
+testcfg = {};
+try {
+    testcfg = JSON.parse(etcd.get("/api/test.json"));
+} catch (e) { }
+function teststoredfs() {
+    // 输入JSON临时存入DFS
+    dir = "/opt___classname___";
+    d = new Date();
+    d.setMinutes(d.getMinutes() - d.getTimezoneOffset());
+    dtm = d.toJSON().replace(/[\-\:\.TZ ]/mg, "");
+    fn = dir + "/" + dtm;
+    if (input.id) {
+        fn += "." + input.id;
+    } else {
+        fn += "_" + _.random(0, 1000000);
+    }
+    fn += ".json";
+    dfs.write(fn, JSON.stringify(input, " ", 4));
+    output.filename = fn;
+    // 刪除旧交件
+    files = dfs.readdir(dir);
+    dt = Date.now() - 1000 * 3600 * 24 * 10;
+    for (var i = files.length - 1; i >= 0; i--) {
+        if (files[i].mtime < dt) {
+            dfs.remove(files[i].fullname);
+            files.splice(i, 1);
+        }
+    }
+    // 留最后10个
+    files.sort(function (a, b) { return a.mtime - b.mtime; });
+    for (var i = 0; i < files.length - 10; i++) {
+        dfs.remove(files[i].fullname);
+    }
+}
+// 主执行阶段
+try {
+    if (!input["--testing--"]) {
+        if (testcfg.storedfs) {
+            teststoredfs();
+        }
+        if (testcfg.checkfields) {
+            eval(dfs.read("/script/matrix/utils/ajs/checkfields.js"));
+            var newkeys = checkfields(input, ___field_map___);
+            if (newkeys) {
+                eval(dfs.read("/script/matrix/utils/ajs/JsonImporterFuncs.js"));
+                var result = runServerJS("/matrix/utils/ajs/InitJsonImporter.js", { classname: "___classname___" });
+                for (var k in result) {
+                    output[k] = result[k];
+                }
+                output.newkeys = newkeys;
+                throw ("ok");
+            }
+        }
+    }
+    // 数据合法性检查
+    if (___datacheck___) { }
+    // mql定义
+    mql = `___mql___`;
+    // 执行mql
+    ret = odb.mql(mql, ___values___);
+    // 打印完成信息
+    output.info = ___datainfo___;
+    log.info(output.info);
+} catch (e) {
+    if (e != "ok") {
+        if (typeof (e) == "object") {
+            output.error = e;
+        } else if (typeof (e) == "string") {
+            output.error = "插库错误:" + e;
+        } else {
+            output.error = JSON.stringify(e);
+        }
+        log.error(output.error);
+    }
+}
+
+// 返回输出信息
+OUTPUT = output;

+ 507 - 0
cncc_serverjs/script/matrix/utils/ajs/JsonImporterFuncs.js

@@ -0,0 +1,507 @@
+// JSON 对象数据导入数据库的函数库
+
+// 应用配置信息
+eval(dfs.read("/script/matrix/utils/ajs/config.js"))
+
+function compitable(dta, dtb) {
+    switch (dta) {
+        case "timestamp":
+            switch (dtb) {
+                case "timestamp":
+                    return true;
+                default:
+                    return false;
+            }
+        case "boolean":
+            switch (dtb) {
+                case "boolean":
+                    return true;
+                default:
+                    return false;
+            }
+        case "int":
+        case "integer":
+        case "bigint":
+            switch (dtb) {
+                case "int":
+                case "integer":
+                case "bigint":
+                    return true;
+                default:
+                    return false;
+            }
+        case "number":
+        case "float":
+        case "double":
+            switch (dtb) {
+                case "number":
+                case "float":
+                case "double":
+                case "int":
+                case "integer":
+                case "bigint":
+                    return true;
+                default:
+                    return false;
+            }
+        case "string":
+        case "varchar":
+        case "text":
+            return true;
+    }
+    return false
+}
+
+// 根据 JSON 对象数据建类或新增字段
+// classname 类名
+// clsoption 建类选项
+// data      数据示例
+// fieldmap  字段名映射,参数中指定的字段名均为JSON对象中的属性名,默认将 camelStyle 转换为 snake_style 
+// fields    字段类型
+function alterClass(input) {
+    // 返回信息
+    var output = {};
+    try {
+        // 参数检查
+        if (!input.classname) { // like /cncc/itil/project
+            throw ("需要指定classname");
+        }
+        if (input.classname[0] != "/") { // like /cncc/itil/project
+            throw ("classname必须以 / 开头");
+        }
+        if (!input.data || typeof (input.data) != "object") {
+            throw ("data必须指定为一个对象");
+        }
+        // 检查父类是否存在,不存在就创建
+        cns = input.classname.split("/");
+        clsname = "";
+        for (var cni = 1; cni < cns.length - 1; cni++) {
+            clsname += "/" + cns[cni];
+            odb.mql("create class if not exists " + clsname + "()");
+        }
+        pclsname = clsname;
+        clsname += "/" + cns[cns.length - 1];
+
+        // 提取现有类的字段信息
+        clsexist = false;
+        clsfields = {};
+        try {
+            fieldslist = odb.classfields(clsname);
+            for (var fi = 0; fi < fieldslist.length; fi++) {
+                fld = fieldslist[fi];
+                fname = fld.name;
+                if (/^\w+\:.*/.test(fname)) {
+                    fname = fname.replace(/^\w+\:/, "");
+                }
+                if (fname && fld.ftype) {
+                    clsfields[fname] = {
+                        iskey: fld.iskey,
+                        ftype: fld.ftype,
+                    };
+                }
+            }
+            clsexist = true;
+        } catch (e) { }
+        if (!clsexist) {
+            try {
+                fieldslist = odb.classfields(pclsname);
+                for (var fi = 0; fi < fieldslist.length; fi++) {
+                    fld = fieldslist[fi];
+                    fname = fld.name;
+                    if (/^\w+\:.*/.test(fname)) {
+                        fname = fname.replace(/^\w+\:/, "");
+                    }
+                    if (fname && fld.ftype) {
+                        clsfields[fname] = {
+                            iskey: fld.iskey,
+                            ftype: fld.ftype,
+                        };
+                    }
+                }
+            } catch (e) { }
+        }
+        output.clsfields = clsfields;
+
+        // 通过参数确定的字段类型信息
+        fields = input.fields;
+        if (!fields) {
+            fields = {};
+        }
+        // 字段名映射,参数中指定的字段名均为JSON对象中的属性名,默认将 camelStyle 转换为 snake_style
+        fieldmap = input.fieldmap;
+        if (!fieldmap) {
+            fieldmap = {};
+        }
+        // 反向字段名映射,类中的字段名映射为JSON对象中的属性名
+        xfieldmap = {};
+        // 类中的字段名列表,用于排序
+        xfieldslist = [];
+        // 类字段类型信息
+        xfields = {};
+        xpks = [];
+        for (var jk in input.data) {
+            xk = fieldmap[jk];
+            // 通过参数确定的字段类型信息
+            if (!xk) {
+                // 默认将 camelStyle 转换为 snake_style
+                xk = "j_"; // 区别于其它字段,自动创建的字段以 j_ 开头
+                for (var i = 0; i < jk.length; i++) {
+                    if (jk[i] >= 'A' && jk[i] <= 'Z') {
+                        xk += "_" + jk[i].toLowerCase();
+                    } else {
+                        xk += jk[i];
+                    }
+                }
+                fieldmap[jk] = xk;
+            }
+            xfieldslist.push(xk);
+            xfieldmap[xk] = jk;
+            dt = fields[jk];
+            if (dt && dt.indexOf(",key") > 0) {
+                dt = dt.replace(",key", "");
+                xpks.push(xk);
+            }
+            switch (dt) {
+                case "date":
+                case "time":
+                case "datetime":
+                    dt = "timestamp";
+                    break;
+                case "int":
+                case "integer":
+                    dt = "bigint";
+                    break;
+                case "number":
+                case "float":
+                    dt = "double";
+                    break;
+                case "text":
+                    dt = "text";
+                    break;
+                case "string":
+                    dt = "varchar";
+                    break;
+                case "boolean":
+                    dt = "boolean";
+                    break;
+            }
+            if (!dt) {
+                // 没有明确定义的字段类型
+                // 根据数据判断类型
+                dt = "varchar";
+                d = input.data[jk];
+                if (d || d == "" || d == 0 || d == false) {
+                    switch (typeof (d)) {
+                        case 'object':
+                            // 转为text
+                            dt = "text";
+                            break;
+                        case 'number':
+                            // 是否为整数
+                            if (("" + d).indexOf(".") < 0) {
+                                dt = "bigint";
+                            } else {
+                                dt = "double";
+                            }
+                            break;
+                        case 'boolean':
+                            dt = "boolean";
+                            break;
+                        case 'string':
+                        default:
+                            // 是否为日期时间
+                            if (/_time/.test(xk) || /_date/.test(xk)) {
+                                dt = "timestamp";
+                            } else {
+                                dt = "varchar";
+                            }
+                            break;
+                    }
+                } else {
+                    if (/_time/.test(xk) || /_date/.test(xk)) {
+                        dt = "timestamp";
+                    } else {
+                        dt = "varchar";
+                    }
+                }
+            }
+            xfields[xk] = dt;
+        }
+        output.xfields = xfields;
+
+        if (!clsexist) {
+            // 类不存在,自动创建类
+            mql = "create class if not exists " + clsname + "(";
+            indexes = "indexes(";
+            for (var fi = 0; fi < xfieldslist.length; fi++) {
+                xk = xfieldslist[fi];
+                if (xk in { "id": "", "class": "", "name": "", "day": "", "tags": "", "vtime": "" }) {
+                    throw ("内部使用字段名 " + xk + ",需要映射成其它名称");
+                }
+                if (clsfields[xk] && clsfields[xk].ftype != xfields[xk] && !compitable(clsfields[xk].ftype, xfields[xk])) {
+                    throw ("类继承字段 " + xk + " 信息不一致," + clsfields[xk].ftype + "!=" + xfields[xk] + ",需手动干预");
+                }
+                mql += fi == 0 ? "\n" : ",\n";
+                mql += xk + " " + xfields[xk];
+                if (fi > 0) {
+                    indexes += ",";
+                }
+                indexes += xk;
+            }
+            indexes += ")";
+            mql += ",\n" + indexes;
+            if (xpks.length > 0) {
+                mql += ",\n";
+                mql += "keys(";
+                for (var pki = 0; pki < xpks.length; pki++) {
+                    if (pki > 0) {
+                        mql += ",";
+                    }
+                    mql += xpks[pki];
+                }
+                mql += ")";
+            }
+            mql += "\n";
+            mql += ")";
+            if (input.clsoption) {
+                mql += input.clsoption;
+            }
+            odb.mql(mql);
+            output = { mql: mql };
+        } else {
+            // 类已存在,检查主键信息是否存在
+            // for (var pki = 0; pki < xpks.length; pki++) {
+            //     xk = xpks[pki];
+            //     if (!clsfields[xk] || !clsfields[xk].iskey) {
+            //         throw ("已经存在同名类主键 " + xk + " 信息不一致,需手动干预");
+            //     }
+            // }
+            // 追加字段
+            mql = "alter class " + clsname + " add index column";
+            addn = 0;
+            for (var fi = 0; fi < xfieldslist.length; fi++) {
+                xk = xfieldslist[fi];
+                if (!clsfields[xk]) {
+                    mql += (addn == 0) ? " " : ", ";
+                    mql += xk + " " + xfields[xk];
+                    addn++;
+                } else if (clsfields[xk].ftype != xfields[xk] && !compitable(clsfields[xk].ftype, xfields[xk])) {
+                    throw ("已经存在同名类字段 " + xk + " 信息不一致," + clsfields[xk].ftype + "!=" + xfields[xk] + ",需手动干预");
+                }
+            }
+            if (addn > 0) {
+                odb.mql(mql);
+                output = { mql: mql };
+            }
+        }
+    } catch (e) {
+        if (typeof (e) == "object") {
+            output.error = e;
+        } else if (typeof (e) == "string") {
+            output.error = "错误:" + e;
+        } else {
+            output.error = JSON.stringify(e);
+        }
+    }
+    return output
+}
+
+// 根据 JSON 数据生成导入脚本
+function generateJsonImporterJS(input) {
+    var output = {};
+    try {
+        // 参数检查
+        if (!input.classname) { // like /cncc/itil/project
+            throw ("需要指定classname");
+        }
+        if (input.classname[0] != "/") { // like /cncc/itil/project
+            throw ("classname必须以 / 开头");
+        }
+        sjsfn = input.jsfilename;
+        if (!sjsfn) {
+            sjsfn = "/script" + input.classname; // like /script/cncc/itil/project
+        }
+        if (sjsfn.substring(0, 8) != "/script/") {
+            throw ("jsfilename必须以 /script/ 开头");
+        }
+        sjsfn = sjsfn.replace(/\.js$/, "");
+        output.file = sjsfn;
+
+        d = new Date();
+        d.setMinutes(d.getMinutes() - d.getTimezoneOffset());
+        dtm = d.toJSON().replace(/T/, " ").replace(/Z/,"");
+        mql = "insert into " + input.classname + " (\n";
+        mql_values = ") values (\n";
+        mql_end = ")";
+        values = "";
+        fieldmap = input.fieldmap;
+        if (!fieldmap) {
+            fieldmap = {};
+        }
+        xfieldmap = {};
+        xfields = [];
+        clsfields = {};
+        try {
+            fieldslist = odb.classfields(input.classname);
+            for (var fi = 0; fi < fieldslist.length; fi++) {
+                fld = fieldslist[fi];
+                fname = fld.name;
+                if (/^\w+\:.*/.test(fname)) {
+                    fname = fname.replace(/^\w+\:/, "");
+                }
+                if (fname && fld.ftype) {
+                    clsfields[fname] = {
+                        iskey: fld.iskey,
+                        ftype: fld.ftype,
+                    };
+                }
+            }
+        } catch (e) { }
+        for (var k in input.data) {
+            xk = fieldmap[k];
+            if (!xk) {
+                xk = "j_"; // 区别于其它字段,自动创建的字段以 j_ 开头
+                for (var i = 0; i < k.length; i++) {
+                    if (k[i] >= 'A' && k[i] <= 'Z') {
+                        xk += "_" + k[i].toLowerCase();
+                    } else {
+                        xk += k[i];
+                    }
+                }
+                fieldmap[k] = xk;
+            }
+            xfields.push(xk);
+            xfieldmap[xk] = k;
+        }
+        xfields.sort();
+        fsep = ",";
+        for (var i = 0; i < xfields.length; i++) {
+            if (i == xfields.length - 1) {
+                fsep = "";
+            }
+            xk = xfields[i];
+            k = xfieldmap[xk];
+            mql += xk + fsep + "\n";
+            mql_values += "?" + fsep + "\n";
+            values += "    ";
+            v = input.data[k];
+            if (!clsfields[xk]) {
+                throw ("字段不存在", xk)
+            }
+            switch (clsfields[xk].ftype) {
+                case "text":
+                case "varchar":
+                    if (v && typeof (v) == "object") {
+                        values += "JSON.stringify(";
+                        values += "input." + k + ", \" \", 4)" + fsep;
+                        values += JSON.stringify(v, " ", 4).replace(/^/mg, "            // ").replace(/            /, " ");
+                    } else {
+                        values += "input." + k + "?"
+                        values += "input." + k + ":''" + fsep;
+                        values += ("" + v).replace(/^/mg, "            // ").replace(/            /, " ");
+                    }
+                    break;
+                default:
+                    values += "input." + k + fsep;
+                    values += ("" + v).replace(/^/mg, "            // ").replace(/            /, " ");
+            }
+            values += "\n    ";
+        }
+        mql += mql_values + mql_end;
+        values = "\n    " + values;
+
+        datainfo = "{";
+        datacheck = "";
+        if (input.mustfield) {
+            ids = input.mustfield.split(",");
+            for (var i = 0; i < ids.length; i++) {
+                id = ids[i];
+                if (i > 0) {
+                    datacheck += "\n    ";
+                }
+                datacheck += "if (!input." + id + ") {\n    ";
+                datacheck += "    throw (\"输入参数必须为对象,且指定属性" + id + "\");\n    ";
+                datacheck += "}";
+                if (i == 0) {
+                    datainfo += "\n    ";
+                } else {
+                    datainfo += ",\n    ";
+                }
+                datainfo += "    " + id + ": input." + id;
+            }
+        }
+        datainfo += "\n    ";
+        datainfo += "}";
+
+        importjs = dfs.read("/script/matrix/utils/ajs/JsonImporter.template.js");
+        importjs = importjs.replace(/___field_map___/mg, JSON.stringify(fieldmap));
+        importjs = importjs.replace(/___classname___/mg, input.classname);
+        importjs = importjs.replace(/___datetime_now___/mg, dtm);
+        importjs = importjs.replace(/if\s*\(\s*___datacheck___\s*\)\s*\{.*\}/mg, datacheck);
+        importjs = importjs.replace(/___mql___/mg, mql);
+        importjs = importjs.replace(/___values___/mg, values);
+        importjs = importjs.replace(/___datainfo___/mg, datainfo);
+
+        output.content = importjs;
+
+        dfs.write(sjsfn + ".js", importjs);
+    } catch (e) {
+        if (typeof (e) == "object") {
+            output.error = e;
+        } else if (typeof (e) == "string") {
+            output.error = "错误:" + e;
+        } else {
+            output.error = JSON.stringify(e);
+        }
+    }
+    return output
+}
+
+// 激活脚本,生成的脚本文件需要激活后才能生效
+function activeServerJS(jsfilename) {
+    result = {};
+    calljsfp = encodeURIComponent(jsfilename.replace(/\/script/, ""));
+    http.do("POST",
+        cfg.server + "/fs/tolocal/script" + calljsfp + "?issys=true",
+        { "Authorization": "Basic " + cfg.author },
+        '',
+        function (response) {
+            // success func
+            ret = response.data;
+            if (ret.message) {
+                result = ret.message;
+            } else {
+                result = ret;
+            }
+        },
+        function (response) {
+            // error func
+            result.error = response.data;
+        });
+    return result;
+}
+
+// 验证测试执行脚本
+function runServerJS(jsfilename, data) {
+    result = {};
+    reqinput = encodeURIComponent(base64.encode(JSON.stringify(data)));
+    calljsfp = encodeURIComponent(jsfilename.replace(/\/script/, ""));
+    http.do("POST",
+        cfg.server + "/script/exec/js?filepath=" + calljsfp + "&input=" + reqinput,
+        { "Authorization": "Basic " + cfg.author },
+        '',
+        function (response) {
+            // success func
+            ret = response.data;
+            if (ret.message) {
+                result = ret.message;
+            } else {
+                result = ret;
+            }
+        },
+        function (response) {
+            // error func
+            result.error = response.data;
+        });
+    return result;
+}

+ 10 - 0
cncc_serverjs/script/matrix/utils/ajs/checkfields.js

@@ -0,0 +1,10 @@
+
+function checkfields(data, fieldmap)  {
+    var newkeys = "";
+    for (var k in data) {
+        if (!fieldmap[k]) {
+            newkeys += k + ",";
+        }
+    }
+    return newkeys;
+}

+ 10 - 0
cncc_serverjs/script/matrix/utils/ajs/config.js

@@ -0,0 +1,10 @@
+cfg = {
+    server: "http://27.193.12.228:8080",
+    author: base64.encode("meta.admin:admin"),
+};
+try{
+    etc = JSON.parse(etcd.get("api/cfg.json"));
+    for(var k in etc) {
+        cfg[k] = etc[k];
+    }
+}catch(e){}

+ 20 - 0
cncc_serverjs/script/matrix/utils/ajs/test.js

@@ -0,0 +1,20 @@
+
+output = {};
+
+try {
+    eval(dfs.read("/script/matrix/utils/ajs/JsonImporterFuncs.js"));
+
+    output.result = {};
+    output.result.change_main         = runServerJS("/matrix/utils/ajs/InitJsonImporter.js", {classname:"/cncc/action/change_main"});
+} catch (e) {
+    if (typeof (e) == "object") {
+        output.error = e;
+    } else if (typeof (e) == "string") {
+        output.error = "错误:" + e;
+    } else {
+        output.error = JSON.stringify(e);
+    }
+}
+
+// 返回输出信息
+OUTPUT = output;

+ 35 - 0
cncc_serverjs/script/matrix/wframe/init.js

@@ -0,0 +1,35 @@
+
+// 输入输出参数格式化
+input = INPUT;
+output = {};
+try {
+    input = decodeURIComponent(input);
+} catch (e) { }
+try {
+    input = base64.decode(input);
+} catch (e) { }
+try {
+    input = JSON.parse(input);
+    input = JSON.parse(input); // 解析可能存在的重复编码
+} catch (e) { }
+
+// 主执行阶段
+try {
+    main(input, output);
+} catch (e) {
+    // 错误信息输出处理,抛出 ok 表示正常结束    
+    if (e != "ok") {
+        if (typeof (e) == "object") {
+            output.error = e;
+        } else if (typeof (e) == "string") {
+            output.error = "错误:" + e;
+        } else {
+            output.error = JSON.stringify(e);
+        }
+        log.error(output.error);
+        STATUS = "error";
+    }
+}
+
+// 返回输出信息
+OUTPUT = output;

+ 16 - 0
cncc_serverjs/script/matrix/wframe/test.js

@@ -0,0 +1,16 @@
+
+
+eval(dfs.read("/script/matrix/wframe/init.js"));
+
+function main(input,output) {
+    eval(dfs.read("/script/matrix/wframe/util.js"));
+    
+    output.params = input;
+    
+    var dt = parseTime(input.tfmt, input.time);
+    
+    //output.now = now;
+    output.result = {};
+    output.result.dt = dt.toJSON();
+    output.result.st = formatTime(input.nfmt, dt);
+}

+ 78 - 0
cncc_serverjs/script/matrix/wframe/util.js

@@ -0,0 +1,78 @@
+
+// 解析时间字符串 格式标记为 yyyy MM dd HH mm ss SSS
+var date_formats_flag = {
+    "y": { idx: 0, name: "yyyy", len: 4, re: /^\d{4}$/, p: 0 },
+    "M": { idx: 1, name: "MM", len: 2, re: /^\d{2}$/, p: 5 },
+    "d": { idx: 2, name: "dd", len: 2, re: /^\d{2}$/, p: 8 },
+    "H": { idx: 3, name: "HH", len: 2, re: /^\d{2}$/, p: 11 },
+    "m": { idx: 4, name: "mm", len: 2, re: /^\d{2}$/, p: 14 },
+    "s": { idx: 5, name: "ss", len: 2, re: /^\d{2}$/, p: 17 },
+    "S": { idx: 6, name: "SSS", len: 3, re: /^\d{3}$/, p: 20 },
+};
+now = new Date();
+function parseTime(sfmt, yMdHmsS) {
+    if (!sfmt) {
+        throw ("没有指定时间格式");
+    }
+    if (!yMdHmsS) {
+        throw ("没有指定时间字符串");
+    }
+    try {
+        if (sfmt.length != yMdHmsS.length) {
+            throw ("长度不一致");
+        }
+        var dt = [null, null, null, null, null, null, null];
+        for (var i = 0; i < sfmt.length; i++) {
+            var fmt = date_formats_flag[sfmt[i]];
+            if (fmt && sfmt.length >= i + fmt.len && sfmt.substr(i, fmt.len) == fmt.name) {
+                if (yMdHmsS.length < i + fmt.len) {
+                    throw (fmt.name + " " + i);
+                }
+                var ds = yMdHmsS.substr(i, fmt.len);
+                if (!fmt.re.test(ds)) {
+                    throw (fmt.name + " " + ds);
+                }
+                dt[fmt.idx] = parseInt(ds);
+                i += fmt.len - 1;
+            } else {
+                if (yMdHmsS.length <= i || sfmt[i] != yMdHmsS[i]) {
+                    throw (sfmt[i]);
+                }
+            }
+        }
+        var d = new Date(
+            dt[0] == null ? now.getFullYear() : dt[0],
+            dt[1] == null ? now.getMonth() : dt[1] - 1,
+            dt[2] == null ? 1 : dt[2],
+            dt[3],
+            dt[4],
+            dt[5],
+            dt[6]
+        );
+        d.setMinutes(d.getMinutes() - d.getTimezoneOffset());
+        return d;
+    } catch (e) {
+        throw ("时间格式错误,正确格式是 " + sfmt + "," + e);
+    }
+}
+
+function formatTime(sfmt, dt) {
+    if (!sfmt) {
+        throw ("没有指定时间格式");
+    }
+    if (!dt) {
+        throw ("没有指定时间");
+    }
+    var ds = dt.toJSON();
+    var s = "";
+    for (var i = 0; i < sfmt.length; i++) {
+        var fmt = date_formats_flag[sfmt[i]];
+        if (fmt && sfmt.length >= i + fmt.len && sfmt.substr(i, fmt.len) == fmt.name) {
+            s += ds.substring(fmt.p, fmt.p + fmt.len);
+            i += fmt.len - 1;
+        } else {
+            s += sfmt[i];
+        }
+    }
+    return s;
+}