Commit aec179d3 authored by Medicean's avatar Medicean

php::mysql&mysqli 数据库操作增强

* 数据库新增、修改、删除
* 表新增、改名、删除
parent ddd7e66f
...@@ -77,10 +77,18 @@ class PHP { ...@@ -77,10 +77,18 @@ class PHP {
}); });
// 5. tree右键::功能菜单 // 5. tree右键::功能菜单
this.tree.attachEvent('onRightClick', (id, event) => { this.tree.attachEvent('onRightClick', (id, event) => {
if (!id.startsWith('conn::')) { return };
this.tree.selectItem(id); this.tree.selectItem(id);
const arr = id.split('::');
if (arr.length < 2) { throw new Error('ID ERR: ' + id) };
switch(arr[0]) {
case 'conn':
this.tree.callEvent('onClick', [id]); this.tree.callEvent('onClick', [id]);
bmenu([ bmenu([
{
text: "新建数据库",
icon: 'fa fa-plus-circle',
action: this.addDatabase.bind(this)
},
{ {
text: LANG['list']['menu']['add'], text: LANG['list']['menu']['add'],
icon: 'fa fa-plus-circle', icon: 'fa fa-plus-circle',
...@@ -99,7 +107,109 @@ class PHP { ...@@ -99,7 +107,109 @@ class PHP {
action: this.delConf.bind(this) action: this.delConf.bind(this)
} }
], event); ], 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 { ...@@ -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: `<i class="fa fa-plus"></i> 创建`},
{type: 'newcolumn', offset:20},
{ type:"button" , name:"canclebtn", value: `<i class="fa fa-ban"></i> 取消`},
]}
]}
], 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: `<i class="fa fa-pen"></i> 修改`},
{type: 'newcolumn', offset:20},
{ type:"button" , name:"canclebtn", value: `<i class="fa fa-ban"></i> 取消`},
]}
]}
], 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: `<i class="fa fa-file-code-o"></i> 输入新表名`
},(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) { getDatabases(id) {
this.manager.list.layout.progressOn(); this.manager.list.layout.progressOn();
...@@ -549,6 +1028,24 @@ class PHP { ...@@ -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 // 执行SQL
execSQL(sql) { execSQL(sql) {
this.manager.query.layout.progressOn(); this.manager.query.layout.progressOn();
...@@ -573,6 +1070,38 @@ class PHP { ...@@ -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执行结果 // 更新SQL执行结果
updateResult(data) { updateResult(data) {
// 1.分割数组 // 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