库函数增加修改日志记录,增加函数修改授权,展示优化

This commit is contained in:
暮光:城中城
2021-04-27 23:24:21 +08:00
parent 744e877309
commit 58976dc829
22 changed files with 517 additions and 57 deletions

View File

@@ -0,0 +1,158 @@
package com.zyplayer.doc.data.repository.manage.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import java.io.Serializable;
import java.util.Date;
/**
* <p>
* 数据库函数修改日志
* </p>
*
* @author 暮光:城中城
* @since 2021-04-26
*/
public class DbProcLog implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键自增ID
*/
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/**
* 数据源ID
*/
private Long datasourceId;
/**
* 所属数据库
*/
private String procDb;
/**
* 名字
*/
private String procName;
/**
* 类型
*/
private String procType;
/**
* 函数创建SQL
*/
private String procBody;
/**
* 保存状态 1=成功 2=失败
*/
private Integer status;
/**
* 创建人ID
*/
private Long createUserId;
/**
* 创建人名字
*/
private String createUserName;
/**
* 创建时间
*/
private Date createTime;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getDatasourceId() {
return datasourceId;
}
public void setDatasourceId(Long datasourceId) {
this.datasourceId = datasourceId;
}
public String getProcDb() {
return procDb;
}
public void setProcDb(String procDb) {
this.procDb = procDb;
}
public String getProcName() {
return procName;
}
public void setProcName(String procName) {
this.procName = procName;
}
public String getProcType() {
return procType;
}
public void setProcType(String procType) {
this.procType = procType;
}
public String getProcBody() {
return procBody;
}
public void setProcBody(String procBody) {
this.procBody = procBody;
}
public Long getCreateUserId() {
return createUserId;
}
public void setCreateUserId(Long createUserId) {
this.createUserId = createUserId;
}
public String getCreateUserName() {
return createUserName;
}
public void setCreateUserName(String createUserName) {
this.createUserName = createUserName;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
@Override
public String toString() {
return "DbProcLog{" +
"id=" + id +
", datasourceId=" + datasourceId +
", procDb=" + procDb +
", procName=" + procName +
", procType=" + procType +
", procBody=" + procBody +
", createUserId=" + createUserId +
", createUserName=" + createUserName +
", createTime=" + createTime +
"}";
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
}

View File

@@ -0,0 +1,16 @@
package com.zyplayer.doc.data.repository.manage.mapper;
import com.zyplayer.doc.data.repository.manage.entity.DbProcLog;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* <p>
* 数据库函数修改日志 Mapper 接口
* </p>
*
* @author 暮光:城中城
* @since 2021-04-26
*/
public interface DbProcLogMapper extends BaseMapper<DbProcLog> {
}

View File

@@ -13,15 +13,15 @@ import java.util.ArrayList;
import java.util.List;
public class CodeGenerator {
public static void main(String[] args) {
final String moduleName = "manage";
// final String[] tableName = { "zyplayer_storage", "auth_info", "user_auth", "user_info", "db_datasource" };
// final String[] tableName = { "wiki_space", "wiki_page", "wiki_page_content", "wiki_page_file", "wiki_page_comment", "wiki_page_zan" };
// final String[] tableName = { "db_datasource", "es_datasource", "db_favorite" };
final String[] tableName = { "wiki_space_favorite", "user_setting" };
final String[] tableName = {"db_proc_log"};
// 代码生成器
AutoGenerator mpg = new AutoGenerator();
// 全局配置
@@ -35,7 +35,7 @@ public class CodeGenerator {
gc.setServiceName("%sService");
gc.setControllerName("Generator%sController");
mpg.setGlobalConfig(gc);
// 数据源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://127.0.0.1:3306/zyplayer_doc_manage?useUnicode=true&useSSL=false&characterEncoding=utf8");
@@ -44,7 +44,7 @@ public class CodeGenerator {
dsc.setUsername("root");
dsc.setPassword("root");
mpg.setDataSource(dsc);
// 包配置
final PackageConfig pc = new PackageConfig();
pc.setModuleName(null);
@@ -55,7 +55,7 @@ public class CodeGenerator {
pc.setService("service.manage");
pc.setServiceImpl("service.manage.impl");
mpg.setPackageInfo(pc);
// 自定义配置
InjectionConfig cfg = new InjectionConfig() {
@Override
@@ -73,7 +73,7 @@ public class CodeGenerator {
cfg.setFileOutConfigList(focList);
mpg.setCfg(cfg);
mpg.setTemplate(new TemplateConfig().setXml(null));
// 策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setNaming(NamingStrategy.underline_to_camel);
@@ -90,5 +90,5 @@ public class CodeGenerator {
mpg.setTemplateEngine(new FreemarkerTemplateEngine());
mpg.execute();
}
}

View File

@@ -0,0 +1,16 @@
package com.zyplayer.doc.data.service.manage;
import com.zyplayer.doc.data.repository.manage.entity.DbProcLog;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* <p>
* 数据库函数修改日志 服务类
* </p>
*
* @author 暮光:城中城
* @since 2021-04-26
*/
public interface DbProcLogService extends IService<DbProcLog> {
}

View File

@@ -0,0 +1,20 @@
package com.zyplayer.doc.data.service.manage.impl;
import com.zyplayer.doc.data.repository.manage.entity.DbProcLog;
import com.zyplayer.doc.data.repository.manage.mapper.DbProcLogMapper;
import com.zyplayer.doc.data.service.manage.DbProcLogService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
/**
* <p>
* 数据库函数修改日志 服务实现类
* </p>
*
* @author 暮光:城中城
* @since 2021-04-26
*/
@Service
public class DbProcLogServiceImpl extends ServiceImpl<DbProcLogMapper, DbProcLog> implements DbProcLogService {
}

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zyplayer.doc.data.repository.manage.mapper.DbProcLogMapper">
</mapper>

View File

@@ -67,6 +67,11 @@
<artifactId>easyexcel</artifactId>
<version>2.1.4</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
</dependencies>
<properties>

View File

@@ -91,6 +91,11 @@ public class DbDataSourceAuthController {
UserAuth userAuth = this.createUserAuth(sourceId, currentUser.getUserId(), authVo.getUserId(), authId);
userAuthList.add(userAuth);
}
if (Objects.equals(authVo.getProcEditAuth(), 1)) {
Long authId = authInfoMap.get(DbAuthType.PROC_EDIT.getName());
UserAuth userAuth = this.createUserAuth(sourceId, currentUser.getUserId(), authVo.getUserId(), authId);
userAuthList.add(userAuth);
}
if (userAuthList.size() <= 0) {
continue;
}
@@ -121,7 +126,6 @@ public class DbDataSourceAuthController {
userAuthGroup.forEach((key, value) -> {
Set<String> authNameSet = value.stream().map(auth -> authInfoMap.get(auth.getAuthId())).collect(Collectors.toSet());
UserDbAuthVo authVo = new UserDbAuthVo();
authVo.setExecuteAuth(0);
if (this.haveAuth(authNameSet, DbAuthType.UPDATE) == 1) {
authVo.setExecuteAuth(3);
} else if (this.haveAuth(authNameSet, DbAuthType.SELECT) == 1) {
@@ -130,6 +134,7 @@ public class DbDataSourceAuthController {
authVo.setExecuteAuth(1);
}
authVo.setDescEditAuth(this.haveAuth(authNameSet, DbAuthType.DESC_EDIT));
authVo.setProcEditAuth(this.haveAuth(authNameSet, DbAuthType.PROC_EDIT));
authVo.setUserId(key);
authVo.setUserName(userInfoMap.get(key));
authVoList.add(authVo);

View File

@@ -15,6 +15,7 @@ import com.zyplayer.doc.db.framework.configuration.DatasourceUtil;
import com.zyplayer.doc.db.framework.db.bean.DatabaseFactoryBean;
import com.zyplayer.doc.db.framework.db.bean.DatabaseRegistrationBean;
import com.zyplayer.doc.db.framework.json.DocDbResponseJson;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.springframework.web.bind.annotation.PostMapping;
@@ -59,8 +60,13 @@ public class DbDatasourceController {
public ResponseJson groups() {
QueryWrapper<DbDatasource> wrapper = new QueryWrapper<>();
wrapper.eq("yn", 1);
wrapper.isNotNull("group_name");
wrapper.select("group_name");
wrapper.groupBy("group_name");
List<DbDatasource> datasourceList = dbDatasourceService.list(wrapper);
if (CollectionUtils.isEmpty(datasourceList)) {
return DocDbResponseJson.ok();
}
Set<String> groupNameSet = datasourceList.stream().map(DbDatasource::getGroupName).filter(StringUtils::isNotBlank).collect(Collectors.toSet());
return DocDbResponseJson.ok(groupNameSet);
}

View File

@@ -1,10 +1,20 @@
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.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException;
import com.zyplayer.doc.core.annotation.AuthMan;
import com.zyplayer.doc.core.exception.ConfirmException;
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.DbProcLog;
import com.zyplayer.doc.data.repository.support.consts.DocAuthConst;
import com.zyplayer.doc.data.service.manage.DbProcLogService;
import com.zyplayer.doc.db.controller.param.ProcedureListParam;
import com.zyplayer.doc.db.framework.consts.DbAuthType;
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;
@@ -18,6 +28,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
/**
@@ -34,6 +45,8 @@ public class DbProcedureController {
@Resource
DbBaseFactory dbBaseFactory;
@Resource
DbProcLogService dbProcLogService;
/**
* 存储过程列表
@@ -43,18 +56,19 @@ public class DbProcedureController {
*/
@PostMapping(value = "/list")
public ResponseJson list(ProcedureListParam procedureParam) {
boolean manageAuth = DocUserUtil.haveAuth(DocAuthConst.DB_DATASOURCE_MANAGE);
if (!manageAuth) {
return DocDbResponseJson.warn("没有该数据源的管理权限");
try {
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;
} catch (Exception e) {
// 一般是数据库的帐号没权限查存储过程
return DocDbResponseJson.error(e.getMessage());
}
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;
}
/**
@@ -68,13 +82,14 @@ public class DbProcedureController {
*/
@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);
try {
ProcedureDto procedureDto = dbBaseService.getProcedureDetail(sourceId, dbName, typeName, procName);
return DocDbResponseJson.ok(procedureDto);
} catch (Exception e) {
// 一般是数据库的帐号没权限查存储过程
return DocDbResponseJson.error(e.getMessage());
}
}
/**
@@ -88,13 +103,19 @@ public class DbProcedureController {
*/
@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("没有该数据源的管理权限");
this.judgeAuth(sourceId, DbAuthType.PROC_EDIT.getName(), "没有修改该库函数的权限");
DbProcLog dbProcLog = this.createDbProcLog(sourceId, dbName, typeName, procName, "删除函数操作");
try {
DbBaseService dbBaseService = dbBaseFactory.getDbBaseService(sourceId);
dbBaseService.deleteProcedure(sourceId, dbName, typeName, procName);
return DocDbResponseJson.ok();
} catch (Exception e) {
dbProcLog.setStatus(2);
// 一般是数据库的帐号没权限查存储过程
return DocDbResponseJson.error(e.getMessage());
} finally {
dbProcLogService.save(dbProcLog);
}
DbBaseService dbBaseService = dbBaseFactory.getDbBaseService(sourceId);
dbBaseService.deleteProcedure(sourceId, dbName, typeName, procName);
return DocDbResponseJson.ok();
}
/**
@@ -109,14 +130,93 @@ public class DbProcedureController {
*/
@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("没有该数据源的管理权限");
this.judgeAuth(sourceId, DbAuthType.PROC_EDIT.getName(), "没有修改该库函数的权限");
DbProcLog dbProcLog = this.createDbProcLog(sourceId, dbName, typeName, procName, procSql);
try {
DbBaseService dbBaseService = dbBaseFactory.getDbBaseService(sourceId);
ExecuteResult executeResult = dbBaseService.saveProcedure(sourceId, dbName, typeName, procName, procSql);
if (StringUtils.isNotBlank(executeResult.getErrMsg())) {
dbProcLog.setStatus(2);
}
return DocDbResponseJson.ok(executeResult);
} catch (Exception e) {
dbProcLog.setStatus(2);
// 一般是数据库的帐号没权限查存储过程
return DocDbResponseJson.error(e.getMessage());
} finally {
dbProcLogService.save(dbProcLog);
}
DbBaseService dbBaseService = dbBaseFactory.getDbBaseService(sourceId);
ExecuteResult executeResult = dbBaseService.saveProcedure(sourceId, dbName, typeName, procName, procSql);
return DocDbResponseJson.ok(executeResult);
}
/**
* 存储过程修改日志列表
*
* @param sourceId 数据源ID
* @param dbName 数据库名
* @param typeName 类型名
* @param procName 函数名
* @return 列表
*/
@PostMapping(value = "/log/list")
public ResponseJson logList(Integer pageNum, Integer pageSize, Long sourceId, String dbName, String typeName, String procName) {
QueryWrapper<DbProcLog> wrapper = new QueryWrapper<>();
wrapper.eq("datasource_id", sourceId);
wrapper.eq("proc_db", dbName);
wrapper.eq("proc_name", procName);
wrapper.eq("proc_type", typeName);
wrapper.orderByDesc("id");
wrapper.select("id", "proc_body", "create_user_name", "create_time", "status");
IPage<DbProcLog> page = new Page<>(pageNum, pageSize, pageNum == 1);
dbProcLogService.page(page, wrapper);
return DocDbResponseJson.ok(page);
}
/**
* 存储过程修改日志详情
*
* @param logId 日志ID
* @return 详情
*/
@PostMapping(value = "/log/detail")
public ResponseJson logDetail(Long logId) {
DbProcLog dbProcLog = dbProcLogService.getById(logId);
return DocDbResponseJson.ok(dbProcLog);
}
/**
* 权限判断
*
* @author 暮光:城中城
*/
private void judgeAuth(Long sourceId, String authName, String noAuthInfo) {
if (!DocUserUtil.haveAuth(DocAuthConst.DB_DATASOURCE_MANAGE)
&& !DocUserUtil.haveCustomAuth(authName, DocAuthConst.DB + sourceId)) {
throw new ConfirmException(noAuthInfo);
}
}
/**
* 创建日志对象
* @param sourceId
* @param dbName
* @param typeName
* @param procName
* @param procSql
* @return
*/
public DbProcLog createDbProcLog(Long sourceId, String dbName, String typeName, String procName, String procSql) {
DocUserDetails currentUser = DocUserUtil.getCurrentUser();
DbProcLog dbProcLog = new DbProcLog();
dbProcLog.setDatasourceId(sourceId);
dbProcLog.setCreateTime(new Date());
dbProcLog.setCreateUserId(currentUser.getUserId());
dbProcLog.setCreateUserName(currentUser.getUsername());
dbProcLog.setProcDb(dbName);
dbProcLog.setProcName(procName);
dbProcLog.setProcType(typeName);
dbProcLog.setProcBody(procSql);
dbProcLog.setStatus(1);
return dbProcLog;
}
}

View File

@@ -5,6 +5,7 @@ public class UserDbAuthVo {
private Long userId;
private Integer executeAuth;
private Integer descEditAuth;
private Integer procEditAuth;
public String getUserName() {
return userName;
@@ -37,4 +38,12 @@ public class UserDbAuthVo {
public void setDescEditAuth(Integer descEditAuth) {
this.descEditAuth = descEditAuth;
}
public Integer getProcEditAuth() {
return procEditAuth;
}
public void setProcEditAuth(Integer procEditAuth) {
this.procEditAuth = procEditAuth;
}
}

View File

@@ -5,7 +5,8 @@ public enum DbAuthType {
VIEW(1, "DB_VIEW_"),
SELECT(2, "DB_SELECT_"),
UPDATE(3, "DB_UPDATE_"),
DESC_EDIT(3, "DB_DESC_EDIT_"),
DESC_EDIT(4, "DB_DESC_EDIT_"),
PROC_EDIT(5, "DB_PROC_EDIT_"),
;
private Integer type;
private String name;

View File

@@ -66,13 +66,13 @@ public class MysqlServiceImpl extends DbBaseService {
// 新建的时候
ProcedureDto procedureDetailNew = new ProcedureDto();
if (Objects.equals(typeName, "FUNCTION")) {
procedureDetailNew.setBody("CREATE DEFINER = CURRENT_USER " + typeName + " `" + procName + "`() RETURNS integer\n" +
procedureDetailNew.setBody("CREATE DEFINER = CURRENT_USER " + typeName + " `" + dbName + "`.`" + 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" +
procedureDetailNew.setBody("CREATE DEFINER = CURRENT_USER " + typeName + " `" + dbName + "`.`" + procName + "`()\n" +
"BEGIN\n" +
"\t#Routine body goes here...\n" +
"END;");
@@ -85,9 +85,10 @@ public class MysqlServiceImpl extends DbBaseService {
// 组装好SQL
String type = procedureDetail.getType();
String name = procedureDetail.getName();
String db = procedureDetail.getDb();
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);
String createStr = String.format("CREATE DEFINER=`%s`@`%s` %s `%s`.`%s`(%s)", definerArr[0], definerArr[1], type, db, name, paramList);
if (Objects.equals(procedureDetail.getType(), "FUNCTION")) {
createStr += " RETURNS " + procedureDetail.getReturns();
}
@@ -99,7 +100,7 @@ public class MysqlServiceImpl extends DbBaseService {
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 + "(")) {
if (!firstLine.contains("`" + procName + "`(") && !firstLine.contains(" " + procName + "(") && !firstLine.contains("." + procName + "(")) {
return ExecuteResult.error("在编辑页面不允许修改函数名,如需新建或修改,请到列表页删除后再新建函数", procSql);
}
ProcedureDto procedureDetail = this.getProcedureDetail(sourceId, dbName, typeName, procName);
@@ -121,7 +122,7 @@ public class MysqlServiceImpl extends DbBaseService {
executeParam.setSql(procedureDetail.getBody());
sqlExecutor.execute(executeParam);
} catch (Exception e1) {
return ExecuteResult.error("执行和恢复函数均失败请先备份您的SQL以防丢失", procSql);
return ExecuteResult.error("执行和恢复函数均失败请先备份您的SQL以防丢失\n" + e.getMessage(), procSql);
}
return ExecuteResult.error(e.getMessage(), procSql);
}

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.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>
<!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.a7f24e90.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.a7f24e90.js></script></body></html>

View File

@@ -55,6 +55,7 @@ INSERT INTO `auth_info` VALUES (14, 'DB_VIEW_', '数据源查看权', 0, 1, '201
INSERT INTO `auth_info` VALUES (15, 'DB_SELECT_', '数据源查询权', 0, 1, '2019-08-18 23:25:17', 0);
INSERT INTO `auth_info` VALUES (16, 'DB_UPDATE_', '数据源增删改查权', 0, 1, '2019-08-18 23:25:17', 0);
INSERT INTO `auth_info` VALUES (17, 'DB_DESC_EDIT_', '表字段注释修改权', 0, 1, '2019-08-18 23:25:17', 0);
INSERT INTO `auth_info` VALUES (18, 'DB_PROC_EDIT_', '存储过程修改权', 0, 1, '2021-04-24 23:25:17', 0);
-- ----------------------------
-- Table structure for db_datasource
@@ -467,7 +468,7 @@ CREATE TABLE `wiki_space_favorite` (
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='';
DROP TABLE IF EXISTS `wiki_space_favorite`;
DROP TABLE IF EXISTS `user_setting`;
CREATE TABLE `user_setting` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`user_id` bigint(20) DEFAULT NULL COMMENT 'ID',
@@ -478,5 +479,20 @@ CREATE TABLE `user_setting` (
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='';
DROP TABLE IF EXISTS `db_proc_log`;
CREATE TABLE `db_proc_log` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`datasource_id` bigint(20) DEFAULT NULL COMMENT 'ID',
`proc_db` varchar(100) DEFAULT NULL COMMENT '',
`proc_name` varchar(100) DEFAULT NULL COMMENT '',
`proc_type` varchar(50) DEFAULT NULL COMMENT '',
`proc_body` longblob DEFAULT NULL COMMENT 'SQL',
`status` tinyint(4) NOT NULL DEFAULT '1' COMMENT ' 1= 2=',
`create_user_id` bigint(20) DEFAULT NULL COMMENT 'ID',
`create_user_name` varchar(20) DEFAULT NULL COMMENT '',
`create_time` datetime DEFAULT NULL COMMENT '',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='';
SET FOREIGN_KEY_CHECKS = 1;

View File

@@ -58,4 +58,22 @@ CREATE TABLE `user_setting` (
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='用户设置表';
CREATE TABLE `db_proc_log` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键自增ID',
`datasource_id` bigint(20) DEFAULT NULL COMMENT '数据源ID',
`proc_db` varchar(100) DEFAULT NULL COMMENT '所属数据库',
`proc_name` varchar(100) DEFAULT NULL COMMENT '名字',
`proc_type` varchar(50) DEFAULT NULL COMMENT '类型',
`proc_body` longblob DEFAULT NULL COMMENT '函数创建SQL',
`status` tinyint(4) NOT NULL DEFAULT '1' COMMENT '保存状态 1=成功 2=失败',
`create_user_id` bigint(20) DEFAULT NULL COMMENT '创建人ID',
`create_user_name` varchar(20) DEFAULT NULL COMMENT '创建人名字',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='数据库函数修改日志';
INSERT INTO `auth_info`(auth_name, auth_desc, can_edit, create_uid, creation_time, auth_type)
VALUES ('DB_PROC_EDIT_', '存储过程修改权', 0, 1, '2021-04-24 23:25:17', 0);

View File

@@ -95,6 +95,12 @@ export default {
saveProcedure: data => {
return request({url: '/zyplayer-doc-db/procedure/save', method: 'post', data: Qs.stringify(data)});
},
procedureLogList: data => {
return request({url: '/zyplayer-doc-db/procedure/log/list', method: 'post', data: Qs.stringify(data)});
},
procedureLogDetail: data => {
return request({url: '/zyplayer-doc-db/procedure/log/detail', method: 'post', data: Qs.stringify(data)});
},
systemUpgradeInfo: data => {
return request({url: '/system/info/upgrade', method: 'post', data: Qs.stringify(data)});
},

View File

@@ -83,7 +83,7 @@
<span style="margin-left: 10px;color: #999;font-size: 12px;"><i class="el-icon-info"></i> 添加删除或编辑之后记得点击保存哦~</span>
</span>
<el-row>
<el-select v-model="dbSourceAuthNewUser" filterable remote reserve-keyword
<el-select v-model="dbSourceAuthNewUser" filterable remote reserve-keyword autoComplete="new-password"
placeholder="请输入名字、邮箱、账号搜索用户" :remote-method="getSearchUserList"
:loading="dbSourceAuthUserLoading" style="width: 750px;margin-right: 10px;">
<el-option v-for="item in searchUserList" :key="item.id" :label="item.userName" :value="item.id"></el-option>
@@ -94,11 +94,14 @@
<el-table-column prop="userName" label="用户" width="150"></el-table-column>
<el-table-column label="权限">
<template slot-scope="scope">
<el-radio v-model="scope.row.executeAuth" :label="0">无权限</el-radio>
<el-radio v-model="scope.row.executeAuth" :label="1">库表查看权</el-radio>
<el-radio v-model="scope.row.executeAuth" :label="2">数据查询权</el-radio>
<el-radio v-model="scope.row.executeAuth" :label="3">所有权限</el-radio>
<el-select v-model="scope.row.executeAuth" placeholder="选择权限" style="width: 150px;margin-right: 10px;">
<el-option value="">无权限</el-option>
<el-option :value="1" label="库表查看权"></el-option>
<el-option :value="2" label="数据查询权"></el-option>
<el-option :value="3" label="所有权限"></el-option>
</el-select>
<el-checkbox :true-label="1" :false-label="0" v-model="scope.row.descEditAuth">表字段注释修改权</el-checkbox>
<el-checkbox :true-label="1" :false-label="0" v-model="scope.row.procEditAuth">函数修改权</el-checkbox>
</template>
</el-table-column>
<el-table-column label="操作" width="80">
@@ -201,8 +204,9 @@
this.dbSourceAuthUserList.push({
userName: userName,
userId: this.dbSourceAuthNewUser,
executeAuth: 0,
executeAuth: '',
descEditAuth: 0,
procEditAuth: 0,
});
this.dbSourceAuthNewUser = "";
},
@@ -292,6 +296,8 @@
setTimeout(() => {
this.loadDataListLoading = false;
}, 800);
}).catch(() => {
this.loadDataListLoading = false;
});
},
getDatasourceGroupList() {

View File

@@ -55,11 +55,11 @@
</div>
<div style="padding: 10px;" v-loading="columnListLoading">
<el-table :data="columnList" stripe border style="width: 100%; margin-bottom: 5px;">
<el-table-column prop="name" label="字段名" width="200"></el-table-column>
<el-table-column prop="name" label="字段名" width="220"></el-table-column>
<el-table-column label="自增" width="50">
<template slot-scope="scope">{{scope.row.isidentity ? '是' : '否'}}</template>
</el-table-column>
<el-table-column prop="type" label="类型" width="150"></el-table-column>
<el-table-column prop="type" label="类型" width="180"></el-table-column>
<el-table-column prop="length" label="长度" width="80"></el-table-column>
<el-table-column prop="nullable" label="空值" width="80"></el-table-column>
<el-table-column label="主键" width="50">

View File

@@ -128,6 +128,8 @@
}
this.procedureList = json.data || [];
this.procedureListLoading = false;
}).catch(() => {
this.procedureListLoading = false;
});
},
doEditProc(item) {

View File

@@ -12,7 +12,8 @@
<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="primary" @click="saveProcedure" icon="el-icon-document-checked" size="mini">保存</el-button>
<el-button type="" @click="showProcedureLog" icon="el-icon-document" 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>
@@ -24,6 +25,36 @@
<pre>{{saveProcedureErrInfo}}</pre>
</div>
</el-dialog>
<!--函数修改日志弹窗-->
<el-dialog title="函数修改日志" :visible.sync="procLogVisible" :footer="null">
<el-table :data="procLogList" stripe border style="width: 100%;" height="400">
<el-table-column prop="id" label="ID" width="100"></el-table-column>
<el-table-column prop="createUserName" label="修改人"></el-table-column>
<el-table-column prop="createTime" label="修改时间"></el-table-column>
<el-table-column prop="status" label="状态">
<template slot-scope="scope">
<el-tag type="success" v-if="scope.row.status==1">保存成功</el-tag>
<el-tag type="danger" v-else-if="scope.row.status==2">保存失败</el-tag>
<el-tag type="danger" v-else>-</el-tag>
</template>
</el-table-column>
<el-table-column prop="action" label="操作" width="130">
<template slot-scope="scope">
<el-button type="" @click="reEditProc(scope.row.id)">重新编辑</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-dialog>
</div>
</template>
@@ -44,6 +75,12 @@
sqlExecutorEditor: {},
saveProcedureErrInfo: '',
saveProcedureErrVisible: false,
// 日志列表
procLogVisible: false,
procLogList: [],
pageSize: 30,
currentPage: 1,
tableTotalCount: 0,
};
},
mounted: function () {
@@ -74,12 +111,43 @@
let newName = {key: this.$route.fullPath, val: '编辑函数-' + this.vueQueryParam.procName};
this.$store.commit('global/addTableName', newName);
},
handleCurrentChange(to) {
this.currentPage = to;
this.searchProcedureLogList();
},
handlePageSizeChange(to) {
this.pageSize = to;
this.searchProcedureLogList();
},
showProcedureLog() {
this.currentPage = 1;
this.procLogVisible = true;
this.searchProcedureLogList();
},
searchProcedureLogList() {
let param = {...this.vueQueryParam, ...this.searchParam, pageNum: this.currentPage, pageSize: this.pageSize};
datasourceApi.procedureLogList(param).then(json => {
if (this.currentPage == 1) {
this.tableTotalCount = json.total || 0;
}
this.procLogList = json.data || [];
});
},
reEditProc(id) {
datasourceApi.procedureLogDetail({logId: id}).then(json => {
let procedureLog = json.data || {};
this.sqlExecutorEditor.setValue(procedureLog.procBody, 1);
this.procLogVisible = false;
});
},
searchProcedureDetail() {
this.procedureInfoLoading = true;
datasourceApi.procedureDetail(this.vueQueryParam).then(json => {
this.procedureInfo = json.data || {};
this.procedureInfoLoading = false;
this.sqlExecutorEditor.setValue(this.procedureInfo.body, 1);
}).catch(() => {
this.procedureInfoLoading = false;
});
},
saveProcedure() {
@@ -94,6 +162,8 @@
} else {
this.$message.success("保存成功!");
}
}).catch(() => {
this.procedureInfoLoading = false;
});
},
doDeleteProc(item) {