Commit 36811a5b authored by Medicean's avatar Medicean

Merge branch 'future-db' into v2.0.x

parents b7d91d35 eb62a56f
......@@ -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',
}
}
},
......
......@@ -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: '删除列失败',
}
}
},
......
//
// 数据库管理模块
//
// TODO: 数据管理模块目前的代码存在大量冗余,后期会考虑将 数据库驱动 与 core 分成两个块来做
// import React from 'react';
// import ReactDOM from 'react-dom';
// import AceEditor from 'react-ace';
......
......@@ -77,29 +77,153 @@ 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: LANG['list']['menu']['adddb'],
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: LANG['list']['menu']['addtable'],
icon: 'fa fa-plus-circle',
action: this.addTable.bind(this)
},
{
text: LANG['list']['menu']['adddb'],
icon: 'fa fa-plus-circle',
action: this.addDatabase.bind(this)
}, {
divider: true
}, {
text: LANG['list']['menu']['editdb'],
icon: 'fa fa-edit',
action: this.editDatabase.bind(this)
}, {
divider: true
}, {
text: LANG['list']['menu']['deldb'],
icon: 'fa fa-remove',
action: this.delDatabase.bind(this)
}
], event);
break;
case 'table':
this.tree.callEvent('onClick', [id]);
bmenu([
{
text: LANG['list']['menu']['addtable'],
icon: 'fa fa-plus-circle',
action: this.addTable.bind(this)
}, {
divider: true
}, {
text: LANG['list']['menu']['edittable'],
icon: 'fa fa-edit',
action: this.editTable.bind(this)
}, {
divider: true
}, {
text: LANG['list']['menu']['deltable'],
icon: 'fa fa-remove',
action: this.delTable.bind(this)
}
], event);
break;
case 'column':
this.tree.callEvent('onClick', [id]);
bmenu([
{
text: LANG['list']['menu']['editcolumn'],
icon: 'fa fa-edit',
action: this.editColumn.bind(this)
}, {
text: LANG['list']['menu']['delcolumn'],
icon: 'fa fa-remove',
action: this.delColumn.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 +542,603 @@ 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(LANG['form']['adddb']['title']);
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: 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({
text: _,
value: _,
});
})
return ret;
})() },
{ type: 'combo', label: LANG['form']['adddb']['charactercollation'], 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: `<i class="fa fa-plus"></i> ${LANG['form']['adddb']['createbtn']}`},
{type: 'newcolumn', offset:20},
{ type:"button" , name:"cancelbtn", value: `<i class="fa fa-ban"></i> ${LANG['form']['adddb']['cancelbtn']}`},
]}
]}
], 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['form']['adddb']['success'] ,LANG_T['success']);
win.close();
// refresh
this.getDatabases(id);
return
}
toastr.error(LANG['form']['adddb']['error'], LANG_T['error']);
return
});
// 创建
break
case "cancelbtn":
win.close();
break;
}
});
break;
default:
toastr.warning(LANG['notsupport'], 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(LANG['form']['editdb']['title']);
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: 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({
text: _,
value: _,
});
})
return ret;
})() },
{ type: 'combo', label: LANG['form']['editdb']['charactercollation'], 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: `<i class="fa fa-pen"></i> ${LANG['form']['editdb']['updatebtn']}`},
{type: 'newcolumn', offset:20},
{ type:"button" , name:"cancelbtn", value: `<i class="fa fa-ban"></i> ${LANG['form']['editdb']['cancelbtn']}`},
]}
]}
], 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['form']['editdb']['success'] ,LANG_T['success']);
win.close();
// refresh
this.getDatabases(id);
return
}
toastr.error(LANG['form']['editdb']['error'], LANG_T['error']);
return
});
// 修改
break
case "cancelbtn":
win.close();
break;
}
});
});
break;
default:
toastr.warning(LANG['notsupport'], 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(LANG['form']['deldb']['confirm'](dbname), {
icon: 2, shift: 6,
title: LANG['form']['deldb']['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['form']['deldb']['success'], LANG_T['success']);
this.getDatabases(id);
}else{
toastr.error(LANG['form']['deldb']['error'], LANG_T['error']);
}
});
break;
default:
toastr.warning(LANG['notsupport'], 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,
// \`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(LANG['form']['addtable']['title']);
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: LANG['form']['addtable']['add'],
}, {
type: 'separator'
}, {
id: 'delete',
type: 'button',
icon: 'remove',
text: LANG['form']['addtable']['delete']
},{
id: 'save',
type: 'button',
icon: 'save',
text: LANG['form']['addtable']['save']
}]);
dhtmlxValidation.hasOwnProperty("isValidPositiveInteger") ? "" : dhtmlxValidation.isValidPositiveInteger = (a) => { return !!a.toString().match(/(^\d+$)/);}
const grid=win.attachGrid();
grid.clearAll();
// 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"]);
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['form']['addtable']['delete_not_select'], LANG_T['warning']);
return
}
let _ncids = ncids.split(",");
_ncids.map(_=>{
grid.deleteRow(_);
});
break;
case "save":
let rids = grid.getAllRowIds();
if(!rids){
toastr.warning(LANG['form']['addtable']['save_row_is_null'], 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(LANG['form']['addtable']['cell_valid_error'](i,j), 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: `<i class="fa fa-file-code-o"></i> ${LANG['form']['addtable']['confirmtitle']}`
},(value, i, e) => {
if(!value.match(/^[a-zA-Z0-9_]+$/)){
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) => {
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']['addtable']['success'],LANG_T['success']);
this.getTables(id,dbname);
win.close();
}else{
toastr.error(LANG['form']['addtable']['error'], LANG_T['error']);
}
});
});
break;
}
});
break;
default:
toastr.warning(LANG['notsupport'], 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: `<i class="fa fa-file-code-o"></i> ${LANG['form']['edittable']['title']}`
},(value, i, e) => {
if(!value.match(/^[a-zA-Z0-9_]+$/)){
toastr.error(LANG['form']['edittable']['invalid_tablename'], 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['form']['edittable']['success'],LANG_T['success']);
this.getTables(id,dbname);
}else{
toastr.error(LANG['form']['edittable']['error'],LANG_T['error']);
}
});
break;
default:
toastr.warning(LANG['notsupport'], 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(LANG['form']['deltable']['confirm'](tablename), {
icon: 2, shift: 6,
title: LANG['form']['deltable']['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['form']['deltable']['success'],LANG_T['success']);
this.getTables(id,dbname);
}else{
toastr.error(LANG['form']['deltable']['error'],LANG_T['error']);
}
});
break;
default:
toastr.warning(LANG['notsupport'], LANG_T['warning']);
break;
}
});
}
// TODO: 新增列
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();
}
// 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();
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(LANG['form']['delcolumn']['confirm'](columnname), {
icon: 2, shift: 6,
title: LANG['form']['delcolumn']['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['form']['delcolumn']['success'],LANG_T['success']);
this.getColumns(id,dbname, tablename);
}else{
toastr.error(LANG['form']['delcolumn']['error'],LANG_T['error']);
}
});
break;
default:
toastr.warning(LANG['notsupport'], LANG_T['warning']);
break;
}
});
}
// 获取数据库列表
getDatabases(id) {
this.manager.list.layout.progressOn();
......@@ -549,6 +1270,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 +1312,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.分割数组
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment