mirror of
				https://gitee.com/dromara/mayfly-go
				synced 2025-11-04 00:10:25 +08:00 
			
		
		
		
	feat: 机器定时删除终端操作记录
This commit is contained in:
		@@ -22,7 +22,7 @@
 | 
			
		||||
 | 
			
		||||
### 介绍
 | 
			
		||||
 | 
			
		||||
web 版 **linux(终端[终端回放] 文件 脚本 进程 计划任务)、数据库(mysql postgres 达梦)、redis(单机 哨兵 集群)、mongo 统一管理操作平台**
 | 
			
		||||
web 版 **linux(终端[终端回放] 文件 脚本 进程 计划任务)、数据库(mysql postgres oracle 达梦 高斯)、redis(单机 哨兵 集群)、mongo 统一管理操作平台**
 | 
			
		||||
 | 
			
		||||
### 开发语言与主要框架
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,7 @@
 | 
			
		||||
  },
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "@element-plus/icons-vue": "^2.3.1",
 | 
			
		||||
    "@vueuse/core": "^10.7.0",
 | 
			
		||||
    "@vueuse/core": "^10.7.2",
 | 
			
		||||
    "asciinema-player": "^3.6.3",
 | 
			
		||||
    "axios": "^1.6.2",
 | 
			
		||||
    "clipboard": "^2.0.11",
 | 
			
		||||
@@ -31,9 +31,9 @@
 | 
			
		||||
    "screenfull": "^6.0.2",
 | 
			
		||||
    "sortablejs": "^1.15.0",
 | 
			
		||||
    "splitpanes": "^3.1.5",
 | 
			
		||||
    "sql-formatter": "^14.0.0",
 | 
			
		||||
    "sql-formatter": "^15.0.2",
 | 
			
		||||
    "uuid": "^9.0.1",
 | 
			
		||||
    "vue": "^3.4.12",
 | 
			
		||||
    "vue": "^3.4.13",
 | 
			
		||||
    "vue-router": "^4.2.5",
 | 
			
		||||
    "xterm": "^5.3.0",
 | 
			
		||||
    "xterm-addon-fit": "^0.8.0",
 | 
			
		||||
@@ -48,7 +48,7 @@
 | 
			
		||||
    "@typescript-eslint/eslint-plugin": "^6.7.4",
 | 
			
		||||
    "@typescript-eslint/parser": "^6.7.4",
 | 
			
		||||
    "@vitejs/plugin-vue": "^5.0.3",
 | 
			
		||||
    "@vue/compiler-sfc": "^3.4.12",
 | 
			
		||||
    "@vue/compiler-sfc": "^3.4.13",
 | 
			
		||||
    "dotenv": "^16.3.1",
 | 
			
		||||
    "eslint": "^8.35.0",
 | 
			
		||||
    "eslint-plugin-vue": "^9.19.2",
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +1,11 @@
 | 
			
		||||
import { h, render, VNode } from 'vue';
 | 
			
		||||
import SqlExecDialog from './SqlExecDialog.vue';
 | 
			
		||||
import { SqlLanguage } from 'sql-formatter/lib/src/sqlFormatter';
 | 
			
		||||
 | 
			
		||||
export type SqlExecProps = {
 | 
			
		||||
    sql: string;
 | 
			
		||||
    dbId: number;
 | 
			
		||||
    db: string;
 | 
			
		||||
    dbType?: SqlLanguage;
 | 
			
		||||
    dbType?: string;
 | 
			
		||||
    runSuccessCallback?: Function;
 | 
			
		||||
    cancelCallback?: Function;
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -329,11 +329,6 @@ const getNowDbInst = () => {
 | 
			
		||||
onMounted(async () => {
 | 
			
		||||
    console.log('in table data mounted');
 | 
			
		||||
    state.tableHeight = props.tableHeight;
 | 
			
		||||
    const columns = await getNowDbInst().loadColumns(props.dbName, props.tableName);
 | 
			
		||||
    columns.forEach((x: any) => {
 | 
			
		||||
        x.show = true;
 | 
			
		||||
    });
 | 
			
		||||
    state.columns = columns;
 | 
			
		||||
    await onRefresh();
 | 
			
		||||
 | 
			
		||||
    state.dbDialect = getDbDialect(getNowDbInst().type);
 | 
			
		||||
@@ -367,6 +362,14 @@ const selectData = async () => {
 | 
			
		||||
    const db = props.dbName;
 | 
			
		||||
    const table = props.tableName;
 | 
			
		||||
    try {
 | 
			
		||||
        if (state.columns.length == 0) {
 | 
			
		||||
            const columns = await getNowDbInst().loadColumns(props.dbName, props.tableName);
 | 
			
		||||
            columns.forEach((x: any) => {
 | 
			
		||||
                x.show = true;
 | 
			
		||||
            });
 | 
			
		||||
            state.columns = columns;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const countRes = await dbInst.runSql(db, dbInst.getDefaultCountSql(table, state.condition));
 | 
			
		||||
        state.count = countRes.res[0].count || countRes.res[0].COUNT || 0;
 | 
			
		||||
        let sql = dbInst.getDefaultSelectSql(table, state.condition, state.orderBy, state.pageNum, state.pageSize);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,6 @@
 | 
			
		||||
import { MysqlDialect } from './mysql_dialect';
 | 
			
		||||
import { PostgresqlDialect } from './postgres_dialect';
 | 
			
		||||
import { DMDialect } from '@/views/ops/db/dialect/dm_dialect';
 | 
			
		||||
import { SqlLanguage } from 'sql-formatter/lib/src/sqlFormatter';
 | 
			
		||||
import { OracleDialect } from '@/views/ops/db/dialect/oracle_dialect';
 | 
			
		||||
import { MariadbDialect } from '@/views/ops/db/dialect/mariadb_dialect';
 | 
			
		||||
 | 
			
		||||
@@ -92,7 +91,7 @@ export interface DialectInfo {
 | 
			
		||||
    /**
 | 
			
		||||
     * 格式化sql的方言
 | 
			
		||||
     */
 | 
			
		||||
    formatSqlDialect: SqlLanguage;
 | 
			
		||||
    formatSqlDialect: string;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 列字段类型
 | 
			
		||||
 
 | 
			
		||||
@@ -26,8 +26,8 @@ func GetAccountLoginSecurity() *AccountLoginSecurity {
 | 
			
		||||
	als := new(AccountLoginSecurity)
 | 
			
		||||
	als.UseCaptcha = c.ConvBool(jm["useCaptcha"], true)
 | 
			
		||||
	als.UseOtp = c.ConvBool(jm["useOtp"], false)
 | 
			
		||||
	als.LoginFailCount = c.ConvInt(jm["loginFailCount"], 5)
 | 
			
		||||
	als.LoginFailMin = c.ConvInt(jm["loginFailMin"], 10)
 | 
			
		||||
	als.LoginFailCount = stringx.ConvInt(jm["loginFailCount"], 5)
 | 
			
		||||
	als.LoginFailMin = stringx.ConvInt(jm["loginFailMin"], 10)
 | 
			
		||||
	otpIssuer := jm["otpIssuer"]
 | 
			
		||||
	if otpIssuer == "" {
 | 
			
		||||
		otpIssuer = "mayfly-go"
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,9 @@ import (
 | 
			
		||||
	"mayfly-go/pkg/base"
 | 
			
		||||
	"mayfly-go/pkg/contextx"
 | 
			
		||||
	"mayfly-go/pkg/errorx"
 | 
			
		||||
	"mayfly-go/pkg/logx"
 | 
			
		||||
	"mayfly-go/pkg/model"
 | 
			
		||||
	"mayfly-go/pkg/scheduler"
 | 
			
		||||
	"mayfly-go/pkg/utils/stringx"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path"
 | 
			
		||||
@@ -26,6 +28,9 @@ type MachineTermOp interface {
 | 
			
		||||
	TermConn(ctx context.Context, cli *mcm.Cli, wsConn *websocket.Conn, rows, cols int) error
 | 
			
		||||
 | 
			
		||||
	GetPageList(condition *entity.MachineTermOp, pageParam *model.PageParam, toEntity any, orderBy ...string) (*model.PageResult[any], error)
 | 
			
		||||
 | 
			
		||||
	// 定时删除终端文件回放记录
 | 
			
		||||
	TimerDeleteTermOp()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newMachineTermOpApp(machineTermOpRepo repository.MachineTermOp) MachineTermOp {
 | 
			
		||||
@@ -38,7 +43,7 @@ type machineTermOpAppImpl struct {
 | 
			
		||||
	base.AppImpl[*entity.MachineTermOp, repository.MachineTermOp]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (a *machineTermOpAppImpl) TermConn(ctx context.Context, cli *mcm.Cli, wsConn *websocket.Conn, rows, cols int) error {
 | 
			
		||||
func (m *machineTermOpAppImpl) TermConn(ctx context.Context, cli *mcm.Cli, wsConn *websocket.Conn, rows, cols int) error {
 | 
			
		||||
	var recorder *mcm.Recorder
 | 
			
		||||
	var termOpRecord *entity.MachineTermOp
 | 
			
		||||
 | 
			
		||||
@@ -83,11 +88,41 @@ func (a *machineTermOpAppImpl) TermConn(ctx context.Context, cli *mcm.Cli, wsCon
 | 
			
		||||
	if termOpRecord != nil {
 | 
			
		||||
		now := time.Now()
 | 
			
		||||
		termOpRecord.EndTime = &now
 | 
			
		||||
		return a.Insert(ctx, termOpRecord)
 | 
			
		||||
		return m.Insert(ctx, termOpRecord)
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (a *machineTermOpAppImpl) GetPageList(condition *entity.MachineTermOp, pageParam *model.PageParam, toEntity any, orderBy ...string) (*model.PageResult[any], error) {
 | 
			
		||||
	return a.GetRepo().GetPageList(condition, pageParam, toEntity)
 | 
			
		||||
func (m *machineTermOpAppImpl) GetPageList(condition *entity.MachineTermOp, pageParam *model.PageParam, toEntity any, orderBy ...string) (*model.PageResult[any], error) {
 | 
			
		||||
	return m.GetRepo().GetPageList(condition, pageParam, toEntity)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *machineTermOpAppImpl) TimerDeleteTermOp() {
 | 
			
		||||
	logx.Debug("开始定时删除机器终端回放记录...")
 | 
			
		||||
	scheduler.AddFun("@every 60m", func() {
 | 
			
		||||
		startDate := time.Now().AddDate(0, 0, -config.GetMachine().TermOpSaveDays)
 | 
			
		||||
		cond := &entity.MachineTermOpQuery{
 | 
			
		||||
			StartCreateTime: &startDate,
 | 
			
		||||
		}
 | 
			
		||||
		termOps, err := m.GetRepo().SelectByQuery(cond)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		basePath := config.GetMachine().TerminalRecPath
 | 
			
		||||
		for _, termOp := range termOps {
 | 
			
		||||
			if err := m.DeleteTermOp(basePath, termOp); err != nil {
 | 
			
		||||
				logx.Warnf("删除终端操作记录失败: %s", err.Error())
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 删除终端记录即对应文件
 | 
			
		||||
func (m *machineTermOpAppImpl) DeleteTermOp(basePath string, termOp *entity.MachineTermOp) error {
 | 
			
		||||
	if err := m.DeleteById(context.Background(), termOp.Id); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return os.Remove(path.Join(basePath, termOp.RecordFilePath))
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,7 @@ import (
 | 
			
		||||
	sysapp "mayfly-go/internal/sys/application"
 | 
			
		||||
	"mayfly-go/pkg/logx"
 | 
			
		||||
	"mayfly-go/pkg/utils/bytex"
 | 
			
		||||
	"mayfly-go/pkg/utils/stringx"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
@@ -13,6 +14,7 @@ const (
 | 
			
		||||
type Machine struct {
 | 
			
		||||
	TerminalRecPath   string // 终端操作记录存储位置
 | 
			
		||||
	UploadMaxFileSize int64  // 允许上传的最大文件size
 | 
			
		||||
	TermOpSaveDays    int    // 终端记录保存天数
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 获取机器相关配置
 | 
			
		||||
@@ -39,5 +41,6 @@ func GetMachine() *Machine {
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	mc.UploadMaxFileSize = uploadMaxFileSize
 | 
			
		||||
	mc.TermOpSaveDays = stringx.ConvInt(jm["termOpSaveDays"], 30)
 | 
			
		||||
	return mc
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,7 @@
 | 
			
		||||
package entity
 | 
			
		||||
 | 
			
		||||
import "time"
 | 
			
		||||
 | 
			
		||||
type MachineQuery struct {
 | 
			
		||||
	Ids     string `json:"ids" form:"ids"`
 | 
			
		||||
	Name    string `json:"name" form:"name"`
 | 
			
		||||
@@ -15,3 +17,7 @@ type AuthCertQuery struct {
 | 
			
		||||
	Name       string `json:"name" form:"name"`
 | 
			
		||||
	AuthMethod string `json:"authMethod" form:"authMethod"` // IP地址
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type MachineTermOpQuery struct {
 | 
			
		||||
	StartCreateTime *time.Time
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -11,4 +11,7 @@ type MachineTermOp interface {
 | 
			
		||||
 | 
			
		||||
	// 分页获取机器终端执行记录列表
 | 
			
		||||
	GetPageList(condition *entity.MachineTermOp, pageParam *model.PageParam, toEntity any, orderBy ...string) (*model.PageResult[any], error)
 | 
			
		||||
 | 
			
		||||
	// 根据条件获取记录列表
 | 
			
		||||
	SelectByQuery(cond *entity.MachineTermOpQuery) ([]*entity.MachineTermOp, error)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -20,3 +20,11 @@ func (m *machineTermOpRepoImpl) GetPageList(condition *entity.MachineTermOp, pag
 | 
			
		||||
	qd := gormx.NewQuery(condition).WithCondModel(condition).WithOrderBy(orderBy...)
 | 
			
		||||
	return gormx.PageQuery(qd, pageParam, toEntity)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 根据条件获取记录列表
 | 
			
		||||
func (m *machineTermOpRepoImpl) SelectByQuery(cond *entity.MachineTermOpQuery) ([]*entity.MachineTermOp, error) {
 | 
			
		||||
	qd := gormx.NewQuery(m.GetModel()).Le("create_time", cond.StartCreateTime)
 | 
			
		||||
	var res []*entity.MachineTermOp
 | 
			
		||||
	err := gormx.ListByQueryCond(qd, &res)
 | 
			
		||||
	return res, err
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -14,6 +14,8 @@ func Init() {
 | 
			
		||||
 | 
			
		||||
	application.GetMachineApp().TimerUpdateStats()
 | 
			
		||||
 | 
			
		||||
	application.GetMachineTermOpApp().TimerDeleteTermOp()
 | 
			
		||||
 | 
			
		||||
	global.EventBus.Subscribe(consts.DeleteMachineEventTopic, "machineFile", func(ctx context.Context, event *eventbus.Event) error {
 | 
			
		||||
		me := event.Val.(*entity.Machine)
 | 
			
		||||
		return application.GetMachineFileApp().DeleteByCond(ctx, &entity.MachineFile{MachineId: me.Id})
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,7 @@ package entity
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"mayfly-go/pkg/model"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"mayfly-go/pkg/utils/stringx"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
@@ -49,7 +49,7 @@ func (c *Config) IntValue(defaultValue int) int {
 | 
			
		||||
	if c.Id == 0 {
 | 
			
		||||
		return defaultValue
 | 
			
		||||
	}
 | 
			
		||||
	return c.ConvInt(c.Value, defaultValue)
 | 
			
		||||
	return stringx.ConvInt(c.Value, defaultValue)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 转换配置中的值为bool类型(默认"1"或"true"为true,其他为false)
 | 
			
		||||
@@ -59,15 +59,3 @@ func (c *Config) ConvBool(value string, defaultValue bool) bool {
 | 
			
		||||
	}
 | 
			
		||||
	return value == "1" || value == "true"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 转换配置值中的值为int
 | 
			
		||||
func (c *Config) ConvInt(value string, defaultValue int) int {
 | 
			
		||||
	if value == "" {
 | 
			
		||||
		return defaultValue
 | 
			
		||||
	}
 | 
			
		||||
	if intV, err := strconv.Atoi(value); err != nil {
 | 
			
		||||
		return defaultValue
 | 
			
		||||
	} else {
 | 
			
		||||
		return intV
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										17
									
								
								server/pkg/utils/stringx/conv.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								server/pkg/utils/stringx/conv.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
			
		||||
package stringx
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"strconv"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// 将字符串值转为int值, 若value为空或者转换失败,则返回默认值
 | 
			
		||||
func ConvInt(value string, defaultValue int) int {
 | 
			
		||||
	if value == "" {
 | 
			
		||||
		return defaultValue
 | 
			
		||||
	}
 | 
			
		||||
	if intV, err := strconv.Atoi(value); err != nil {
 | 
			
		||||
		return defaultValue
 | 
			
		||||
	} else {
 | 
			
		||||
		return intV
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -622,7 +622,7 @@ INSERT INTO `t_sys_config` (name, `key`, params, value, remark, permission, crea
 | 
			
		||||
INSERT INTO `t_sys_config` (`name`, `key`, `params`, `value`, `remark`, `permission`, `create_time`, `creator_id`, `creator`, `update_time`, `modifier_id`, `modifier`, `is_deleted`, `delete_time`) VALUES('系统全局样式设置', 'SysStyleConfig', '[{"model":"logoIcon","name":"logo图标","placeholder":"系统logo图标(base64编码, 建议svg格式,不超过10k)","required":false},{"model":"title","name":"菜单栏标题","placeholder":"系统菜单栏标题展示","required":false},{"model":"viceTitle","name":"登录页标题","placeholder":"登录页标题展示","required":false},{"model":"useWatermark","name":"是否启用水印","placeholder":"是否启用系统水印","options":"true,false","required":false},{"model":"watermarkContent","name":"水印补充信息","placeholder":"额外水印信息","required":false}]', '{"title":"mayfly-go","viceTitle":"mayfly-go","logoIcon":"","useWatermark":"true","watermarkContent":""}', '系统icon、标题、水印信息等配置', 'all', '2024-01-04 15:17:18', 1, 'admin', '2024-01-05 09:40:44', 1, 'admin', 0, NULL);
 | 
			
		||||
INSERT INTO `t_sys_config` (name, `key`, params, value, remark, create_time, creator_id, creator, update_time, modifier_id, modifier)VALUES ('数据库查询最大结果集', 'DbQueryMaxCount', '[]', '200', '允许sql查询的最大结果集数。注: 0=不限制', '2023-02-11 14:29:03', 1, 'admin', '2023-02-11 14:40:56', 1, 'admin');
 | 
			
		||||
INSERT INTO `t_sys_config` (name, `key`, params, value, remark, create_time, creator_id, creator, update_time, modifier_id, modifier)VALUES ('数据库是否记录查询SQL', 'DbSaveQuerySQL', '[]', '0', '1: 记录、0:不记录', '2023-02-11 16:07:14', 1, 'admin', '2023-02-11 16:44:17', 1, 'admin');
 | 
			
		||||
INSERT INTO `t_sys_config` (name, `key`, params, value, remark, permission, create_time, creator_id, creator, update_time, modifier_id, modifier, is_deleted, delete_time) VALUES('机器相关配置', 'MachineConfig', '[{"name":"终端回放存储路径","model":"terminalRecPath","placeholder":"终端回放存储路径"},{"name":"uploadMaxFileSize","model":"uploadMaxFileSize","placeholder":"允许上传的最大文件大小(1MB\\\\2GB等)"}]', '{"terminalRecPath":"./rec","uploadMaxFileSize":"1GB"}', '机器相关配置,如终端回放路径等', 'admin,', '2023-07-13 16:26:44', 1, 'admin', '2023-11-09 22:01:31', 1, 'admin', 0, NULL);
 | 
			
		||||
INSERT INTO `t_sys_config` (`name`, `key`, `params`, `value`, `remark`, `permission`, `create_time`, `creator_id`, `creator`, `update_time`, `modifier_id`, `modifier`, `is_deleted`, `delete_time`) VALUES('机器相关配置', 'MachineConfig', '[{"name":"终端回放存储路径","model":"terminalRecPath","placeholder":"终端回放存储路径"},{"name":"uploadMaxFileSize","model":"uploadMaxFileSize","placeholder":"允许上传的最大文件大小(1MB\\2GB等)"},{"model":"termOpSaveDays","name":"终端记录保存时间","placeholder":"终端记录保存时间(单位天)"}]', '{"terminalRecPath":"./rec","uploadMaxFileSize":"100MB"}', '机器相关配置,如终端回放路径等', 'all', '2023-07-13 16:26:44', 1, 'admin', '2024-01-15 16:30:22', 1, 'admin', 0, NULL);
 | 
			
		||||
INSERT INTO `t_sys_config` (`name`, `key`, `params`, `value`, `remark`, `permission`, `create_time`, `creator_id`, `creator`, `update_time`, `modifier_id`, `modifier`, `is_deleted`, `delete_time`) VALUES('数据库备份恢复', 'DbBackupRestore', '[{"model":"backupPath","name":"备份路径","placeholder":"备份文件存储路径"}]', '{"backupPath":"./db/backup"}', '', 'admin,', '2023-12-29 09:55:26', 1, 'admin', '2023-12-29 15:45:24', 1, 'admin', 0, NULL);
 | 
			
		||||
INSERT INTO `t_sys_config` (`name`, `key`, `params`, `value`, `remark`, `permission`, `create_time`, `creator_id`, `creator`, `update_time`, `modifier_id`, `modifier`, `is_deleted`, `delete_time`) VALUES('Mysql可执行文件', 'MysqlBin', '[{"model":"path","name":"路径","placeholder":"可执行文件路径","required":true},{"model":"mysql","name":"mysql","placeholder":"mysql命令路径(空则为 路径/mysql)","required":false},{"model":"mysqldump","name":"mysqldump","placeholder":"mysqldump命令路径(空则为 路径/mysqldump)","required":false},{"model":"mysqlbinlog","name":"mysqlbinlog","placeholder":"mysqlbinlog命令路径(空则为 路径/mysqlbinlog)","required":false}]', '{"mysql":"","mysqldump":"","mysqlbinlog":"","path":"./db/mysql/bin"}', '', 'admin,', '2023-12-29 10:01:33', 1, 'admin', '2023-12-29 13:34:40', 1, 'admin', 0, NULL);
 | 
			
		||||
INSERT INTO `t_sys_config` (`name`, `key`, `params`, `value`, `remark`, `permission`, `create_time`, `creator_id`, `creator`, `update_time`, `modifier_id`, `modifier`, `is_deleted`, `delete_time`) VALUES('MariaDB可执行文件', 'MariadbBin', '[{"model":"path","name":"路径","placeholder":"可执行文件路径","required":true},{"model":"mysql","name":"mysql","placeholder":"mysql命令路径(空则为 路径/mysql)","required":false},{"model":"mysqldump","name":"mysqldump","placeholder":"mysqldump命令路径(空则为 路径/mysqldump)","required":false},{"model":"mysqlbinlog","name":"mysqlbinlog","placeholder":"mysqlbinlog命令路径(空则为 路径/mysqlbinlog)","required":false}]', '{"mysql":"","mysqldump":"","mysqlbinlog":"","path":"./db/mariadb/bin"}', '', 'admin,', '2023-12-29 10:01:33', 1, 'admin', '2023-12-29 13:34:40', 1, 'admin', 0, NULL);
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user