增加数据库函数和存储过程的增删改查支持,优化数据源管理

This commit is contained in:
暮光:城中城
2021-04-25 21:56:27 +08:00
parent f270a9bb12
commit 744e877309
22 changed files with 1007 additions and 98 deletions

View File

@@ -1,11 +1,14 @@
package com.zyplayer.doc.db.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zyplayer.doc.core.annotation.AuthMan;
import com.zyplayer.doc.core.json.ResponseJson;
import com.zyplayer.doc.data.config.security.DocUserDetails;
import com.zyplayer.doc.data.config.security.DocUserUtil;
import com.zyplayer.doc.data.repository.manage.entity.DbDatasource;
import com.zyplayer.doc.data.repository.manage.entity.UserInfo;
import com.zyplayer.doc.data.repository.support.consts.DocAuthConst;
import com.zyplayer.doc.data.service.manage.DbDatasourceService;
import com.zyplayer.doc.db.framework.configuration.DatasourceUtil;
@@ -20,6 +23,7 @@ import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;
/**
* 数据源控制器
@@ -38,14 +42,27 @@ public class DbDatasourceController {
DbDatasourceService dbDatasourceService;
@PostMapping(value = "/list")
public ResponseJson list() {
public ResponseJson list(Integer pageNum, Integer pageSize, String name, String groupName) {
QueryWrapper<DbDatasource> wrapper = new QueryWrapper<>();
wrapper.eq("yn", 1);
List<DbDatasource> datasourceList = dbDatasourceService.list(wrapper);
for (DbDatasource dbDatasource : datasourceList) {
wrapper.eq(StringUtils.isNotBlank(groupName), "group_name", groupName);
wrapper.like(StringUtils.isNotBlank(name), "name", "%" + name + "%");
IPage<DbDatasource> page = new Page<>(pageNum, pageSize, pageNum == 1);
dbDatasourceService.page(page, wrapper);
for (DbDatasource dbDatasource : page.getRecords()) {
dbDatasource.setSourcePassword("***");
}
return DocDbResponseJson.ok(datasourceList);
return DocDbResponseJson.ok(page);
}
@PostMapping(value = "/groups")
public ResponseJson groups() {
QueryWrapper<DbDatasource> wrapper = new QueryWrapper<>();
wrapper.eq("yn", 1);
wrapper.select("group_name");
List<DbDatasource> datasourceList = dbDatasourceService.list(wrapper);
Set<String> groupNameSet = datasourceList.stream().map(DbDatasource::getGroupName).filter(StringUtils::isNotBlank).collect(Collectors.toSet());
return DocDbResponseJson.ok(groupNameSet);
}
@PostMapping(value = "/test")

View File

@@ -0,0 +1,122 @@
package com.zyplayer.doc.db.controller;
import com.zyplayer.doc.core.annotation.AuthMan;
import com.zyplayer.doc.core.json.ResponseJson;
import com.zyplayer.doc.data.config.security.DocUserUtil;
import com.zyplayer.doc.data.repository.support.consts.DocAuthConst;
import com.zyplayer.doc.db.controller.param.ProcedureListParam;
import com.zyplayer.doc.db.framework.db.dto.ProcedureDto;
import com.zyplayer.doc.db.framework.db.mapper.base.ExecuteResult;
import com.zyplayer.doc.db.framework.json.DocDbResponseJson;
import com.zyplayer.doc.db.service.DbBaseFactory;
import com.zyplayer.doc.db.service.DbBaseService;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.List;
/**
* 存储过程管理控制器
*
* @author 暮光:城中城
* @since 2021年4月24日
*/
@AuthMan
@RestController
@RequestMapping("/zyplayer-doc-db/procedure")
public class DbProcedureController {
private static Logger logger = LoggerFactory.getLogger(DbProcedureController.class);
@Resource
DbBaseFactory dbBaseFactory;
/**
* 存储过程列表
*
* @param procedureParam 参数
* @return 列表
*/
@PostMapping(value = "/list")
public ResponseJson list(ProcedureListParam procedureParam) {
boolean manageAuth = DocUserUtil.haveAuth(DocAuthConst.DB_DATASOURCE_MANAGE);
if (!manageAuth) {
return DocDbResponseJson.warn("没有该数据源的管理权限");
}
DbBaseService dbBaseService = dbBaseFactory.getDbBaseService(procedureParam.getSourceId());
procedureParam.setOffset((procedureParam.getPageNum() - 1) * procedureParam.getPageSize());
List<ProcedureDto> procedureDtoList = dbBaseService.getProcedureList(procedureParam);
DocDbResponseJson responseJson = DocDbResponseJson.ok(procedureDtoList);
if (procedureParam.getPageNum() == 1) {
responseJson.setTotal(dbBaseService.getProcedureCount(procedureParam));
}
return responseJson;
}
/**
* 获取函数详情
*
* @param sourceId 数据源ID
* @param dbName 数据库名
* @param typeName 类型名
* @param procName 函数名
* @return 详情
*/
@PostMapping(value = "/detail")
public ResponseJson detail(Long sourceId, String dbName, String typeName, String procName) {
boolean manageAuth = DocUserUtil.haveAuth(DocAuthConst.DB_DATASOURCE_MANAGE);
if (!manageAuth) {
return DocDbResponseJson.warn("没有该数据源的管理权限");
}
DbBaseService dbBaseService = dbBaseFactory.getDbBaseService(sourceId);
ProcedureDto procedureDto = dbBaseService.getProcedureDetail(sourceId, dbName, typeName, procName);
return DocDbResponseJson.ok(procedureDto);
}
/**
* 删除函数
*
* @param sourceId 数据源ID
* @param dbName 数据库名
* @param typeName 类型名
* @param procName 函数名
* @return 结果
*/
@PostMapping(value = "/delete")
public ResponseJson delete(Long sourceId, String dbName, String typeName, String procName) {
boolean manageAuth = DocUserUtil.haveAuth(DocAuthConst.DB_DATASOURCE_MANAGE);
if (!manageAuth) {
return DocDbResponseJson.warn("没有该数据源的管理权限");
}
DbBaseService dbBaseService = dbBaseFactory.getDbBaseService(sourceId);
dbBaseService.deleteProcedure(sourceId, dbName, typeName, procName);
return DocDbResponseJson.ok();
}
/**
* 保存函数
*
* @param sourceId 数据源ID
* @param dbName 数据库名
* @param typeName 类型名
* @param procName 函数名
* @param procSql 存储过程创建SQL
* @return 结果
*/
@PostMapping(value = "/save")
public ResponseJson save(Long sourceId, String dbName, String typeName, String procName, String procSql) {
boolean manageAuth = DocUserUtil.haveAuth(DocAuthConst.DB_DATASOURCE_MANAGE);
if (!manageAuth) {
return DocDbResponseJson.warn("没有该数据源的管理权限");
}
DbBaseService dbBaseService = dbBaseFactory.getDbBaseService(sourceId);
ExecuteResult executeResult = dbBaseService.saveProcedure(sourceId, dbName, typeName, procName, procSql);
return DocDbResponseJson.ok(executeResult);
}
}

View File

@@ -0,0 +1,67 @@
package com.zyplayer.doc.db.controller.param;
public class ProcedureListParam {
private Long sourceId;
private String dbName;
private Integer pageNum;
private Integer pageSize;
private Integer offset;
private String name;
private String type;
public Long getSourceId() {
return sourceId;
}
public void setSourceId(Long sourceId) {
this.sourceId = sourceId;
}
public String getDbName() {
return dbName;
}
public void setDbName(String dbName) {
this.dbName = dbName;
}
public Integer getPageNum() {
return pageNum;
}
public void setPageNum(Integer pageNum) {
this.pageNum = pageNum;
}
public Integer getPageSize() {
return pageSize;
}
public void setPageSize(Integer pageSize) {
this.pageSize = pageSize;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public Integer getOffset() {
return offset;
}
public void setOffset(Integer offset) {
this.offset = offset;
}
}

View File

@@ -0,0 +1,79 @@
package com.zyplayer.doc.db.framework.db.dto;
/**
* 存储过程信息
*/
public class ProcedureDto {
private String db;
private String name;
private String type;
private String definer;
private String body;
private String paramList;
private String returns;
private String created;
public String getDb() {
return db;
}
public void setDb(String db) {
this.db = db;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getDefiner() {
return definer;
}
public void setDefiner(String definer) {
this.definer = definer;
}
public String getCreated() {
return created;
}
public void setCreated(String created) {
this.created = created;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
public String getParamList() {
return paramList;
}
public void setParamList(String paramList) {
this.paramList = paramList;
}
public String getReturns() {
return returns;
}
public void setReturns(String returns) {
this.returns = returns;
}
}

View File

@@ -1,5 +1,6 @@
package com.zyplayer.doc.db.framework.db.mapper.base;
import com.zyplayer.doc.db.controller.param.ProcedureListParam;
import com.zyplayer.doc.db.controller.vo.TableStatusVo;
import com.zyplayer.doc.db.framework.db.dto.*;
import org.apache.ibatis.annotations.Param;
@@ -119,4 +120,44 @@ public interface BaseMapper {
* @since 2019年9月1日
*/
TableStatusVo getTableStatus(@Param("dbName") String dbName, @Param("tableName") String tableName);
/**
* 获取存储过程总条数
*
* @param procedureParam 参数
* @author 暮光:城中城
* @since 2020年4月24日
*/
Long getProcedureCount(@Param("param") ProcedureListParam procedureParam);
/**
* 获取存储过程列表
*
* @param procedureParam 参数
* @author 暮光:城中城
* @since 2020年4月24日
*/
List<ProcedureDto> getProcedureList(@Param("param") ProcedureListParam procedureParam);
/**
* 获取存储过程详情
*
* @param dbName 数据库名
* @param typeName 类型名称 PROCEDURE、FUNCTION
* @param procName 过程名称
* @author 暮光:城中城
* @since 2020年4月24日
*/
ProcedureDto getProcedureDetail(@Param("dbName") String dbName, @Param("typeName") String typeName, @Param("procName") String procName);
/**
* 删除存储过程
*
* @param dbName 数据库名
* @param typeName 类型名称 PROCEDURE、FUNCTION
* @param procName 过程名称
* @author 暮光:城中城
* @since 2020年4月24日
*/
void deleteProcedure(@Param("dbName") String dbName, @Param("typeName") String typeName, @Param("procName") String procName);
}

View File

@@ -99,4 +99,29 @@
comment #{newDesc}
</insert>
<select id="getProcedureCount" resultType="java.lang.Long">
select count(1) from mysql.proc
<include refid="ProcedureListCondition"/>
</select>
<select id="getProcedureList" resultType="com.zyplayer.doc.db.framework.db.dto.ProcedureDto">
select `db`, `name`, `type`, `definer`, `created` from mysql.proc
<include refid="ProcedureListCondition"/>
limit #{param.pageSize} offset #{param.offset}
</select>
<select id="getProcedureDetail" resultType="com.zyplayer.doc.db.framework.db.dto.ProcedureDto">
select `db`, `name`, `type`, `definer`, `created`, `body`, `param_list` as paramList, `returns` from mysql.proc where db=#{dbName} and `type`=#{typeName} and name=#{procName}
</select>
<delete id="deleteProcedure">
DROP ${typeName} IF EXISTS `${dbName}`.`${procName}`
</delete>
<sql id="ProcedureListCondition">
where db=#{param.dbName}
<if test="param.name != null and param.name != ''">and `name` like #{param.name}</if>
<if test="param.type != null and param.type != ''">and `type` = #{param.type}</if>
</sql>
</mapper>

View File

@@ -3,6 +3,8 @@ package com.zyplayer.doc.db.framework.json;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializeConfig;
import com.alibaba.fastjson.serializer.SimpleDateFormatSerializer;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.github.pagehelper.PageInfo;
import com.zyplayer.doc.core.json.ResponseJson;
import io.swagger.annotations.ApiModelProperty;
@@ -27,6 +29,8 @@ public class DocDbResponseJson implements ResponseJson {
private String errMsg;
@ApiModelProperty(value = "返回数据")
private Object data;
@ApiModelProperty(value = "总数")
private Long total;
public DocDbResponseJson() {
this.errCode = 200;
@@ -76,8 +80,20 @@ public class DocDbResponseJson implements ResponseJson {
}
public void setData(Object data) {
if (null != data) {
if (data instanceof PageInfo) {
PageInfo<?> pageInfo = (PageInfo<?>) data;
this.data = pageInfo.getList();
this.total = pageInfo.getTotal();
} else if (data instanceof IPage) {
IPage<?> iPage = (IPage<?>) data;
this.data = iPage.getRecords();
this.total = iPage.getTotal();
} else {
this.data = data;
}
}
}
/**
* 提示语
@@ -146,4 +162,12 @@ public class DocDbResponseJson implements ResponseJson {
public String toString() {
return "DefaultResponseJson [errCode=" + errCode + ", errMsg=" + errMsg + ", data=" + data + "]";
}
public Long getTotal() {
return total;
}
public void setTotal(Long total) {
this.total = total;
}
}

View File

@@ -1,8 +1,10 @@
package com.zyplayer.doc.db.service;
import cn.hutool.core.util.RandomUtil;
import com.zyplayer.doc.core.exception.ConfirmException;
import com.zyplayer.doc.data.config.security.DocUserUtil;
import com.zyplayer.doc.data.repository.support.consts.DocAuthConst;
import com.zyplayer.doc.db.controller.param.ProcedureListParam;
import com.zyplayer.doc.db.controller.vo.TableColumnVo;
import com.zyplayer.doc.db.controller.vo.TableDdlVo;
import com.zyplayer.doc.db.controller.vo.TableStatusVo;
@@ -10,8 +12,11 @@ import com.zyplayer.doc.db.framework.consts.DbAuthType;
import com.zyplayer.doc.db.framework.db.bean.DatabaseFactoryBean;
import com.zyplayer.doc.db.framework.db.bean.DatabaseRegistrationBean;
import com.zyplayer.doc.db.framework.db.dto.*;
import com.zyplayer.doc.db.framework.db.mapper.base.BaseMapper;
import com.zyplayer.doc.db.framework.db.mapper.base.*;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.*;
@@ -25,6 +30,8 @@ import java.util.stream.Collectors;
*/
public abstract class DbBaseService {
@Resource
SqlExecutor sqlExecutor;
@Resource
DatabaseRegistrationBean databaseRegistrationBean;
@@ -56,6 +63,7 @@ public abstract class DbBaseService {
/**
* 获取当前是什么数据源服务
*
* @return 服务类型
*/
abstract DatabaseFactoryBean.DatabaseProduct getDatabaseProduct();
@@ -262,4 +270,69 @@ public abstract class DbBaseService {
dbResultMap.put("column", tableColumnsMap);
return dbResultMap;
}
/**
* 获取存储过程列表
*
* @param procedureParam 参数
* @author 暮光:城中城
* @since 2020年4月24日
*/
public Long getProcedureCount(ProcedureListParam procedureParam) {
BaseMapper baseMapper = this.getViewAuthBaseMapper(procedureParam.getSourceId());
return baseMapper.getProcedureCount(procedureParam);
}
/**
* 获取存储过程列表
*
* @param procedureParam 参数
* @author 暮光:城中城
* @since 2020年4月24日
*/
public List<ProcedureDto> getProcedureList(ProcedureListParam procedureParam) {
BaseMapper baseMapper = this.getViewAuthBaseMapper(procedureParam.getSourceId());
// MySQL是加%,其他数据库不一样的话需要改到各自的实现里面去
if (StringUtils.isNotBlank(procedureParam.getName())) {
procedureParam.setName("%" + procedureParam.getName() + "%");
}
return baseMapper.getProcedureList(procedureParam);
}
/**
* 获取存储过程详情
*
* @param dbName 数据库名
* @author 暮光:城中城
* @since 2020年4月24日
*/
public ProcedureDto getProcedureDetail(Long sourceId, String dbName, String typeName, String procName) {
BaseMapper baseMapper = this.getViewAuthBaseMapper(sourceId);
return baseMapper.getProcedureDetail(dbName, typeName, procName);
}
/**
* 删除存储过程
*
* @param dbName 数据库名
* @author 暮光:城中城
* @since 2020年4月24日
*/
public void deleteProcedure(Long sourceId, String dbName, String typeName, String procName) {
BaseMapper baseMapper = this.getViewAuthBaseMapper(sourceId);
baseMapper.deleteProcedure(dbName, typeName, procName);
}
/**
* 保存存储过程
*
* @param procSql 存储过程SQL
* @author 暮光:城中城
* @since 2020年4月24日
* @return
*/
public ExecuteResult saveProcedure(Long sourceId, String dbName, String typeName, String procName, String procSql) {
// 需要各数据服务自己实现,各数据库产品的实现都不一样
throw new ConfirmException("暂未支持的数据库类型");
}
}

View File

@@ -1,14 +1,22 @@
package com.zyplayer.doc.db.service;
import cn.hutool.core.util.RandomUtil;
import com.sun.org.apache.bcel.internal.generic.RETURN;
import com.zyplayer.doc.core.exception.ConfirmException;
import com.zyplayer.doc.db.controller.vo.TableDdlVo;
import com.zyplayer.doc.db.framework.db.bean.DatabaseFactoryBean;
import com.zyplayer.doc.db.framework.db.dto.ColumnInfoDto;
import com.zyplayer.doc.db.framework.db.dto.ProcedureDto;
import com.zyplayer.doc.db.framework.db.mapper.base.BaseMapper;
import com.zyplayer.doc.db.framework.db.mapper.base.ExecuteParam;
import com.zyplayer.doc.db.framework.db.mapper.base.ExecuteResult;
import com.zyplayer.doc.db.framework.db.mapper.base.ExecuteType;
import com.zyplayer.doc.db.framework.db.mapper.mysql.MysqlMapper;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
@Service
@@ -49,4 +57,73 @@ public class MysqlServiceImpl extends DbBaseService {
columnInfo.setExtra(StringUtils.isBlank(extra) ? "" : extra);
baseMapper.updateTableColumnDesc(dbName, tableName, columnName, newDesc, columnInfo);
}
@Override
public ProcedureDto getProcedureDetail(Long sourceId, String dbName, String typeName, String procName) {
BaseMapper baseMapper = this.getViewAuthBaseMapper(sourceId);
ProcedureDto procedureDetail = baseMapper.getProcedureDetail(dbName, typeName, procName);
if (procedureDetail == null) {
// 新建的时候
ProcedureDto procedureDetailNew = new ProcedureDto();
if (Objects.equals(typeName, "FUNCTION")) {
procedureDetailNew.setBody("CREATE DEFINER = CURRENT_USER " + typeName + " `" + procName + "`() RETURNS integer\n" +
"BEGIN\n" +
"\t#Routine body goes here...\n" +
"\tRETURN 0;\n" +
"END;");
} else {
procedureDetailNew.setBody("CREATE DEFINER = CURRENT_USER " + typeName + " `" + procName + "`()\n" +
"BEGIN\n" +
"\t#Routine body goes here...\n" +
"END;");
}
procedureDetailNew.setDb(dbName);
procedureDetailNew.setDefiner("CURRENT_USER");
procedureDetailNew.setType(typeName);
return procedureDetailNew;
}
// 组装好SQL
String type = procedureDetail.getType();
String name = procedureDetail.getName();
String paramList = StringUtils.defaultIfBlank(procedureDetail.getParamList(), "");
String[] definerArr = procedureDetail.getDefiner().split("@");
String createStr = String.format("CREATE DEFINER=`%s`@`%s` %s `%s`(%s)", definerArr[0], definerArr[1], type, name, paramList);
if (Objects.equals(procedureDetail.getType(), "FUNCTION")) {
createStr += " RETURNS " + procedureDetail.getReturns();
}
procedureDetail.setBody(createStr + "\r\n" + procedureDetail.getBody());
return procedureDetail;
}
@Override
public ExecuteResult saveProcedure(Long sourceId, String dbName, String typeName, String procName, String procSql) {
String firstLine = procSql.split("\n")[0];
// 看函数名是否被修改了,修改会导致函数名的不确定,有认知上的成本,明确的先删再建吧
if (!firstLine.contains(" `" + procName + "`(") && !firstLine.contains(" " + procName + "(")) {
return ExecuteResult.error("在编辑页面不允许修改函数名,如需新建或修改,请到列表页删除后再新建函数", procSql);
}
ProcedureDto procedureDetail = this.getProcedureDetail(sourceId, dbName, typeName, procName);
// 按MySQL的来是先删除再创建如果其他数据库不是这个逻辑需要重写本方法实现自己的逻辑
BaseMapper baseMapper = this.getViewAuthBaseMapper(sourceId);
baseMapper.deleteProcedure(dbName, typeName, procName);
// 执行创建SQL
ExecuteParam executeParam = new ExecuteParam();
executeParam.setDatasourceId(sourceId);
executeParam.setExecuteId(RandomUtil.randomUUID());
executeParam.setExecuteType(ExecuteType.ALL);
executeParam.setSql(procSql);
executeParam.setMaxRows(1000);
try {
return sqlExecutor.execute(executeParam);
} catch (Exception e) {
try {
// 尝试恢复函数
executeParam.setSql(procedureDetail.getBody());
sqlExecutor.execute(executeParam);
} catch (Exception e1) {
return ExecuteResult.error("执行和恢复函数均失败请先备份您的SQL以防丢失", procSql);
}
return ExecuteResult.error(e.getMessage(), procSql);
}
}
}

View File

@@ -1 +0,0 @@
#app,.el-container,.el-menu{height:100%}.el-header{background-color:#1d4e89!important}.database-list-tree{background-color:#fafafa}.database-list-tree .el-tree-node>.el-tree-node__children{overflow:unset}.el-tree-node__content .el-icon-more{margin-left:5px;color:#606266;font-size:12px;display:none;padding:2px 5px}.el-tree-node__content:hover .el-icon-more{display:inline-block}.login-container{border-radius:5px;-moz-border-radius:5px;background-clip:padding-box;margin:0 auto;width:350px;padding:35px 35px 15px 35px;background:#fff;border:1px solid #eaeaea;-webkit-box-shadow:0 0 25px #cac6c6;box-shadow:0 0 25px #cac6c6}.title{margin:0 auto 40px auto;text-align:center;color:#505458}.remember{margin:0 0 35px 0}.my-info-vue .box-card{margin:10px}.table-info-vue .el-dialog__body{padding:0 20px 10px}.table-info-vue .el-form-item{margin-bottom:5px}.table-info-vue .edit-table-desc{cursor:pointer;color:#409eff}.table-info-vue .description{cursor:pointer;min-height:23px}.table-info-vue .el-table td,.table-info-vue .el-table th{padding:5px 0}.table-info-vue .status-info-row{padding:8px 0}.table-info-vue .status-info-row .label{width:80px;display:inline-block;text-align:right;color:#606266}.table-database-vue .el-table td,.table-database-vue .el-table th{padding:5px 0}body,html{margin:0;padding:0;height:100%}.header-right-user-name{color:#fff;padding-right:5px}.el-menu-vertical{border-right:0}.el-menu-vertical,.el-menu-vertical .el-menu{background:#fafafa}.el-header{background-color:#409eff;color:#333;line-height:40px;text-align:right;height:40px!important}.data-transfer-vue .el-button+.el-button{margin-left:4px}.data-executor-vue .ace-monokai .ace_print-margin{display:none}.data-executor-vue .el-card__body{padding:10px}.data-executor-vue .el-table td,.el-table th{padding:6px 0}.data-executor-vue .execute-result-table .el-input__inner{height:25px;line-height:25px;padding:0 5px}.data-executor-vue .execute-result-table .el-textarea__inner{height:27px;min-height:27px;line-height:25px;padding:0 5px;resize:none}.data-executor-vue .execute-use-time{font-size:12px;margin-right:10px}.data-executor-vue-out .el-tabs__nav-scroll{padding-left:20px}.data-executor-vue-out .el-button+.el-button{margin-left:0}.data-executor-vue-out .el-table__body-wrapper{height:calc(100vh - 180px);overflow-y:auto}

View File

@@ -0,0 +1 @@
#app,.el-container,.el-menu{height:100%}.el-header{background-color:#1d4e89!important}.database-list-tree{background-color:#fafafa}.database-list-tree .el-tree-node>.el-tree-node__children{overflow:unset}.el-tree-node__content .el-icon-more{margin-left:5px;color:#606266;font-size:12px;display:none;padding:2px 5px}.el-tree-node__content:hover .el-icon-more{display:inline-block}.login-container{border-radius:5px;-moz-border-radius:5px;background-clip:padding-box;margin:0 auto;width:350px;padding:35px 35px 15px 35px;background:#fff;border:1px solid #eaeaea;-webkit-box-shadow:0 0 25px #cac6c6;box-shadow:0 0 25px #cac6c6}.title{margin:0 auto 40px auto;text-align:center;color:#505458}.remember{margin:0 0 35px 0}.my-info-vue .box-card{margin:10px}.table-info-vue .el-dialog__body{padding:0 20px 10px}.table-info-vue .el-form-item{margin-bottom:5px}.table-info-vue .edit-table-desc{cursor:pointer;color:#409eff}.table-info-vue .description{cursor:pointer;min-height:23px}.table-info-vue .el-table td,.table-info-vue .el-table th{padding:5px 0}.table-info-vue .status-info-row{padding:8px 0}.table-info-vue .status-info-row .label{width:80px;display:inline-block;text-align:right;color:#606266}.table-database-vue .el-table td,.table-database-vue .el-table th{padding:5px 0}.table-database-vue .label{width:140px;text-align:right}.table-database-vue .el-table th,.table-procedure-edit-vue .el-table td,.table-procedure-vue .el-table td{padding:5px 0}body,html{margin:0;padding:0;height:100%}.header-right-user-name{color:#fff;padding-right:5px}.el-menu-vertical{border-right:0}.el-menu-vertical,.el-menu-vertical .el-menu{background:#fafafa}.el-header{background-color:#409eff;color:#333;line-height:40px;text-align:right;height:40px!important}.data-transfer-vue .el-button+.el-button{margin-left:4px}.data-executor-vue .ace-monokai .ace_print-margin{display:none}.data-executor-vue .el-card__body{padding:10px}.data-executor-vue .el-table td,.el-table th{padding:6px 0}.data-executor-vue .execute-result-table .el-input__inner{height:25px;line-height:25px;padding:0 5px}.data-executor-vue .execute-result-table .el-textarea__inner{height:27px;min-height:27px;line-height:25px;padding:0 5px;resize:none}.data-executor-vue .execute-use-time{font-size:12px;margin-right:10px}.data-executor-vue-out .el-tabs__nav-scroll{padding-left:20px}.data-executor-vue-out .el-button+.el-button{margin-left:0}.data-executor-vue-out .el-table__body-wrapper{height:calc(100vh - 180px);overflow-y:auto}

View File

@@ -1 +1 @@
<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1"><link rel=icon href=favicon-db.png><title>数据库文档管理</title><link href=css/app.1c916a62.css rel=preload as=style><link href=css/chunk-vendors.8924efc6.css rel=preload as=style><link href=js/app.26e84e5d.js rel=preload as=script><link href=js/chunk-vendors.306ce2df.js rel=preload as=script><link href=css/chunk-vendors.8924efc6.css rel=stylesheet><link href=css/app.1c916a62.css rel=stylesheet></head><body><noscript><strong>We're sorry but zyplayer-db-ui doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script src=js/chunk-vendors.306ce2df.js></script><script src=js/app.26e84e5d.js></script></body></html>
<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1"><link rel=icon href=favicon-db.png><title>数据库文档管理</title><link href=css/app.b6b9fe42.css rel=preload as=style><link href=css/chunk-vendors.8924efc6.css rel=preload as=style><link href=js/app.069b56af.js rel=preload as=script><link href=js/chunk-vendors.d40f789d.js rel=preload as=script><link href=css/chunk-vendors.8924efc6.css rel=stylesheet><link href=css/app.b6b9fe42.css rel=stylesheet></head><body><noscript><strong>We're sorry but zyplayer-db-ui doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script src=js/chunk-vendors.d40f789d.js></script><script src=js/app.069b56af.js></script></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -42,6 +42,7 @@
<el-dropdown v-if="data.type == 1" @command="databaseActionDropdown">
<i class="el-icon-more" @click.stop=""></i>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item icon="el-icon-coin" :command="{command: 'procedure', node: node}">函数管理</el-dropdown-item>
<el-dropdown-item icon="el-icon-refresh" :command="{command: 'refresh', node: node}">刷新</el-dropdown-item>
<!-- <el-dropdown-item icon="el-icon-upload2" :command="{command: 'upload', node: node}">导入</el-dropdown-item>-->
<!-- <el-dropdown-item icon="el-icon-download" :command="{command: 'download', node: node}">导出</el-dropdown-item>-->
@@ -166,6 +167,8 @@
}
}
this.datasourceOptions = datasourceOptions;
this.choiceDatasourceId = '';
this.databaseList = [];
},
datasourceChangeEvents() {
this.nowDatasourceShow = this.choiceDatasourceId;
@@ -207,6 +210,10 @@
this.loadGetTableList(param.node.data, () => {
setTimeout(() => param.node.loading = false, 500);
});
} else if (param.command == 'procedure') {
let nodeData = param.node.data;
let procedureParam = {sourceId: this.choiceDatasourceId,dbName: nodeData.dbName, host: nodeData.host};
this.$router.push({path: '/procedure/list', query: procedureParam});
} else {
this.$message.warning("暂未支持的选项");
}

View File

@@ -38,6 +38,9 @@ export default {
manageDatasourceList: data => {
return request({url: '/zyplayer-doc-db/datasource/list', method: 'post', data: Qs.stringify(data)});
},
manageDatasourceGroupList: data => {
return request({url: '/zyplayer-doc-db/datasource/groups', method: 'post', data: Qs.stringify(data)});
},
manageUpdateDatasource: data => {
return request({url: '/zyplayer-doc-db/datasource/update', method: 'post', data: Qs.stringify(data)});
},
@@ -79,6 +82,18 @@ export default {
},
dbUserAuthList: data => {
return request({url: '/zyplayer-doc-db/auth/list', method: 'post', data: Qs.stringify(data)});
},
procedureList: data => {
return request({url: '/zyplayer-doc-db/procedure/list', method: 'post', data: Qs.stringify(data)});
},
deleteProcedure: data => {
return request({url: '/zyplayer-doc-db/procedure/delete', method: 'post', data: Qs.stringify(data)});
},
procedureDetail: data => {
return request({url: '/zyplayer-doc-db/procedure/detail', method: 'post', data: Qs.stringify(data)});
},
saveProcedure: data => {
return request({url: '/zyplayer-doc-db/procedure/save', method: 'post', data: Qs.stringify(data)});
},
systemUpgradeInfo: data => {
return request({url: '/system/info/upgrade', method: 'post', data: Qs.stringify(data)});

View File

@@ -8,6 +8,8 @@ import PageTableView from './components/layouts/PageTableView'
import TableInfo from './views/table/Info.vue'
import TableDatabase from './views/table/Database.vue'
import TableProcedure from './views/table/Procedure.vue'
import TableProcedureEdit from './views/table/ProcedureEdit.vue'
import DataDatasourceManage from './views/data/DatasourceManage.vue'
import DataExport from './views/data/Export.vue'
@@ -35,6 +37,8 @@ let routes = [
children: [
{path: '/table/info', name: '表信息',component: TableInfo},
{path: '/table/database', name: '库信息',component: TableDatabase},
{path: '/procedure/list', name: '存储过程',component: TableProcedure},
{path: '/procedure/edit', name: '编辑存储过程',component: TableProcedureEdit},
{path: '/data/datasourceManage', name: '数据源管理',component: DataDatasourceManage},
{path: '/data/export', name: '数据库导出',component: DataExport},
{path: '/data/executor', name: 'SQL执行器',component: DataExecutor},

View File

@@ -1,17 +1,25 @@
<template>
<div style="padding: 0 10px;">
<el-card>
<div slot="header" class="clearfix">
<span>数据源管理</span>
<el-button style="float: right;margin-left: 5px;" :loading="loadDataListLoading" v-on:click="getDatasourceList" plain icon="el-icon-refresh" size="small">刷新</el-button>
<el-button style="float: right;" v-on:click="addDatasource" type="primary" icon="el-icon-circle-plus-outline" size="small">新增</el-button>
</div>
<el-form :inline="true">
<el-form-item label="名字">
<el-input v-model="searchParam.name" placeholder="名字"></el-input>
</el-form-item>
<el-form-item label="分组">
<el-select v-model="searchParam.groupName" placeholder="分组">
<el-option value="">全部</el-option>
<el-option :value="item" v-for="item in datasourceGroupList"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" :loading="loadDataListLoading" @click="getDatasourceList" icon="el-icon-search">查询</el-button>
<el-button @click="addDatasource" icon="el-icon-circle-plus-outline">新增</el-button>
</el-form-item>
</el-form>
<el-table :data="datasourceList" stripe border style="width: 100%; margin-bottom: 5px;">
<el-table-column prop="name" label="名字" width="200"></el-table-column>
<el-table-column prop="groupName" label="分组" width="100"></el-table-column>
<el-table-column prop="driverClassName" label="驱动类" width="200"></el-table-column>
<el-table-column prop="sourceUrl" label="数据源URL"></el-table-column>
<el-table-column prop="sourceName" label="账号" width="200"></el-table-column>
<el-table-column prop="name" label="名字"></el-table-column>
<el-table-column prop="groupName" label="分组"></el-table-column>
<el-table-column prop="driverClassName" label="驱动类"></el-table-column>
<el-table-column prop="sourceName" label="账号"></el-table-column>
<el-table-column label="操作" width="220">
<template slot-scope="scope">
<el-button v-on:click="editDatasource(scope.row)" type="primary" size="mini">修改</el-button>
@@ -20,7 +28,16 @@
</template>
</el-table-column>
</el-table>
</el-card>
<el-pagination
style="margin-top: 10px;"
@size-change="handlePageSizeChange"
@current-change="handleCurrentChange"
:current-page="currentPage"
:page-sizes="[10, 30, 50]"
:page-size="pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="tableTotalCount">
</el-pagination>
<!--增加数据源弹窗-->
<el-dialog :inline="true" :title="newDatasource.id>0?'编辑数据源':'新增数据源'" :visible.sync="datasourceDialogVisible" width="760px">
<el-form label-width="120px">
@@ -112,6 +129,13 @@
loadDataListLoading: false,
datasourceDialogVisible: false,
datasourceList: [],
searchParam: {
name: '',
groupName: ''
},
pageSize: 30,
currentPage: 1,
tableTotalCount: 0,
newDatasource: {},
urlPlaceholder: "数据源URL",
@@ -130,6 +154,7 @@
},
mounted: function () {
this.getDatasourceList();
this.getDatasourceGroupList();
},
methods: {
editDbAuth(row) {
@@ -248,18 +273,32 @@
this.urlPlaceholder = "例jdbc:postgresql://127.0.0.1:5432/user_info";
}
},
handleCurrentChange(to) {
this.currentPage = to;
this.getDatasourceList();
},
handlePageSizeChange(to) {
this.pageSize = to;
this.getDatasourceList();
},
getDatasourceList() {
this.loadDataListLoading = true;
datasourceApi.manageDatasourceList({}).then(json => {
let param = {...this.searchParam, pageNum: this.currentPage, pageSize: this.pageSize};
datasourceApi.manageDatasourceList(param).then(json => {
if (this.currentPage == 1) {
this.tableTotalCount = json.total || 0;
}
this.datasourceList = json.data || [];
let datasourceGroupList = [];
this.datasourceList.filter(item => !!item.groupName).forEach(item => datasourceGroupList.push(item.groupName));
this.datasourceGroupList = Array.from(new Set(datasourceGroupList));
setTimeout(() => {
this.loadDataListLoading = false;
}, 800);
});
},
getDatasourceGroupList() {
datasourceApi.manageDatasourceGroupList({}).then(json => {
this.datasourceGroupList = json.data || [];
});
},
}
}
</script>

View File

@@ -2,18 +2,18 @@
<div class="table-database-vue">
<el-card style="margin: 10px;" shadow="never">
<div slot="header" class="clearfix">库信息</div>
<el-form label-width="100px">
<el-form-item label="数据源:">{{vueQueryParam.host}}</el-form-item>
<el-form-item label="数据库:">{{vueQueryParam.dbName}}</el-form-item>
</el-form>
<el-form :inline="true" label-width="100px">
<el-form-item label="关键字:">
<el-input v-model="keyword" placeholder="输入字段名或注释搜索相关的表或字段信息" style="width: 500px;"></el-input>
</el-form-item>
<el-form-item>
<el-row style="margin-bottom: 20px;">
<el-col :span="12"><span class="label">数据源</span>{{vueQueryParam.host}}</el-col>
<el-col :span="12"><span class="label">数据库</span>{{vueQueryParam.dbName}}</el-col>
</el-row>
<el-row>
<el-col :span="24">
<span class="label">关键字</span>
<el-input v-model="keyword" placeholder="输入字段名或注释搜索库中相关的表或字段信息" style="width: 350px;margin-right: 10px;"></el-input>
<el-button class="search-submit" type="primary" icon="el-icon-search" @click="searchSubmit">模糊搜索</el-button>
</el-form-item>
</el-form>
<el-button icon="el-icon-coin" @click="funcManage">函数管理</el-button>
</el-col>
</el-row>
</el-card>
<div style="padding: 10px;" v-loading="columnListLoading">
<el-table :data="columnList" stripe border style="width: 100%; margin-bottom: 5px;">
@@ -65,10 +65,14 @@
this.columnListLoading = false;
});
},
funcManage() {
this.$router.push({path: '/procedure/list', query: this.vueQueryParam});
},
}
}
</script>
<style>
.table-database-vue .el-table td, .table-database-vue .el-table th{padding: 5px 0;}
.table-database-vue .label{width: 140px; text-align: right;}
</style>

View File

@@ -0,0 +1,180 @@
<template>
<div class="table-procedure-vue">
<el-card style="margin: 10px;" shadow="never">
<div slot="header" class="clearfix">库信息</div>
<el-row>
<el-col :span="12"><span class="label">数据源</span>{{vueQueryParam.host}}</el-col>
<el-col :span="12"><span class="label">数据库</span>{{vueQueryParam.dbName}}</el-col>
</el-row>
</el-card>
<el-card style="margin: 10px;" shadow="never" header="函数管理">
<el-form :inline="true">
<el-form-item label="名称">
<el-input v-model="searchParam.name" placeholder="名字"></el-input>
</el-form-item>
<el-form-item label="类型">
<el-select v-model="searchParam.type" placeholder="类型">
<el-option value="">全部</el-option>
<el-option value="PROCEDURE" label="存储过程"></el-option>
<el-option value="FUNCTION" label="函数"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" :loading="procedureListLoading" @click="searchProcedureList" icon="el-icon-search">查询</el-button>
<el-button @click="createProc" icon="el-icon-circle-plus-outline">新建函数</el-button>
</el-form-item>
</el-form>
<el-table :data="procedureList" stripe border style="width: 100%;">
<el-table-column prop="name" label="名称" width="200"></el-table-column>
<el-table-column prop="type" label="类型" width="200">
<!--<template slot-scope="scope">{{scope.row.type=='PROCEDURE' ? '过程' : '函数'}}</template>-->
</el-table-column>
<el-table-column prop="definer" label="定义者"></el-table-column>
<el-table-column prop="created" label="创建时间"></el-table-column>
<el-table-column prop="action" label="操作">
<template slot-scope="scope">
<el-button type="primary" @click="doEditProc(scope.row)">编辑</el-button>
<el-button type="danger" @click="doDeleteProc(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination
style="margin-top: 10px;"
@size-change="handlePageSizeChange"
@current-change="handleCurrentChange"
:current-page="currentPage"
:page-sizes="[10, 30, 50]"
:page-size="pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="tableTotalCount">
</el-pagination>
</el-card>
<!--新建函数弹窗-->
<el-dialog :inline="true" title="新建函数" :visible.sync="newProcedureDialogVisible" width="760px">
<el-form label-width="120px">
<el-form-item label="类型:">
<el-select v-model="newProcedureInfo.type" placeholder="请选择类型" style="width: 100%">
<el-option value="PROCEDURE" label="存储过程"></el-option>
<el-option value="FUNCTION" label="函数"></el-option>
</el-select>
</el-form-item>
<el-form-item label="函数名:">
<el-input v-model="newProcedureInfo.name" placeholder="请输入函数名"></el-input>
</el-form-item>
</el-form>
<div slot="footer" style="text-align: center;">
<el-button @click="newProcedureOk" type="primary">下一步</el-button>
<el-button @click="newProcedureDialogVisible=false" plain>取消</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import datasourceApi from '../../common/api/datasource'
export default {
data() {
return {
procedureListLoading: false,
vueQueryParam: {},
procedureList: [],
newProcedureDialogVisible: false,
newProcedureInfo: {
type: '',
name: '',
},
searchParam: {
name: '',
type: ''
},
pageSize: 30,
currentPage: 1,
tableTotalCount: 0,
};
},
mounted: function () {
// 延迟设置展开的目录edit比app先初始化
setTimeout(() => {
this.$emit('initLoadDataList', {
sourceId: this.vueQueryParam.sourceId,
host: this.vueQueryParam.host,
dbName: this.vueQueryParam.dbName
});
}, 500);
this.initQueryParam(this.$route);
this.searchProcedureList();
},
methods: {
initQueryParam(to) {
this.vueQueryParam = to.query;
let newName = {key: this.$route.fullPath, val: '函数管理-' + this.vueQueryParam.dbName};
this.$store.commit('global/addTableName', newName);
},
handleCurrentChange(to) {
this.currentPage = to;
this.searchProcedureList();
},
handlePageSizeChange(to) {
this.pageSize = to;
this.searchProcedureList();
},
searchProcedureList() {
this.procedureListLoading = true;
let param = {...this.vueQueryParam, ...this.searchParam, pageNum: this.currentPage, pageSize: this.pageSize};
datasourceApi.procedureList(param).then(json => {
if (this.currentPage == 1) {
this.tableTotalCount = json.total || 0;
}
this.procedureList = json.data || [];
this.procedureListLoading = false;
});
},
doEditProc(item) {
let param = {...this.vueQueryParam, typeName: item.type, procName: item.name};
this.$router.push({path: '/procedure/edit', query: param});
},
createProc() {
this.newProcedureDialogVisible = true;
},
newProcedureOk() {
if (!this.newProcedureInfo.type) {
this.$message.error("请先选择类型");return;
}
if (!this.newProcedureInfo.name) {
this.$message.error("请先输入函数名");return;
}
let param = {
...this.vueQueryParam,
typeName: this.newProcedureInfo.type,
procName: this.newProcedureInfo.name
};
this.newProcedureDialogVisible = false;
this.newProcedureInfo = {type: '', name: ''};
this.$router.push({path: '/procedure/edit', query: param});
},
doDeleteProc(item) {
let param = {
sourceId: this.vueQueryParam.sourceId,
dbName: this.vueQueryParam.dbName,
typeName: item.type,
procName: item.name
};
this.$confirm('确定要删除此存储过程吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
datasourceApi.deleteProcedure(param).then(json => {
this.$message.success("删除成功!");
this.searchProcedureList();
});
}).catch(() => {});
},
}
}
</script>
<style>
.table-procedure-vue .el-table td, .table-database-vue .el-table th{padding: 5px 0;}
</style>

View File

@@ -0,0 +1,135 @@
<template>
<div class="table-procedure-edit-vue">
<el-card style="margin: 10px;" shadow="never">
<div slot="header" class="clearfix">函数信息</div>
<el-row>
<el-col :span="6"><span class="label">数据源</span>{{vueQueryParam.host}}</el-col>
<el-col :span="6"><span class="label">数据库</span>{{vueQueryParam.dbName}}</el-col>
<el-col :span="6"><span class="label">类型</span>{{vueQueryParam.typeName}}</el-col>
<el-col :span="6"><span class="label">名称</span>{{vueQueryParam.procName}}</el-col>
</el-row>
</el-card>
<el-card style="margin: 10px;" shadow="never" v-loading="procedureInfoLoading">
<div slot="header" class="clearfix">
<span style="margin-right: 20px;">编辑函数</span>
<el-button type="" @click="saveProcedure" icon="el-icon-document-checked" size="mini">保存</el-button>
<!-- <el-button type="" @click="" icon="el-icon-video-play" size="mini">运行</el-button>-->
<!-- <el-button type="" @click="" icon="el-icon-video-pause" size="mini">停止</el-button>-->
</div>
<pre id="sqlExecutorEditor" style="width: 100%;height: 500px;margin-top: 0;"></pre>
</el-card>
<!--错误信息弹窗-->
<el-dialog title="保存函数失败" :visible.sync="saveProcedureErrVisible" :footer="null">
<div style="width: 700px;max-height: 500px;overflow: auto;">
<pre>{{saveProcedureErrInfo}}</pre>
</div>
</el-dialog>
</div>
</template>
<script>
import '../../common/lib/ace/ace'
import '../../common/lib/ace/theme-monokai'
import '../../common/lib/ace/mode-sql'
import '../../common/lib/ace/ext-language_tools'
import '../../common/lib/ace/snippets/sql'
import datasourceApi from '../../common/api/datasource'
export default {
data() {
return {
procedureInfoLoading: false,
vueQueryParam: {},
procedureInfo: {},
sqlExecutorEditor: {},
saveProcedureErrInfo: '',
saveProcedureErrVisible: false,
};
},
mounted: function () {
// 延迟设置展开的目录edit比app先初始化
setTimeout(() => {
this.$emit('initLoadDataList', {
sourceId: this.vueQueryParam.sourceId,
host: this.vueQueryParam.host,
dbName: this.vueQueryParam.dbName
});
}, 500);
let that = this;
this.sqlExecutorEditor = this.initAceEditor("sqlExecutorEditor", 20);
this.sqlExecutorEditor.setFontSize(16);
this.sqlExecutorEditor.commands.addCommand({
name: "execute-sql",
bindKey: {win: "Ctrl-S", mac: "Command-S"},
exec: function (editor) {
that.saveProcedure();
}
});
this.initQueryParam(this.$route);
this.searchProcedureDetail();
},
methods: {
initQueryParam(to) {
this.vueQueryParam = to.query;
let newName = {key: this.$route.fullPath, val: '编辑函数-' + this.vueQueryParam.procName};
this.$store.commit('global/addTableName', newName);
},
searchProcedureDetail() {
this.procedureInfoLoading = true;
datasourceApi.procedureDetail(this.vueQueryParam).then(json => {
this.procedureInfo = json.data || {};
this.procedureInfoLoading = false;
this.sqlExecutorEditor.setValue(this.procedureInfo.body, 1);
});
},
saveProcedure() {
this.procedureInfoLoading = true;
let param = {...this.vueQueryParam, procSql: this.sqlExecutorEditor.getValue()};
datasourceApi.saveProcedure(param).then(json => {
this.procedureInfoLoading = false;
let executeInfo = json.data || {};
if (!!executeInfo.errMsg) {
this.saveProcedureErrInfo = executeInfo.errMsg;
this.saveProcedureErrVisible = true;
} else {
this.$message.success("保存成功!");
}
});
},
doDeleteProc(item) {
let param = {
sourceId: this.vueQueryParam.sourceId,
dbName: this.vueQueryParam.dbName,
typeName: item.type,
procName: item.name
};
this.$confirm('确定要删除此存储过程吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
datasourceApi.deleteProcedure(param).then(json => {
this.$message.success("删除成功!");
});
}).catch(() => {});
},
initAceEditor(editor, minLines) {
return ace.edit(editor, {
theme: "ace/theme/monokai",
mode: "ace/mode/sql",
wrap: true,
autoScrollEditorIntoView: true,
enableBasicAutocompletion: true,
enableSnippets: true,
enableLiveAutocompletion: true,
minLines: minLines,
maxLines: 40,
});
},
}
}
</script>
<style>
.table-procedure-edit-vue .el-table td, .table-database-vue .el-table th{padding: 5px 0;}
</style>