mirror of
				https://gitee.com/dromara/mayfly-go
				synced 2025-11-04 08:20:25 +08:00 
			
		
		
		
	Compare commits
	
		
			11 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					b88923a128 | ||
| 
						 | 
					fe8cd93c78 | ||
| 
						 | 
					64b49dae2e | ||
| 
						 | 
					edbbbca5f9 | ||
| 
						 | 
					5ad0d90038 | ||
| 
						 | 
					9b9173dea7 | ||
| 
						 | 
					f58331c1c1 | ||
| 
						 | 
					b2dc9dff0b | ||
| 
						 | 
					51d06ab206 | ||
| 
						 | 
					799e0ac9fc | ||
| 
						 | 
					56e7a8843b | 
							
								
								
									
										18
									
								
								.vscode/launch.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										18
									
								
								.vscode/launch.json
									
									
									
									
										vendored
									
									
								
							@@ -1,18 +0,0 @@
 | 
				
			|||||||
{
 | 
					 | 
				
			||||||
    // 使用 IntelliSense 了解相关属性。 
 | 
					 | 
				
			||||||
    // 悬停以查看现有属性的描述。
 | 
					 | 
				
			||||||
    // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
 | 
					 | 
				
			||||||
    "version": "0.2.0",
 | 
					 | 
				
			||||||
    "configurations": [
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            "name": "mayfly-go",
 | 
					 | 
				
			||||||
            "type": "go",
 | 
					 | 
				
			||||||
            "request": "launch",
 | 
					 | 
				
			||||||
            "mode": "auto",
 | 
					 | 
				
			||||||
            "program": "${fileDirname}/main.go",
 | 
					 | 
				
			||||||
            "env": {},
 | 
					 | 
				
			||||||
            "args": []
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
    ]
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										51
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										51
									
								
								README.md
									
									
									
									
									
								
							@@ -1,7 +1,8 @@
 | 
				
			|||||||
# mayfly-go
 | 
					# 🌈mayfly-go
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 介绍
 | 
				
			||||||
 | 
					简单基于DDD(领域驱动设计)分层架构实现的web版 **linux、数据库(mysql)、redis、mongo统一管理操作平台**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### 介绍
 | 
					 | 
				
			||||||
简单基于DDD(领域驱动设计)分层架构实现web版mysql,redis,linux统一操作管理平台
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
### 开发语言与主要框架
 | 
					### 开发语言与主要框架
 | 
				
			||||||
- 前端:typescript、vue3、element-plus
 | 
					- 前端:typescript、vue3、element-plus
 | 
				
			||||||
@@ -11,23 +12,55 @@
 | 
				
			|||||||
### 交流及问题反馈加 QQ 群
 | 
					### 交流及问题反馈加 QQ 群
 | 
				
			||||||
<a target="_blank" href="https://qm.qq.com/cgi-bin/qm/qr?jump_from=webapi">119699946</a>
 | 
					<a target="_blank" href="https://qm.qq.com/cgi-bin/qm/qr?jump_from=webapi">119699946</a>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### 系统相关资料
 | 
					### 系统相关资料
 | 
				
			||||||
- 项目文档: https://objs.gitee.io/mayfly-go-docs
 | 
					- 项目文档: https://objs.gitee.io/mayfly-go-docs
 | 
				
			||||||
- 系统操作视频: https://space.bilibili.com/484091081/channel/collectiondetail?sid=392854
 | 
					- 系统操作视频: https://space.bilibili.com/484091081/channel/collectiondetail?sid=392854
 | 
				
			||||||
 | 
					- 安装包下载:https://gitee.com/objs/mayfly-go/releases
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### 系统功能
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
记录操作记录
 | 
					### 系统核心功能截图
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					##### 记录操作记录
 | 
				
			||||||

 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### 系统管理
 | 
					#### 机器操作
 | 
				
			||||||
账号管理
 | 
					##### 状态查看
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					##### ssh终端
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					##### 文件操作
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 数据库操作
 | 
				
			||||||
 | 
					##### sql编辑器
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					##### 在线增删改查数据
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### Redis操作
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### Mongo操作
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					##### 系统管理
 | 
				
			||||||
 | 
					##### 账号管理
 | 
				
			||||||

 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
角色管理
 | 
					##### 角色管理
 | 
				
			||||||

 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
资源管理
 | 
					##### 资源管理
 | 
				
			||||||

 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
**其他更多功能&操作指南可查看在线文档**:  https://objs.gitee.io/mayfly-go-docs
 | 
					**其他更多功能&操作指南可查看在线文档**:  https://objs.gitee.io/mayfly-go-docs
 | 
				
			||||||
							
								
								
									
										136
									
								
								build_release.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										136
									
								
								build_release.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,136 @@
 | 
				
			|||||||
 | 
					#bin/bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#----------------------------------------------
 | 
				
			||||||
 | 
					# 前后端打包编译至指定目录,即快速制作发行版
 | 
				
			||||||
 | 
					#----------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					project_path=`pwd`
 | 
				
			||||||
 | 
					# 构建后的二进制执行文件名
 | 
				
			||||||
 | 
					exec_file_name="mayfly-go"
 | 
				
			||||||
 | 
					# web项目目录
 | 
				
			||||||
 | 
					web_folder="${project_path}/mayfly_go_web"
 | 
				
			||||||
 | 
					# server目录
 | 
				
			||||||
 | 
					server_folder="${project_path}/server"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function echo_red() {
 | 
				
			||||||
 | 
					    echo -e "\033[1;31m$1\033[0m"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function echo_green() {
 | 
				
			||||||
 | 
					    echo -e "\033[1;32m$1\033[0m"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function echo_yellow() {
 | 
				
			||||||
 | 
					    echo -e "\033[1;33m$1\033[0m"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function buildWeb() {
 | 
				
			||||||
 | 
					    cd ${web_folder}
 | 
				
			||||||
 | 
					    copy2Server=$1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    echo_yellow "-------------------打包前端开始-------------------"
 | 
				
			||||||
 | 
					    yarn run build
 | 
				
			||||||
 | 
					    if [ "${copy2Server}" == "1" ] ; then
 | 
				
			||||||
 | 
					        echo_green '将打包后的静态文件拷贝至server/static'
 | 
				
			||||||
 | 
					        rm -rf ${server_folder}/static && mkdir -p ${server_folder}/static && cp -r ${web_folder}/dist/* ${server_folder}/static
 | 
				
			||||||
 | 
					    fi
 | 
				
			||||||
 | 
					    echo_yellow ">>>>>>>>>>>>>>>>>>>打包前端结束<<<<<<<<<<<<<<<<<<<<\n"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function build() {
 | 
				
			||||||
 | 
					    cd ${project_path}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # 打包产物的输出目录
 | 
				
			||||||
 | 
					    toFolder=$1
 | 
				
			||||||
 | 
					    os=$2
 | 
				
			||||||
 | 
					    arch=$3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    echo_yellow "-------------------${os}-${arch}打包构建开始-------------------"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cd ${server_folder}
 | 
				
			||||||
 | 
					    echo_green "打包构建可执行文件..."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    execFileName=${exec_file_name}
 | 
				
			||||||
 | 
					    # 如果是windows系统,可执行文件需要添加.exe结尾
 | 
				
			||||||
 | 
					    if [ "${os}" == "windows" ];then
 | 
				
			||||||
 | 
					        execFileName="${execFileName}.exe"
 | 
				
			||||||
 | 
					    fi
 | 
				
			||||||
 | 
					    CGO_ENABLE=0 GOOS=${os} GOARCH=${arch} go build -o ${execFileName} main.go
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if [ -d ${toFolder} ] ; then
 | 
				
			||||||
 | 
					        echo_green "目标文件夹已存在,清空文件夹"
 | 
				
			||||||
 | 
					        sudo rm -rf ${toFolder}
 | 
				
			||||||
 | 
					    fi
 | 
				
			||||||
 | 
					    echo_green "创建'${toFolder}'目录"
 | 
				
			||||||
 | 
					    mkdir ${toFolder}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    echo_green "移动二进制文件至'${toFolder}'"
 | 
				
			||||||
 | 
					    mv ${server_folder}/${execFileName} ${toFolder}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    echo_green "拷贝前端静态页面至'${toFolder}/static'"
 | 
				
			||||||
 | 
					    mkdir -p ${toFolder}/static && cp -r ${web_folder}/dist/* ${toFolder}/static
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    echo_green "拷贝脚本等资源文件[config.yml、mayfly-go.sql、readme.txt、startup.sh、shutdown.sh]"
 | 
				
			||||||
 | 
					    cp ${server_folder}/config.yml ${toFolder}
 | 
				
			||||||
 | 
					    cp ${server_folder}/mayfly-go.sql ${toFolder}
 | 
				
			||||||
 | 
					    cp ${server_folder}/readme.txt ${toFolder}
 | 
				
			||||||
 | 
					    cp ${server_folder}/startup.sh ${toFolder}
 | 
				
			||||||
 | 
					    cp ${server_folder}/shutdown.sh ${toFolder}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    echo_yellow ">>>>>>>>>>>>>>>>>>>${os}-${arch}打包构建完成<<<<<<<<<<<<<<<<<<<<\n"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function buildLinuxAmd64() {
 | 
				
			||||||
 | 
					    build "$1/mayfly-go-linux-amd64" "linux" "amd64"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function buildLinuxArm64() {
 | 
				
			||||||
 | 
					    build "$1/mayfly-go-linux-arm64" "linux" "arm64"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function buildWindows() {
 | 
				
			||||||
 | 
					    build "$1/mayfly-go-windows" "windows" "amd64"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function runBuild() {
 | 
				
			||||||
 | 
					    # 构建结果的目的路径
 | 
				
			||||||
 | 
					    read -p "请输入构建产物输出目录: " toPath
 | 
				
			||||||
 | 
					    if [ ! -d ${toPath} ] ; then
 | 
				
			||||||
 | 
					        echo_red "构建产物输出目录不存在!"
 | 
				
			||||||
 | 
					        exit;
 | 
				
			||||||
 | 
					    fi
 | 
				
			||||||
 | 
					    # 进入目标路径,并赋值全路径
 | 
				
			||||||
 | 
					    cd ${toPath}
 | 
				
			||||||
 | 
					    toPath=`pwd`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    read -p "是否构建前端[0|其他->否 1->是 2->构建并拷贝至server/static]: " runBuildWeb
 | 
				
			||||||
 | 
					    read -p "请选择构建版本[0|其他->全部 1->linux-amd64 2->linux-arm64 3->windows]: " buildType
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    if [ "${runBuildWeb}" == "1" ];then
 | 
				
			||||||
 | 
					        buildWeb
 | 
				
			||||||
 | 
					    fi
 | 
				
			||||||
 | 
					    if [ "${runBuildWeb}" == "2" ];then
 | 
				
			||||||
 | 
					        buildWeb 1
 | 
				
			||||||
 | 
					    fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if [ "${buildType}" == "1" ];then
 | 
				
			||||||
 | 
					        buildLinuxAmd64 ${toPath}
 | 
				
			||||||
 | 
					        exit;
 | 
				
			||||||
 | 
					    fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if [ "${buildType}" == "2" ];then
 | 
				
			||||||
 | 
					        buildLinuxArm64 ${toPath}
 | 
				
			||||||
 | 
					        exit;
 | 
				
			||||||
 | 
					    fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if [ "${buildType}" == "3" ];then
 | 
				
			||||||
 | 
					        buildWindows ${toPath}
 | 
				
			||||||
 | 
					        exit;
 | 
				
			||||||
 | 
					    fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    buildLinuxAmd64 ${toPath}
 | 
				
			||||||
 | 
					    buildLinuxArm64 ${toPath}
 | 
				
			||||||
 | 
					    buildWindows ${toPath}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					runBuild
 | 
				
			||||||
							
								
								
									
										220
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										220
									
								
								go.sum
									
									
									
									
									
								
							@@ -1,220 +0,0 @@
 | 
				
			|||||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
 | 
					 | 
				
			||||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
 | 
					 | 
				
			||||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
 | 
					 | 
				
			||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
 | 
					 | 
				
			||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 | 
					 | 
				
			||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 | 
					 | 
				
			||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 | 
					 | 
				
			||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
 | 
					 | 
				
			||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
 | 
					 | 
				
			||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
 | 
					 | 
				
			||||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
 | 
					 | 
				
			||||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
 | 
					 | 
				
			||||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
 | 
					 | 
				
			||||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
 | 
					 | 
				
			||||||
github.com/gin-gonic/gin v1.7.7 h1:3DoBmSbJbZAWqXJC3SLjAPfutPJJRN1U5pALB7EeTTs=
 | 
					 | 
				
			||||||
github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U=
 | 
					 | 
				
			||||||
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
 | 
					 | 
				
			||||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
 | 
					 | 
				
			||||||
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
 | 
					 | 
				
			||||||
github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU=
 | 
					 | 
				
			||||||
github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
 | 
					 | 
				
			||||||
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
 | 
					 | 
				
			||||||
github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho=
 | 
					 | 
				
			||||||
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
 | 
					 | 
				
			||||||
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
 | 
					 | 
				
			||||||
github.com/go-playground/validator/v10 v10.10.1 h1:uA0+amWMiglNZKZ9FJRKUAe9U3RX91eVn1JYXMWt7ig=
 | 
					 | 
				
			||||||
github.com/go-playground/validator/v10 v10.10.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU=
 | 
					 | 
				
			||||||
github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg=
 | 
					 | 
				
			||||||
github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
 | 
					 | 
				
			||||||
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
 | 
					 | 
				
			||||||
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
 | 
					 | 
				
			||||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
 | 
					 | 
				
			||||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
 | 
					 | 
				
			||||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
 | 
					 | 
				
			||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 | 
					 | 
				
			||||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
 | 
					 | 
				
			||||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
 | 
					 | 
				
			||||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
 | 
					 | 
				
			||||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
 | 
					 | 
				
			||||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
 | 
					 | 
				
			||||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
 | 
					 | 
				
			||||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
 | 
					 | 
				
			||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
 | 
					 | 
				
			||||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
 | 
					 | 
				
			||||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
 | 
					 | 
				
			||||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
 | 
					 | 
				
			||||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
 | 
					 | 
				
			||||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 | 
					 | 
				
			||||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
 | 
					 | 
				
			||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 | 
					 | 
				
			||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 | 
					 | 
				
			||||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
 | 
					 | 
				
			||||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
 | 
					 | 
				
			||||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
 | 
					 | 
				
			||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
 | 
					 | 
				
			||||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
 | 
					 | 
				
			||||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
 | 
					 | 
				
			||||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
 | 
					 | 
				
			||||||
github.com/jinzhu/now v1.1.4 h1:tHnRBy1i5F2Dh8BAFxqFzxKqqvezXrL2OW1TnX+Mlas=
 | 
					 | 
				
			||||||
github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
 | 
					 | 
				
			||||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
 | 
					 | 
				
			||||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
 | 
					 | 
				
			||||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
 | 
					 | 
				
			||||||
github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=
 | 
					 | 
				
			||||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
 | 
					 | 
				
			||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
 | 
					 | 
				
			||||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
 | 
					 | 
				
			||||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
 | 
					 | 
				
			||||||
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
 | 
					 | 
				
			||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 | 
					 | 
				
			||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 | 
					 | 
				
			||||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
 | 
					 | 
				
			||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
 | 
					 | 
				
			||||||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
 | 
					 | 
				
			||||||
github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
 | 
					 | 
				
			||||||
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
 | 
					 | 
				
			||||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
 | 
					 | 
				
			||||||
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
 | 
					 | 
				
			||||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
 | 
					 | 
				
			||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 | 
					 | 
				
			||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
 | 
					 | 
				
			||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 | 
					 | 
				
			||||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
 | 
					 | 
				
			||||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
 | 
					 | 
				
			||||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
 | 
					 | 
				
			||||||
github.com/mojocn/base64Captcha v1.3.5 h1:Qeilr7Ta6eDtG4S+tQuZ5+hO+QHbiGAJdi4PfoagaA0=
 | 
					 | 
				
			||||||
github.com/mojocn/base64Captcha v1.3.5/go.mod h1:/tTTXn4WTpX9CfrmipqRytCpJ27Uw3G6I7NcP2WwcmY=
 | 
					 | 
				
			||||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
 | 
					 | 
				
			||||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
 | 
					 | 
				
			||||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
 | 
					 | 
				
			||||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
 | 
					 | 
				
			||||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
 | 
					 | 
				
			||||||
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
 | 
					 | 
				
			||||||
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
 | 
					 | 
				
			||||||
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
 | 
					 | 
				
			||||||
github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
 | 
					 | 
				
			||||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
 | 
					 | 
				
			||||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
 | 
					 | 
				
			||||||
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
 | 
					 | 
				
			||||||
github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
 | 
					 | 
				
			||||||
github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
 | 
					 | 
				
			||||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
 | 
					 | 
				
			||||||
github.com/pkg/sftp v1.13.4 h1:Lb0RYJCmgUcBgZosfoi9Y9sbl6+LJgOIgk/2Y4YjMFg=
 | 
					 | 
				
			||||||
github.com/pkg/sftp v1.13.4/go.mod h1:LzqnAvaD5TWeNBsZpfKxSYn1MbjWwOsCIAFFJbpIsK8=
 | 
					 | 
				
			||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 | 
					 | 
				
			||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 | 
					 | 
				
			||||||
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
 | 
					 | 
				
			||||||
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
 | 
					 | 
				
			||||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
 | 
					 | 
				
			||||||
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
 | 
					 | 
				
			||||||
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
 | 
					 | 
				
			||||||
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
 | 
					 | 
				
			||||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
 | 
					 | 
				
			||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 | 
					 | 
				
			||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 | 
					 | 
				
			||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
 | 
					 | 
				
			||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
 | 
					 | 
				
			||||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
 | 
					 | 
				
			||||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 | 
					 | 
				
			||||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
 | 
					 | 
				
			||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 | 
					 | 
				
			||||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
 | 
					 | 
				
			||||||
github.com/ugorji/go v1.2.7 h1:qYhyWUUd6WbiM+C6JZAUkIJt/1WrjzNHY9+KCIjVqTo=
 | 
					 | 
				
			||||||
github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
 | 
					 | 
				
			||||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
 | 
					 | 
				
			||||||
github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0=
 | 
					 | 
				
			||||||
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
 | 
					 | 
				
			||||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 | 
					 | 
				
			||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 | 
					 | 
				
			||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 | 
					 | 
				
			||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 | 
					 | 
				
			||||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
 | 
					 | 
				
			||||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 | 
					 | 
				
			||||||
golang.org/x/crypto v0.0.0-20220314234724-5d542ad81a58 h1:L8CkJyVoa0/NslN3RUMLgasK5+KatNvyRGQ9QyCYAfc=
 | 
					 | 
				
			||||||
golang.org/x/crypto v0.0.0-20220314234724-5d542ad81a58/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 | 
					 | 
				
			||||||
golang.org/x/image v0.0.0-20190501045829-6d32002ffd75/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
 | 
					 | 
				
			||||||
golang.org/x/image v0.0.0-20220302094943-723b81ca9867 h1:TcHcE0vrmgzNH1v3ppjcMGbhG5+9fMuvOmUYwNEF4q4=
 | 
					 | 
				
			||||||
golang.org/x/image v0.0.0-20220302094943-723b81ca9867/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
 | 
					 | 
				
			||||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 | 
					 | 
				
			||||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 | 
					 | 
				
			||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 | 
					 | 
				
			||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 | 
					 | 
				
			||||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
 | 
					 | 
				
			||||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
 | 
					 | 
				
			||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 | 
					 | 
				
			||||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
 | 
					 | 
				
			||||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE=
 | 
					 | 
				
			||||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 | 
					 | 
				
			||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 | 
					 | 
				
			||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 | 
					 | 
				
			||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 | 
					 | 
				
			||||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 | 
					 | 
				
			||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 | 
					 | 
				
			||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
					 | 
				
			||||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
					 | 
				
			||||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
					 | 
				
			||||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
					 | 
				
			||||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
					 | 
				
			||||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
					 | 
				
			||||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
					 | 
				
			||||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
					 | 
				
			||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
					 | 
				
			||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
					 | 
				
			||||||
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
					 | 
				
			||||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
					 | 
				
			||||||
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
					 | 
				
			||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
					 | 
				
			||||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
					 | 
				
			||||||
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
					 | 
				
			||||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
					 | 
				
			||||||
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5 h1:y/woIyUBFbpQGKS0u1aHF/40WUDnek3fPOyD08H5Vng=
 | 
					 | 
				
			||||||
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
					 | 
				
			||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
 | 
					 | 
				
			||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 | 
					 | 
				
			||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 | 
					 | 
				
			||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
 | 
					 | 
				
			||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 | 
					 | 
				
			||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 | 
					 | 
				
			||||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
 | 
					 | 
				
			||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
 | 
					 | 
				
			||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 | 
					 | 
				
			||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 | 
					 | 
				
			||||||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
 | 
					 | 
				
			||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 | 
					 | 
				
			||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 | 
					 | 
				
			||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 | 
					 | 
				
			||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
 | 
					 | 
				
			||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 | 
					 | 
				
			||||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
 | 
					 | 
				
			||||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
 | 
					 | 
				
			||||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
 | 
					 | 
				
			||||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
 | 
					 | 
				
			||||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
 | 
					 | 
				
			||||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
 | 
					 | 
				
			||||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
 | 
					 | 
				
			||||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
 | 
					 | 
				
			||||||
google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
 | 
					 | 
				
			||||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
 | 
					 | 
				
			||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 | 
					 | 
				
			||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 | 
					 | 
				
			||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
 | 
					 | 
				
			||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
 | 
					 | 
				
			||||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
 | 
					 | 
				
			||||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
 | 
					 | 
				
			||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
 | 
					 | 
				
			||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
 | 
					 | 
				
			||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 | 
					 | 
				
			||||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 | 
					 | 
				
			||||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 | 
					 | 
				
			||||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 | 
					 | 
				
			||||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
 | 
					 | 
				
			||||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
 | 
					 | 
				
			||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 | 
					 | 
				
			||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
 | 
					 | 
				
			||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 | 
					 | 
				
			||||||
gorm.io/driver/mysql v1.3.2 h1:QJryWiqQ91EvZ0jZL48NOpdlPdMjdip1hQ8bTgo4H7I=
 | 
					 | 
				
			||||||
gorm.io/driver/mysql v1.3.2/go.mod h1:ChK6AHbHgDCFZyJp0F+BmVGb06PSIoh9uVYKAlRbb2U=
 | 
					 | 
				
			||||||
gorm.io/gorm v1.23.1/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
 | 
					 | 
				
			||||||
gorm.io/gorm v1.23.2 h1:xmq9QRMWL8HTJyhAUBXy8FqIIQCYESeKfJL4DoGKiWQ=
 | 
					 | 
				
			||||||
gorm.io/gorm v1.23.2/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
 | 
					 | 
				
			||||||
@@ -7,25 +7,25 @@
 | 
				
			|||||||
    "lint-fix": "eslint --fix --ext .js --ext .jsx --ext .vue src/"
 | 
					    "lint-fix": "eslint --fix --ext .js --ext .jsx --ext .vue src/"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "dependencies": {
 | 
					  "dependencies": {
 | 
				
			||||||
    "axios": "^0.26.1",
 | 
					    "@element-plus/icons-vue": "^2.0.6",
 | 
				
			||||||
    "codemirror": "^5.65.2",
 | 
					    "axios": "^0.27.2",
 | 
				
			||||||
 | 
					    "codemirror": "^5.65.5",
 | 
				
			||||||
    "countup.js": "^2.0.7",
 | 
					    "countup.js": "^2.0.7",
 | 
				
			||||||
    "cropperjs": "^1.5.11",
 | 
					    "cropperjs": "^1.5.11",
 | 
				
			||||||
    "echarts": "^5.3.2",
 | 
					    "echarts": "^5.3.3",
 | 
				
			||||||
    "element-plus": "^2.1.11",
 | 
					    "element-plus": "^2.2.8",
 | 
				
			||||||
    "@element-plus/icons-vue": "^1.1.3",
 | 
					    "jsoneditor": "^9.9.0",
 | 
				
			||||||
    "jsonlint": "^1.6.3",
 | 
					 | 
				
			||||||
    "lodash": "^4.17.21",
 | 
					    "lodash": "^4.17.21",
 | 
				
			||||||
    "mitt": "^3.0.0",
 | 
					    "mitt": "^3.0.0",
 | 
				
			||||||
    "nprogress": "^0.2.0",
 | 
					    "nprogress": "^0.2.0",
 | 
				
			||||||
    "screenfull": "^5.1.0",
 | 
					    "screenfull": "^5.1.0",
 | 
				
			||||||
    "sortablejs": "^1.13.0",
 | 
					    "sortablejs": "^1.13.0",
 | 
				
			||||||
 | 
					    "sql-formatter": "^7.0.3",
 | 
				
			||||||
 | 
					    "vue": "^3.2.37",
 | 
				
			||||||
    "vue-clipboard3": "^1.0.1",
 | 
					    "vue-clipboard3": "^1.0.1",
 | 
				
			||||||
    "sql-formatter": "^4.0.2",
 | 
					    "vue-router": "^4.0.16",
 | 
				
			||||||
    "vue": "^3.2.30",
 | 
					 | 
				
			||||||
    "vue-router": "^4.0.12",
 | 
					 | 
				
			||||||
    "vuex": "^4.0.2",
 | 
					    "vuex": "^4.0.2",
 | 
				
			||||||
    "xterm": "^4.18.0",
 | 
					    "xterm": "^4.19.0",
 | 
				
			||||||
    "xterm-addon-fit": "^0.5.0"
 | 
					    "xterm-addon-fit": "^0.5.0"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "devDependencies": {
 | 
					  "devDependencies": {
 | 
				
			||||||
@@ -35,7 +35,7 @@
 | 
				
			|||||||
    "@types/sortablejs": "^1.10.6",
 | 
					    "@types/sortablejs": "^1.10.6",
 | 
				
			||||||
    "@typescript-eslint/eslint-plugin": "^4.23.0",
 | 
					    "@typescript-eslint/eslint-plugin": "^4.23.0",
 | 
				
			||||||
    "@typescript-eslint/parser": "^4.23.0",
 | 
					    "@typescript-eslint/parser": "^4.23.0",
 | 
				
			||||||
    "@vitejs/plugin-vue": "^1.2.2",
 | 
					    "@vitejs/plugin-vue": "^2.3.3",
 | 
				
			||||||
    "@vue/compiler-sfc": "^3.0.11",
 | 
					    "@vue/compiler-sfc": "^3.0.11",
 | 
				
			||||||
    "dotenv": "^10.0.0",
 | 
					    "dotenv": "^10.0.0",
 | 
				
			||||||
    "eslint": "^8.5.0",
 | 
					    "eslint": "^8.5.0",
 | 
				
			||||||
@@ -43,8 +43,8 @@
 | 
				
			|||||||
    "prettier": "^2.3.0",
 | 
					    "prettier": "^2.3.0",
 | 
				
			||||||
    "sass": "^1.45.1",
 | 
					    "sass": "^1.45.1",
 | 
				
			||||||
    "sass-loader": "^12.4.0",
 | 
					    "sass-loader": "^12.4.0",
 | 
				
			||||||
    "typescript": "^4.2.4",
 | 
					    "typescript": "^4.7.4",
 | 
				
			||||||
    "vite": "^2.8.6",
 | 
					    "vite": "^2.9.13",
 | 
				
			||||||
    "vue-eslint-parser": "^8.0.1"
 | 
					    "vue-eslint-parser": "^8.0.1"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "browserslist": [
 | 
					  "browserslist": [
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										3
									
								
								mayfly_go_web/shim.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								mayfly_go_web/shim.d.ts
									
									
									
									
										vendored
									
									
								
							@@ -5,4 +5,5 @@ declare module '*.vue' {
 | 
				
			|||||||
	export default component;
 | 
						export default component;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
declare module 'codemirror';
 | 
					declare module 'codemirror';
 | 
				
			||||||
declare module 'sql-formatter';
 | 
					declare module 'sql-formatter';
 | 
				
			||||||
 | 
					declare module 'jsoneditor';
 | 
				
			||||||
							
								
								
									
										133
									
								
								mayfly_go_web/src/components/jsonedit/index.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										133
									
								
								mayfly_go_web/src/components/jsonedit/index.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,133 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					    <div>
 | 
				
			||||||
 | 
					        <div ref="jsoneditorVue" :style="{ height: height, width: width }"></div>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script lang="ts">
 | 
				
			||||||
 | 
					import { ref, toRefs, reactive, nextTick, watch, onMounted, onUnmounted, defineComponent } from 'vue';
 | 
				
			||||||
 | 
					import JSONEditor from 'jsoneditor';
 | 
				
			||||||
 | 
					import 'jsoneditor/dist/jsoneditor.min.css';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default defineComponent({
 | 
				
			||||||
 | 
					    name: 'JsonEdit',
 | 
				
			||||||
 | 
					    components: {},
 | 
				
			||||||
 | 
					    props: {
 | 
				
			||||||
 | 
					        modelValue: {
 | 
				
			||||||
 | 
					            type: [String, Object],
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        height: {
 | 
				
			||||||
 | 
					            type: String,
 | 
				
			||||||
 | 
					            default: '500px',
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        width: {
 | 
				
			||||||
 | 
					            type: String,
 | 
				
			||||||
 | 
					            default: 'auto',
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        options: {
 | 
				
			||||||
 | 
					            type: Object,
 | 
				
			||||||
 | 
					            default: null,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        currentMode: {
 | 
				
			||||||
 | 
					            type: String,
 | 
				
			||||||
 | 
					            default: 'tree',
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        modeList: {
 | 
				
			||||||
 | 
					            type: Array,
 | 
				
			||||||
 | 
					            default() {
 | 
				
			||||||
 | 
					                return ['tree', 'code', 'form', 'text', 'view'];
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    setup(props: any, { emit }) {
 | 
				
			||||||
 | 
					        let { modelValue, options, modeList, currentMode } = toRefs(props);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const jsoneditorVue = ref(null)
 | 
				
			||||||
 | 
					        // 编辑器实例
 | 
				
			||||||
 | 
					        let editor = null as any;
 | 
				
			||||||
 | 
					        // 值类型
 | 
				
			||||||
 | 
					        let valueType = 'string';
 | 
				
			||||||
 | 
					        // 是否内部改变(即onChange事件双向绑定),内部改变则不需要重新赋值给editor
 | 
				
			||||||
 | 
					        let internalChange = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const state = reactive({
 | 
				
			||||||
 | 
					            height: '500px',
 | 
				
			||||||
 | 
					            width: 'auto',
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        onMounted(() => {
 | 
				
			||||||
 | 
					            state.width = props.width;
 | 
				
			||||||
 | 
					            state.height = props.height;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            init();
 | 
				
			||||||
 | 
					            setJson(modelValue.value);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        onUnmounted(() => {
 | 
				
			||||||
 | 
					            editor?.destroy();
 | 
				
			||||||
 | 
					            editor = null;
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        watch(
 | 
				
			||||||
 | 
					            () => props.modelValue,
 | 
				
			||||||
 | 
					            (newValue) => {
 | 
				
			||||||
 | 
					                if (!editor) {
 | 
				
			||||||
 | 
					                    init();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                setJson(newValue);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const setJson = (value: any) => {
 | 
				
			||||||
 | 
					            if (internalChange) {
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (typeof value == 'string') {
 | 
				
			||||||
 | 
					                valueType = 'string';
 | 
				
			||||||
 | 
					                editor.set(JSON.parse(value));
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                valueType = 'object';
 | 
				
			||||||
 | 
					                editor.set(value);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const onChange = () => {
 | 
				
			||||||
 | 
					            try {
 | 
				
			||||||
 | 
					                const json = editor.get();
 | 
				
			||||||
 | 
					                if (valueType == 'string') {
 | 
				
			||||||
 | 
					                    emit('update:modelValue', JSON.stringify(json));
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    emit('update:modelValue', json);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                emit('onChange', json);
 | 
				
			||||||
 | 
					                internalChange = true;
 | 
				
			||||||
 | 
					                nextTick(() => {
 | 
				
			||||||
 | 
					                    internalChange = false;
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            } catch (error) {}
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const init = () => {
 | 
				
			||||||
 | 
					            console.log('init json editor');
 | 
				
			||||||
 | 
					            const finalOptions = {
 | 
				
			||||||
 | 
					                ...options.value,
 | 
				
			||||||
 | 
					                mode: currentMode.value,
 | 
				
			||||||
 | 
					                modes: modeList.value,
 | 
				
			||||||
 | 
					                onChange,
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            editor = new JSONEditor(jsoneditorVue.value, finalOptions);
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return {
 | 
				
			||||||
 | 
					            ...toRefs(state),
 | 
				
			||||||
 | 
					            jsoneditorVue,
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style lang="scss">
 | 
				
			||||||
 | 
					div.jsoneditor-menu a.jsoneditor-poweredBy {
 | 
				
			||||||
 | 
					    display: none;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
@@ -18,4 +18,8 @@ export const imports = {
 | 
				
			|||||||
    // redis
 | 
					    // redis
 | 
				
			||||||
    "RedisList": () => import('@/views/ops/redis'),
 | 
					    "RedisList": () => import('@/views/ops/redis'),
 | 
				
			||||||
    "DataOperation": () => import('@/views/ops/redis/DataOperation.vue'),
 | 
					    "DataOperation": () => import('@/views/ops/redis/DataOperation.vue'),
 | 
				
			||||||
 | 
					    // mongo
 | 
				
			||||||
 | 
					    "MongoDataOp": () => import('@/views/ops/mongo/MongoDataOp.vue'),
 | 
				
			||||||
 | 
					    // redis
 | 
				
			||||||
 | 
					    "MongoList": () => import('@/views/ops/mongo/MongoList.vue'),
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -221,26 +221,32 @@ router.beforeEach((to, from, next) => {
 | 
				
			|||||||
    if (to.path === '/login' && !token) {
 | 
					    if (to.path === '/login' && !token) {
 | 
				
			||||||
        next();
 | 
					        next();
 | 
				
			||||||
        NProgress.done();
 | 
					        NProgress.done();
 | 
				
			||||||
    } else {
 | 
					        return;
 | 
				
			||||||
        if (!token) {
 | 
					    }
 | 
				
			||||||
            next(`/login?redirect=${to.path}`);
 | 
					    if (!token) {
 | 
				
			||||||
            clearSession();
 | 
					        next(`/login?redirect=${to.path}`);
 | 
				
			||||||
            resetRoute();
 | 
					        clearSession();
 | 
				
			||||||
            NProgress.done();
 | 
					        resetRoute();
 | 
				
			||||||
 | 
					        NProgress.done();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (SysWs) {
 | 
					        if (SysWs) {
 | 
				
			||||||
                SysWs.close();
 | 
					            SysWs.close();
 | 
				
			||||||
                SysWs = null;
 | 
					            SysWs = null;
 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        } else if (token && to.path === '/login') {
 | 
					 | 
				
			||||||
            next('/');
 | 
					 | 
				
			||||||
            NProgress.done();
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            if (!SysWs) {
 | 
					 | 
				
			||||||
                SysWs = sockets.sysMsgSocket();
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            if (store.state.routesList.routesList.length > 0) next();
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (token && to.path === '/login') {
 | 
				
			||||||
 | 
					        next('/');
 | 
				
			||||||
 | 
					        NProgress.done();
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 终端不需要连接系统websocket消息
 | 
				
			||||||
 | 
					    if (!SysWs && to.path != '/machine/terminal') {
 | 
				
			||||||
 | 
					        SysWs = sockets.sysMsgSocket();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (store.state.routesList.routesList.length > 0) {
 | 
				
			||||||
 | 
					        next();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -239,16 +239,6 @@
 | 
				
			|||||||
	color: set-color(primary);
 | 
						color: set-color(primary);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Switch 开关
 | 
					 | 
				
			||||||
------------------------------- */
 | 
					 | 
				
			||||||
.el-switch.is-checked .el-switch__core {
 | 
					 | 
				
			||||||
	border-color: set-color(primary);
 | 
					 | 
				
			||||||
	background-color: set-color(primary);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
.el-switch__label.is-active {
 | 
					 | 
				
			||||||
	color: set-color(primary);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Slider 滑块
 | 
					/* Slider 滑块
 | 
				
			||||||
------------------------------- */
 | 
					------------------------------- */
 | 
				
			||||||
.el-slider__bar {
 | 
					.el-slider__bar {
 | 
				
			||||||
@@ -993,4 +983,15 @@
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
.el-drawer-fade-leave-active .el-drawer.ltr {
 | 
					.el-drawer-fade-leave-active .el-drawer.ltr {
 | 
				
			||||||
	animation: ltr-drawer-animation 0.3s ease !important;
 | 
						animation: ltr-drawer-animation 0.3s ease !important;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// el-tooltip使用自定义主题时的样式
 | 
				
			||||||
 | 
					.el-popper.is-customized {
 | 
				
			||||||
 | 
					    /* Set padding to ensure the height is 32px */
 | 
				
			||||||
 | 
					  //   padding: 6px 12px;
 | 
				
			||||||
 | 
					    background: linear-gradient(90deg, rgb(159, 229, 151), rgb(204, 229, 129));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  .el-popper.is-customized .el-popper__arrow::before {
 | 
				
			||||||
 | 
					    background: linear-gradient(45deg, #b2e68d, #bce689);
 | 
				
			||||||
 | 
					    right: 0;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
@@ -30,7 +30,7 @@ import { useStore } from '@/store/index.ts';
 | 
				
			|||||||
export default defineComponent({
 | 
					export default defineComponent({
 | 
				
			||||||
    name: 'layoutBreadcrumbSearch',
 | 
					    name: 'layoutBreadcrumbSearch',
 | 
				
			||||||
    setup() {
 | 
					    setup() {
 | 
				
			||||||
        const layoutMenuAutocompleteRef = ref();
 | 
					        const layoutMenuAutocompleteRef: any = ref(null);
 | 
				
			||||||
        const store = useStore();
 | 
					        const store = useStore();
 | 
				
			||||||
        const router = useRouter();
 | 
					        const router = useRouter();
 | 
				
			||||||
        const state: any = reactive({
 | 
					        const state: any = reactive({
 | 
				
			||||||
@@ -68,7 +68,6 @@ export default defineComponent({
 | 
				
			|||||||
        // 初始化菜单数据
 | 
					        // 初始化菜单数据
 | 
				
			||||||
        const initTageView = () => {
 | 
					        const initTageView = () => {
 | 
				
			||||||
            if (state.tagsViewList.length > 0) return false;
 | 
					            if (state.tagsViewList.length > 0) return false;
 | 
				
			||||||
            console.log(getRoutes(store.state.routesList.routesList));
 | 
					 | 
				
			||||||
            getRoutes(store.state.routesList.routesList).map((v: any) => {
 | 
					            getRoutes(store.state.routesList.routesList).map((v: any) => {
 | 
				
			||||||
                if (!v.meta.isHide) {
 | 
					                if (!v.meta.isHide) {
 | 
				
			||||||
                    state.tagsViewList.push({ ...v });
 | 
					                    state.tagsViewList.push({ ...v });
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -292,10 +292,7 @@ export default defineComponent({
 | 
				
			|||||||
            emit('cancel');
 | 
					            emit('cancel');
 | 
				
			||||||
            setTimeout(() => {
 | 
					            setTimeout(() => {
 | 
				
			||||||
                resetInputDb();
 | 
					                resetInputDb();
 | 
				
			||||||
                dbForm.value.resetFields();
 | 
					            }, 500);
 | 
				
			||||||
                //  重置对象属性为null
 | 
					 | 
				
			||||||
                state.form = {} as any;
 | 
					 | 
				
			||||||
            }, 200);
 | 
					 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return {
 | 
					        return {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,17 +7,10 @@
 | 
				
			|||||||
                >删除</el-button
 | 
					                >删除</el-button
 | 
				
			||||||
            >
 | 
					            >
 | 
				
			||||||
            <div style="float: right">
 | 
					            <div style="float: right">
 | 
				
			||||||
                <el-form class="search-form" label-position="right" :inline="true" label-width="60px">
 | 
					                <el-select v-model="query.projectId" placeholder="请选择项目" filterable clearable>
 | 
				
			||||||
                    <el-form-item prop="project">
 | 
					                    <el-option v-for="item in projects" :key="item.id" :label="`${item.name} [${item.remark}]`" :value="item.id"> </el-option>
 | 
				
			||||||
                        <el-select v-model="query.projectId" placeholder="请选择项目" filterable clearable>
 | 
					                </el-select>
 | 
				
			||||||
                            <el-option v-for="item in projects" :key="item.id" :label="`${item.name} [${item.remark}]`" :value="item.id"> </el-option>
 | 
					                <el-button v-waves type="primary" icon="search" @click="search()" class="ml5">查询</el-button>
 | 
				
			||||||
                        </el-select>
 | 
					 | 
				
			||||||
                    </el-form-item>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    <el-form-item>
 | 
					 | 
				
			||||||
                        <el-button v-waves type="primary" icon="search" @click="search()">查询</el-button>
 | 
					 | 
				
			||||||
                    </el-form-item>
 | 
					 | 
				
			||||||
                </el-form>
 | 
					 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
            <el-table :data="datas" ref="table" @current-change="choose" show-overflow-tooltip stripe>
 | 
					            <el-table :data="datas" ref="table" @current-change="choose" show-overflow-tooltip stripe>
 | 
				
			||||||
                <el-table-column label="选择" width="60px">
 | 
					                <el-table-column label="选择" width="60px">
 | 
				
			||||||
@@ -59,8 +52,11 @@
 | 
				
			|||||||
                    </template>
 | 
					                    </template>
 | 
				
			||||||
                </el-table-column>
 | 
					                </el-table-column>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                <!-- <el-table-column fixed="right" label="更多信息" min-width="100">
 | 
					                <el-table-column label="操作" min-width="120" fixed="right">
 | 
				
			||||||
                </el-table-column> -->
 | 
					                    <template #default="scope">
 | 
				
			||||||
 | 
					                        <el-link type="primary" plain size="small" :underline="false" @click="onShowSqlExec(scope.row)">SQL执行记录</el-link>
 | 
				
			||||||
 | 
					                    </template>
 | 
				
			||||||
 | 
					                </el-table-column>
 | 
				
			||||||
            </el-table>
 | 
					            </el-table>
 | 
				
			||||||
            <el-row style="margin-top: 20px" type="flex" justify="end">
 | 
					            <el-row style="margin-top: 20px" type="flex" justify="end">
 | 
				
			||||||
                <el-pagination
 | 
					                <el-pagination
 | 
				
			||||||
@@ -76,9 +72,35 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        <el-dialog width="75%" :title="`${db} 表信息`" :before-close="closeTableInfo" v-model="tableInfoDialog.visible">
 | 
					        <el-dialog width="75%" :title="`${db} 表信息`" :before-close="closeTableInfo" v-model="tableInfoDialog.visible">
 | 
				
			||||||
            <el-row class="mb10">
 | 
					            <el-row class="mb10">
 | 
				
			||||||
 | 
					                <el-popover v-model:visible="showDumpInfo" :width="470" placement="right">
 | 
				
			||||||
 | 
					                    <template #reference>
 | 
				
			||||||
 | 
					                        <el-button class="ml5" type="success" size="small" @click="showDumpInfo = !showDumpInfo">导出</el-button>
 | 
				
			||||||
 | 
					                    </template>
 | 
				
			||||||
 | 
					                    <el-form-item label="导出内容: ">
 | 
				
			||||||
 | 
					                        <el-radio-group v-model="dumpInfo.type">
 | 
				
			||||||
 | 
					                            <el-radio :label="1" size="small">结构</el-radio>
 | 
				
			||||||
 | 
					                            <el-radio :label="2" size="small">数据</el-radio>
 | 
				
			||||||
 | 
					                            <el-radio :label="3" size="small">结构+数据</el-radio>
 | 
				
			||||||
 | 
					                        </el-radio-group>
 | 
				
			||||||
 | 
					                    </el-form-item>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    <el-form-item label="导出表: ">
 | 
				
			||||||
 | 
					                        <el-table @selection-change="handleDumpTableSelectionChange" max-height="300" size="small" :data="tableInfoDialog.infos">
 | 
				
			||||||
 | 
					                            <el-table-column type="selection" width="45" />
 | 
				
			||||||
 | 
					                            <el-table-column property="tableName" label="表名" min-width="150" show-overflow-tooltip> </el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column property="tableComment" label="备注" min-width="150" show-overflow-tooltip></el-table-column>
 | 
				
			||||||
 | 
					                        </el-table>
 | 
				
			||||||
 | 
					                    </el-form-item>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    <div style="text-align: right">
 | 
				
			||||||
 | 
					                        <el-button @click="showDumpInfo = false" size="small">取消</el-button>
 | 
				
			||||||
 | 
					                        <el-button @click="dump(db)" type="success" size="small">确定</el-button>
 | 
				
			||||||
 | 
					                    </div>
 | 
				
			||||||
 | 
					                </el-popover>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                <el-button type="primary" size="small" @click="tableCreateDialog.visible = true">创建表</el-button>
 | 
					                <el-button type="primary" size="small" @click="tableCreateDialog.visible = true">创建表</el-button>
 | 
				
			||||||
            </el-row>
 | 
					            </el-row>
 | 
				
			||||||
            <el-table border stripe :data="tableInfoDialog.infos" size="small">
 | 
					            <el-table v-loading="tableInfoDialog.loading" border stripe :data="tableInfoDialog.infos" size="small">
 | 
				
			||||||
                <el-table-column property="tableName" label="表名" min-width="150" show-overflow-tooltip></el-table-column>
 | 
					                <el-table-column property="tableName" label="表名" min-width="150" show-overflow-tooltip></el-table-column>
 | 
				
			||||||
                <el-table-column property="tableComment" label="备注" min-width="150" show-overflow-tooltip></el-table-column>
 | 
					                <el-table-column property="tableComment" label="备注" min-width="150" show-overflow-tooltip></el-table-column>
 | 
				
			||||||
                <el-table-column
 | 
					                <el-table-column
 | 
				
			||||||
@@ -124,6 +146,69 @@
 | 
				
			|||||||
            </el-table>
 | 
					            </el-table>
 | 
				
			||||||
        </el-dialog>
 | 
					        </el-dialog>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <el-dialog
 | 
				
			||||||
 | 
					            width="90%"
 | 
				
			||||||
 | 
					            :title="`${sqlExecLogDialog.title} - SQL执行记录`"
 | 
				
			||||||
 | 
					            :before-close="onBeforeCloseSqlExecDialog"
 | 
				
			||||||
 | 
					            v-model="sqlExecLogDialog.visible"
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					            <div class="toolbar">
 | 
				
			||||||
 | 
					                <el-input v-model="sqlExecLogDialog.query.db" placeholder="请输入数据库名" clearable style="width: 150px" />
 | 
				
			||||||
 | 
					                <el-input v-model="sqlExecLogDialog.query.table" placeholder="请输入表名" clearable class="ml5" style="width: 150px" />
 | 
				
			||||||
 | 
					                <el-select v-model="sqlExecLogDialog.query.type" placeholder="请选择操作类型" clearable class="ml5">
 | 
				
			||||||
 | 
					                    <el-option v-for="item in enums.DbSqlExecTypeEnum" :key="item.value" :label="item.label" :value="item.value"> </el-option>
 | 
				
			||||||
 | 
					                </el-select>
 | 
				
			||||||
 | 
					                <el-button class="ml5" @click="searchSqlExecLog" type="success" icon="search"></el-button>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					            <el-table border stripe :data="sqlExecLogDialog.data" size="small">
 | 
				
			||||||
 | 
					                <el-table-column prop="db" label="数据库" min-width="60" show-overflow-tooltip> </el-table-column>
 | 
				
			||||||
 | 
					                <el-table-column prop="table" label="表" min-width="60" show-overflow-tooltip> </el-table-column>
 | 
				
			||||||
 | 
					                <el-table-column prop="type" label="类型" width="85" show-overflow-tooltip>
 | 
				
			||||||
 | 
					                    <template #default="scope">
 | 
				
			||||||
 | 
					                        <el-tag v-if="scope.row.type == enums.DbSqlExecTypeEnum.UPDATE.value" color="#E4F5EB" size="small">UPDATE</el-tag>
 | 
				
			||||||
 | 
					                        <el-tag v-if="scope.row.type == enums.DbSqlExecTypeEnum.DELETE.value" color="#F9E2AE" size="small">DELETE</el-tag>
 | 
				
			||||||
 | 
					                        <el-tag v-if="scope.row.type == enums.DbSqlExecTypeEnum.INSERT.value" color="#A8DEE0" size="small">INSERT</el-tag>
 | 
				
			||||||
 | 
					                    </template>
 | 
				
			||||||
 | 
					                </el-table-column>
 | 
				
			||||||
 | 
					                <el-table-column prop="sql" label="SQL" min-width="230" show-overflow-tooltip> </el-table-column>
 | 
				
			||||||
 | 
					                <el-table-column prop="oldValue" label="原值" min-width="150" show-overflow-tooltip> </el-table-column>
 | 
				
			||||||
 | 
					                <el-table-column prop="creator" label="执行人" min-width="60" show-overflow-tooltip> </el-table-column>
 | 
				
			||||||
 | 
					                <el-table-column prop="createTime" label="执行时间" show-overflow-tooltip>
 | 
				
			||||||
 | 
					                    <template #default="scope">
 | 
				
			||||||
 | 
					                        {{ $filters.dateFormat(scope.row.createTime) }}
 | 
				
			||||||
 | 
					                    </template>
 | 
				
			||||||
 | 
					                </el-table-column>
 | 
				
			||||||
 | 
					                <el-table-column prop="remark" label="备注" min-width="60" show-overflow-tooltip> </el-table-column>
 | 
				
			||||||
 | 
					                <el-table-column label="操作" min-width="50" fixed="right">
 | 
				
			||||||
 | 
					                    <template #default="scope">
 | 
				
			||||||
 | 
					                        <el-link
 | 
				
			||||||
 | 
					                            v-if="scope.row.type == enums.DbSqlExecTypeEnum.UPDATE.value || scope.row.type == enums.DbSqlExecTypeEnum.DELETE.value"
 | 
				
			||||||
 | 
					                            type="primary"
 | 
				
			||||||
 | 
					                            plain
 | 
				
			||||||
 | 
					                            size="small"
 | 
				
			||||||
 | 
					                            :underline="false"
 | 
				
			||||||
 | 
					                            @click="onShowRollbackSql(scope.row)"
 | 
				
			||||||
 | 
					                            >还原SQL</el-link
 | 
				
			||||||
 | 
					                        >
 | 
				
			||||||
 | 
					                    </template>
 | 
				
			||||||
 | 
					                </el-table-column>
 | 
				
			||||||
 | 
					            </el-table>
 | 
				
			||||||
 | 
					            <el-row style="margin-top: 20px" type="flex" justify="end">
 | 
				
			||||||
 | 
					                <el-pagination
 | 
				
			||||||
 | 
					                    style="text-align: right"
 | 
				
			||||||
 | 
					                    @current-change="handleSqlExecPageChange"
 | 
				
			||||||
 | 
					                    :total="sqlExecLogDialog.total"
 | 
				
			||||||
 | 
					                    layout="prev, pager, next, total, jumper"
 | 
				
			||||||
 | 
					                    v-model:current-page="sqlExecLogDialog.query.pageNum"
 | 
				
			||||||
 | 
					                    :page-size="sqlExecLogDialog.query.pageSize"
 | 
				
			||||||
 | 
					                ></el-pagination>
 | 
				
			||||||
 | 
					            </el-row>
 | 
				
			||||||
 | 
					        </el-dialog>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <el-dialog width="55%" :title="`还原SQL`" v-model="rollbackSqlDialog.visible">
 | 
				
			||||||
 | 
					            <el-input type="textarea" :autosize="{ minRows: 15, maxRows: 30 }" v-model="rollbackSqlDialog.sql" size="small"> </el-input>
 | 
				
			||||||
 | 
					        </el-dialog>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <el-dialog width="40%" :title="`${chooseTableName} 字段信息`" v-model="columnDialog.visible">
 | 
					        <el-dialog width="40%" :title="`${chooseTableName} 字段信息`" v-model="columnDialog.visible">
 | 
				
			||||||
            <el-table border stripe :data="columnDialog.columns" size="small">
 | 
					            <el-table border stripe :data="columnDialog.columns" size="small">
 | 
				
			||||||
                <el-table-column prop="columnName" label="名称" show-overflow-tooltip> </el-table-column>
 | 
					                <el-table-column prop="columnName" label="名称" show-overflow-tooltip> </el-table-column>
 | 
				
			||||||
@@ -164,8 +249,13 @@ import { formatByteSize } from '@/common/utils/format';
 | 
				
			|||||||
import DbEdit from './DbEdit.vue';
 | 
					import DbEdit from './DbEdit.vue';
 | 
				
			||||||
import CreateTable from './CreateTable.vue';
 | 
					import CreateTable from './CreateTable.vue';
 | 
				
			||||||
import { dbApi } from './api';
 | 
					import { dbApi } from './api';
 | 
				
			||||||
 | 
					import enums from './enums';
 | 
				
			||||||
import { projectApi } from '../project/api.ts';
 | 
					import { projectApi } from '../project/api.ts';
 | 
				
			||||||
import SqlExecBox from './component/SqlExecBox.ts';
 | 
					import SqlExecBox from './component/SqlExecBox.ts';
 | 
				
			||||||
 | 
					import config from '@/common/config';
 | 
				
			||||||
 | 
					import { getSession } from '@/common/utils/storage';
 | 
				
			||||||
 | 
					import { isTrue } from '@/common/assert';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default defineComponent({
 | 
					export default defineComponent({
 | 
				
			||||||
    name: 'DbList',
 | 
					    name: 'DbList',
 | 
				
			||||||
    components: {
 | 
					    components: {
 | 
				
			||||||
@@ -195,9 +285,35 @@ export default defineComponent({
 | 
				
			|||||||
            },
 | 
					            },
 | 
				
			||||||
            datas: [],
 | 
					            datas: [],
 | 
				
			||||||
            total: 0,
 | 
					            total: 0,
 | 
				
			||||||
 | 
					            showDumpInfo: false,
 | 
				
			||||||
 | 
					            dumpInfo: {
 | 
				
			||||||
 | 
					                id: 0,
 | 
				
			||||||
 | 
					                db: '',
 | 
				
			||||||
 | 
					                type: 3,
 | 
				
			||||||
 | 
					                tables: [],
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            // sql执行记录弹框
 | 
				
			||||||
 | 
					            sqlExecLogDialog: {
 | 
				
			||||||
 | 
					                title: '',
 | 
				
			||||||
 | 
					                visible: false,
 | 
				
			||||||
 | 
					                data: [],
 | 
				
			||||||
 | 
					                total: 0,
 | 
				
			||||||
 | 
					                query: {
 | 
				
			||||||
 | 
					                    dbId: 0,
 | 
				
			||||||
 | 
					                    db: '',
 | 
				
			||||||
 | 
					                    table: '',
 | 
				
			||||||
 | 
					                    type: null,
 | 
				
			||||||
 | 
					                    pageNum: 1,
 | 
				
			||||||
 | 
					                    pageSize: 12,
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            rollbackSqlDialog: {
 | 
				
			||||||
 | 
					                visible: false,
 | 
				
			||||||
 | 
					                sql: '',
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
            chooseTableName: '',
 | 
					            chooseTableName: '',
 | 
				
			||||||
            tableInfoDialog: {
 | 
					            tableInfoDialog: {
 | 
				
			||||||
 | 
					                loading: false,
 | 
				
			||||||
                visible: false,
 | 
					                visible: false,
 | 
				
			||||||
                infos: [],
 | 
					                infos: [],
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
@@ -284,14 +400,114 @@ export default defineComponent({
 | 
				
			|||||||
            } catch (err) {}
 | 
					            } catch (err) {}
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const onShowSqlExec = async (row: any) => {
 | 
				
			||||||
 | 
					            state.sqlExecLogDialog.title = `${row.name}[${row.host}:${row.port}]`;
 | 
				
			||||||
 | 
					            state.sqlExecLogDialog.query.dbId = row.id;
 | 
				
			||||||
 | 
					            searchSqlExecLog();
 | 
				
			||||||
 | 
					            state.sqlExecLogDialog.visible = true;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const onBeforeCloseSqlExecDialog = () => {
 | 
				
			||||||
 | 
					            state.sqlExecLogDialog.visible = false;
 | 
				
			||||||
 | 
					            state.sqlExecLogDialog.data = [];
 | 
				
			||||||
 | 
					            state.sqlExecLogDialog.total = 0;
 | 
				
			||||||
 | 
					            state.sqlExecLogDialog.query.dbId = 0;
 | 
				
			||||||
 | 
					            state.sqlExecLogDialog.query.pageNum = 1;
 | 
				
			||||||
 | 
					            state.sqlExecLogDialog.query.table = '';
 | 
				
			||||||
 | 
					            state.sqlExecLogDialog.query.db = '';
 | 
				
			||||||
 | 
					            state.sqlExecLogDialog.query.type = null;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const searchSqlExecLog = async () => {
 | 
				
			||||||
 | 
					            const res = await dbApi.getSqlExecs.request(state.sqlExecLogDialog.query);
 | 
				
			||||||
 | 
					            state.sqlExecLogDialog.data = res.list;
 | 
				
			||||||
 | 
					            state.sqlExecLogDialog.total = res.total;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const handleSqlExecPageChange = (curPage: number) => {
 | 
				
			||||||
 | 
					            state.sqlExecLogDialog.query.pageNum = curPage;
 | 
				
			||||||
 | 
					            searchSqlExecLog();
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * 选择导出数据库表
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        const handleDumpTableSelectionChange = (vals: any) => {
 | 
				
			||||||
 | 
					            state.dumpInfo.tables = vals.map((x: any) => x.tableName);
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * 数据库信息导出
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        const dump = (db: string) => {
 | 
				
			||||||
 | 
					            isTrue(state.dumpInfo.tables.length > 0, '请选择要导出的表');
 | 
				
			||||||
 | 
					            const a = document.createElement('a');
 | 
				
			||||||
 | 
					            a.setAttribute(
 | 
				
			||||||
 | 
					                'href',
 | 
				
			||||||
 | 
					                `${config.baseApiUrl}/dbs/${state.dbId}/dump?db=${db}&type=${state.dumpInfo.type}&tables=${state.dumpInfo.tables.join(
 | 
				
			||||||
 | 
					                    ','
 | 
				
			||||||
 | 
					                )}&token=${getSession('token')}`
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					            a.click();
 | 
				
			||||||
 | 
					            state.showDumpInfo = false;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const onShowRollbackSql = async (sqlExecLog: any) => {
 | 
				
			||||||
 | 
					            const columns = await dbApi.columnMetadata.request({ id: sqlExecLog.dbId, db: sqlExecLog.db, tableName: sqlExecLog.table });
 | 
				
			||||||
 | 
					            const primaryKey = columns[0].columnName;
 | 
				
			||||||
 | 
					            const oldValue = JSON.parse(sqlExecLog.oldValue);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            const rollbackSqls = [];
 | 
				
			||||||
 | 
					            if (sqlExecLog.type == enums.DbSqlExecTypeEnum['UPDATE'].value) {
 | 
				
			||||||
 | 
					                for (let ov of oldValue) {
 | 
				
			||||||
 | 
					                    const setItems = [];
 | 
				
			||||||
 | 
					                    for (let key in ov) {
 | 
				
			||||||
 | 
					                        if (key == primaryKey) {
 | 
				
			||||||
 | 
					                            continue;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        setItems.push(`${key} = ${wrapValue(ov[key])}`);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    rollbackSqls.push(`UPDATE ${sqlExecLog.table} SET ${setItems.join(', ')} WHERE ${primaryKey} = ${wrapValue(ov[primaryKey])};`);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            } else if (sqlExecLog.type == enums.DbSqlExecTypeEnum['DELETE'].value) {
 | 
				
			||||||
 | 
					                const columnNames = columns.map((c: any) => c.columnName);
 | 
				
			||||||
 | 
					                for (let ov of oldValue) {
 | 
				
			||||||
 | 
					                    const values = [];
 | 
				
			||||||
 | 
					                    for (let column of columnNames) {
 | 
				
			||||||
 | 
					                        values.push(wrapValue(ov[column]));
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    rollbackSqls.push(`INSERT INTO ${sqlExecLog.table} (${columnNames.join(', ')}) VALUES (${values.join(', ')});`);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            state.rollbackSqlDialog.sql = rollbackSqls.join('\n');
 | 
				
			||||||
 | 
					            state.rollbackSqlDialog.visible = true;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * 包装值,如果值类型为number则直接返回,其他则需要使用''包装
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        const wrapValue = (val: any) => {
 | 
				
			||||||
 | 
					            if (typeof val == 'number') {
 | 
				
			||||||
 | 
					                return val;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return `'${val}'`;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const showTableInfo = async (row: any, db: string) => {
 | 
					        const showTableInfo = async (row: any, db: string) => {
 | 
				
			||||||
            state.tableInfoDialog.infos = await dbApi.tableInfos.request({ id: row.id, db });
 | 
					            state.tableInfoDialog.loading = true;
 | 
				
			||||||
            state.dbId = row.id;
 | 
					 | 
				
			||||||
            state.db = db;
 | 
					 | 
				
			||||||
            state.tableInfoDialog.visible = true;
 | 
					            state.tableInfoDialog.visible = true;
 | 
				
			||||||
 | 
					            try {
 | 
				
			||||||
 | 
					                state.tableInfoDialog.infos = await dbApi.tableInfos.request({ id: row.id, db });
 | 
				
			||||||
 | 
					                state.dbId = row.id;
 | 
				
			||||||
 | 
					                state.db = db;
 | 
				
			||||||
 | 
					            } finally {
 | 
				
			||||||
 | 
					                state.tableInfoDialog.loading = false;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const closeTableInfo = () => {
 | 
					        const closeTableInfo = () => {
 | 
				
			||||||
 | 
					            state.showDumpInfo = false;
 | 
				
			||||||
            state.tableInfoDialog.visible = false;
 | 
					            state.tableInfoDialog.visible = false;
 | 
				
			||||||
            state.tableInfoDialog.infos = [];
 | 
					            state.tableInfoDialog.infos = [];
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
@@ -353,13 +569,20 @@ export default defineComponent({
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        return {
 | 
					        return {
 | 
				
			||||||
            ...toRefs(state),
 | 
					            ...toRefs(state),
 | 
				
			||||||
            // enums,
 | 
					            enums,
 | 
				
			||||||
            search,
 | 
					            search,
 | 
				
			||||||
            choose,
 | 
					            choose,
 | 
				
			||||||
            handlePageChange,
 | 
					            handlePageChange,
 | 
				
			||||||
            editDb,
 | 
					            editDb,
 | 
				
			||||||
            valChange,
 | 
					            valChange,
 | 
				
			||||||
            deleteDb,
 | 
					            deleteDb,
 | 
				
			||||||
 | 
					            onShowSqlExec,
 | 
				
			||||||
 | 
					            handleDumpTableSelectionChange,
 | 
				
			||||||
 | 
					            dump,
 | 
				
			||||||
 | 
					            onBeforeCloseSqlExecDialog,
 | 
				
			||||||
 | 
					            handleSqlExecPageChange,
 | 
				
			||||||
 | 
					            searchSqlExecLog,
 | 
				
			||||||
 | 
					            onShowRollbackSql,
 | 
				
			||||||
            showTableInfo,
 | 
					            showTableInfo,
 | 
				
			||||||
            closeTableInfo,
 | 
					            closeTableInfo,
 | 
				
			||||||
            showColumns,
 | 
					            showColumns,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,13 +10,7 @@
 | 
				
			|||||||
                    <project-env-select @changeProjectEnv="changeProjectEnv">
 | 
					                    <project-env-select @changeProjectEnv="changeProjectEnv">
 | 
				
			||||||
                        <template #default>
 | 
					                        <template #default>
 | 
				
			||||||
                            <el-form-item label="资源">
 | 
					                            <el-form-item label="资源">
 | 
				
			||||||
                                <el-select
 | 
					                                <el-select v-model="dbId" placeholder="请选择资源实例" @change="changeDbInstance" filterable style="width: 150px">
 | 
				
			||||||
                                    v-model="dbId"
 | 
					 | 
				
			||||||
                                    placeholder="请选择资源实例"
 | 
					 | 
				
			||||||
                                    @change="changeDbInstance"
 | 
					 | 
				
			||||||
                                    filterable
 | 
					 | 
				
			||||||
                                    style="width: 150px"
 | 
					 | 
				
			||||||
                                >
 | 
					 | 
				
			||||||
                                    <el-option v-for="item in dbs" :key="item.id" :label="item.name" :value="item.id">
 | 
					                                    <el-option v-for="item in dbs" :key="item.id" :label="item.name" :value="item.id">
 | 
				
			||||||
                                        <span style="float: left">{{ item.name }}</span>
 | 
					                                        <span style="float: left">{{ item.name }}</span>
 | 
				
			||||||
                                        <span style="float: right; color: #8492a6; margin-left: 6px; font-size: 13px">{{
 | 
					                                        <span style="float: right; color: #8492a6; margin-left: 6px; font-size: 13px">{{
 | 
				
			||||||
@@ -27,7 +21,15 @@
 | 
				
			|||||||
                            </el-form-item>
 | 
					                            </el-form-item>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            <el-form-item label="数据库">
 | 
					                            <el-form-item label="数据库">
 | 
				
			||||||
                                <el-select v-model="db" placeholder="请选择数据库" @change="changeDb" @clear="clearDb" clearable filterable style="width: 150px">
 | 
					                                <el-select
 | 
				
			||||||
 | 
					                                    v-model="db"
 | 
				
			||||||
 | 
					                                    placeholder="请选择数据库"
 | 
				
			||||||
 | 
					                                    @change="changeDb"
 | 
				
			||||||
 | 
					                                    @clear="clearDb"
 | 
				
			||||||
 | 
					                                    clearable
 | 
				
			||||||
 | 
					                                    filterable
 | 
				
			||||||
 | 
					                                    style="width: 150px"
 | 
				
			||||||
 | 
					                                >
 | 
				
			||||||
                                    <el-option v-for="item in databaseList" :key="item" :label="item" :value="item"> </el-option>
 | 
					                                    <el-option v-for="item in databaseList" :key="item" :label="item" :value="item"> </el-option>
 | 
				
			||||||
                                </el-select>
 | 
					                                </el-select>
 | 
				
			||||||
                            </el-form-item>
 | 
					                            </el-form-item>
 | 
				
			||||||
@@ -188,7 +190,7 @@
 | 
				
			|||||||
                        @cell-dblclick="cellClick"
 | 
					                        @cell-dblclick="cellClick"
 | 
				
			||||||
                        @sort-change="onTableSortChange"
 | 
					                        @sort-change="onTableSortChange"
 | 
				
			||||||
                        @selection-change="onDataSelectionChange"
 | 
					                        @selection-change="onDataSelectionChange"
 | 
				
			||||||
                        :data="dt.execRes.data"
 | 
					                        :data="dt.datas"
 | 
				
			||||||
                        size="small"
 | 
					                        size="small"
 | 
				
			||||||
                        :max-height="dataTabsTableHeight"
 | 
					                        :max-height="dataTabsTableHeight"
 | 
				
			||||||
                        v-loading="dt.loading"
 | 
					                        v-loading="dt.loading"
 | 
				
			||||||
@@ -198,12 +200,12 @@
 | 
				
			|||||||
                        border
 | 
					                        border
 | 
				
			||||||
                        class="mt5"
 | 
					                        class="mt5"
 | 
				
			||||||
                    >
 | 
					                    >
 | 
				
			||||||
                        <el-table-column v-if="dt.execRes.tableColumn.length > 0" type="selection" width="35" />
 | 
					                        <el-table-column v-if="dt.datas.length > 0" type="selection" width="35" />
 | 
				
			||||||
                        <el-table-column
 | 
					                        <el-table-column
 | 
				
			||||||
                            min-width="100"
 | 
					                            min-width="100"
 | 
				
			||||||
                            :width="flexColumnWidth(item, dt.execRes.data)"
 | 
					                            :width="flexColumnWidth(item, dt.datas)"
 | 
				
			||||||
                            align="center"
 | 
					                            align="center"
 | 
				
			||||||
                            v-for="item in dt.execRes.tableColumn"
 | 
					                            v-for="item in dt.columnNames"
 | 
				
			||||||
                            :key="item"
 | 
					                            :key="item"
 | 
				
			||||||
                            :prop="item"
 | 
					                            :prop="item"
 | 
				
			||||||
                            :label="item"
 | 
					                            :label="item"
 | 
				
			||||||
@@ -211,14 +213,23 @@
 | 
				
			|||||||
                            :sortable="nowTableName != '' ? 'custom' : false"
 | 
					                            :sortable="nowTableName != '' ? 'custom' : false"
 | 
				
			||||||
                        >
 | 
					                        >
 | 
				
			||||||
                            <template #header>
 | 
					                            <template #header>
 | 
				
			||||||
                                <el-tooltip raw-content effect="dark" placement="top">
 | 
					                                <el-tooltip raw-content placement="top" effect="customized">
 | 
				
			||||||
                                    <template #content> {{ getColumnTip(dt.name, item) }} </template>
 | 
					                                    <template #content> {{ getColumnTip(dt.name, item) }} </template>
 | 
				
			||||||
                                    <el-icon><question-filled /></el-icon>
 | 
					                                    {{ item }}
 | 
				
			||||||
                                </el-tooltip>
 | 
					                                </el-tooltip>
 | 
				
			||||||
                                {{ item }}
 | 
					 | 
				
			||||||
                            </template>
 | 
					                            </template>
 | 
				
			||||||
                        </el-table-column>
 | 
					                        </el-table-column>
 | 
				
			||||||
                    </el-table>
 | 
					                    </el-table>
 | 
				
			||||||
 | 
					                    <el-row type="flex" class="mt5" justify="center">
 | 
				
			||||||
 | 
					                        <el-pagination
 | 
				
			||||||
 | 
					                            small
 | 
				
			||||||
 | 
					                            :total="dt.count"
 | 
				
			||||||
 | 
					                            @current-change="handlePageChange(dt)"
 | 
				
			||||||
 | 
					                            layout="prev, pager, next, total, jumper"
 | 
				
			||||||
 | 
					                            v-model:current-page="dt.pageNum"
 | 
				
			||||||
 | 
					                            :page-size="defalutLimit"
 | 
				
			||||||
 | 
					                        ></el-pagination>
 | 
				
			||||||
 | 
					                    </el-row>
 | 
				
			||||||
                </el-tab-pane>
 | 
					                </el-tab-pane>
 | 
				
			||||||
            </el-tabs>
 | 
					            </el-tabs>
 | 
				
			||||||
        </el-container>
 | 
					        </el-container>
 | 
				
			||||||
@@ -237,7 +248,6 @@ import 'codemirror/theme/base16-light.css';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import 'codemirror/addon/selection/active-line';
 | 
					import 'codemirror/addon/selection/active-line';
 | 
				
			||||||
import _CodeMirror from 'codemirror';
 | 
					import _CodeMirror from 'codemirror';
 | 
				
			||||||
// import 'codemirror/mode/sql/sql.js';
 | 
					 | 
				
			||||||
import 'codemirror/addon/hint/show-hint.js';
 | 
					import 'codemirror/addon/hint/show-hint.js';
 | 
				
			||||||
import 'codemirror/addon/hint/sql-hint.js';
 | 
					import 'codemirror/addon/hint/sql-hint.js';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -262,7 +272,7 @@ export default defineComponent({
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        const state = reactive({
 | 
					        const state = reactive({
 | 
				
			||||||
            token: token,
 | 
					            token: token,
 | 
				
			||||||
            defalutLimit: 25, // 默认查询数量
 | 
					            defalutLimit: 20, // 默认查询数量
 | 
				
			||||||
            dbs: [], // 数据库实例列表
 | 
					            dbs: [], // 数据库实例列表
 | 
				
			||||||
            databaseList: [], // 数据库实例拥有的数据库列表,1数据库实例  -> 多数据库
 | 
					            databaseList: [], // 数据库实例拥有的数据库列表,1数据库实例  -> 多数据库
 | 
				
			||||||
            db: '', // 当前操作的数据库
 | 
					            db: '', // 当前操作的数据库
 | 
				
			||||||
@@ -270,7 +280,6 @@ export default defineComponent({
 | 
				
			|||||||
            dbId: null, // 当前选中操作的数据库实例
 | 
					            dbId: null, // 当前选中操作的数据库实例
 | 
				
			||||||
            tableName: '',
 | 
					            tableName: '',
 | 
				
			||||||
            tableMetadata: [],
 | 
					            tableMetadata: [],
 | 
				
			||||||
            columnMetadata: [],
 | 
					 | 
				
			||||||
            sqlName: '', // 当前sql模板名
 | 
					            sqlName: '', // 当前sql模板名
 | 
				
			||||||
            sqlNames: [], // 所有sql模板名
 | 
					            sqlNames: [], // 所有sql模板名
 | 
				
			||||||
            activeName: 'Query',
 | 
					            activeName: 'Query',
 | 
				
			||||||
@@ -355,7 +364,7 @@ export default defineComponent({
 | 
				
			|||||||
        const setHeight = () => {
 | 
					        const setHeight = () => {
 | 
				
			||||||
            // 默认300px
 | 
					            // 默认300px
 | 
				
			||||||
            codemirror.setSize('auto', `${window.innerHeight - 538}px`);
 | 
					            codemirror.setSize('auto', `${window.innerHeight - 538}px`);
 | 
				
			||||||
            state.dataTabsTableHeight = window.innerHeight - 258;
 | 
					            state.dataTabsTableHeight = window.innerHeight - 258 - 33;
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /**
 | 
					        /**
 | 
				
			||||||
@@ -388,7 +397,44 @@ export default defineComponent({
 | 
				
			|||||||
            let sql = getSql();
 | 
					            let sql = getSql();
 | 
				
			||||||
            isTrue(sql && sql.trim(), '请选中需要执行的sql');
 | 
					            isTrue(sql && sql.trim(), '请选中需要执行的sql');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            state.queryTab.loading = true;
 | 
					            // 去除字符串前的空格、换行等
 | 
				
			||||||
 | 
					            sql = sql.replace(/(^\s*)/g, '');
 | 
				
			||||||
 | 
					            let execRemark = '';
 | 
				
			||||||
 | 
					            let canRun = true;
 | 
				
			||||||
 | 
					            if (
 | 
				
			||||||
 | 
					                sql.startsWith('update') ||
 | 
				
			||||||
 | 
					                sql.startsWith('UPDATE') ||
 | 
				
			||||||
 | 
					                sql.startsWith('INSERT') ||
 | 
				
			||||||
 | 
					                sql.startsWith('insert') ||
 | 
				
			||||||
 | 
					                sql.startsWith('DELETE') ||
 | 
				
			||||||
 | 
					                sql.startsWith('delete')
 | 
				
			||||||
 | 
					            ) {
 | 
				
			||||||
 | 
					                const res: any = await ElMessageBox.prompt('请输入备注', 'Tip', {
 | 
				
			||||||
 | 
					                    confirmButtonText: '确定',
 | 
				
			||||||
 | 
					                    cancelButtonText: '取消',
 | 
				
			||||||
 | 
					                    inputPattern: /^[\s\S]*.*[^\s][\s\S]*$/,
 | 
				
			||||||
 | 
					                    inputErrorMessage: '请输入执行该sql的备注信息',
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					                execRemark = res.value;
 | 
				
			||||||
 | 
					                if (!execRemark) {
 | 
				
			||||||
 | 
					                    canRun = false;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (!canRun) {
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            try {
 | 
				
			||||||
 | 
					                state.queryTab.loading = true;
 | 
				
			||||||
 | 
					                const colAndData: any = await runSql(sql, execRemark);
 | 
				
			||||||
 | 
					                state.queryTab.execRes.data = colAndData.res;
 | 
				
			||||||
 | 
					                state.queryTab.execRes.tableColumn = colAndData.colNames;
 | 
				
			||||||
 | 
					                state.queryTab.loading = false;
 | 
				
			||||||
 | 
					            } catch (e: any) {
 | 
				
			||||||
 | 
					                state.queryTab.loading = false;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            closeExecBtns();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // 即只有以该字符串开头的sql才可修改表数据内容
 | 
					            // 即只有以该字符串开头的sql才可修改表数据内容
 | 
				
			||||||
            if (sql.startsWith('SELECT *') || sql.startsWith('select *') || sql.startsWith('SELECT\n  *')) {
 | 
					            if (sql.startsWith('SELECT *') || sql.startsWith('select *') || sql.startsWith('SELECT\n  *')) {
 | 
				
			||||||
                state.queryTab.selectionDatas = [];
 | 
					                state.queryTab.selectionDatas = [];
 | 
				
			||||||
@@ -405,16 +451,6 @@ export default defineComponent({
 | 
				
			|||||||
                state.queryTab.nowTableName = '';
 | 
					                state.queryTab.nowTableName = '';
 | 
				
			||||||
                state.nowTableName = '';
 | 
					                state.nowTableName = '';
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					 | 
				
			||||||
            try {
 | 
					 | 
				
			||||||
                const colAndData: any = await runSql(sql);
 | 
					 | 
				
			||||||
                state.queryTab.execRes.data = colAndData.res;
 | 
					 | 
				
			||||||
                state.queryTab.execRes.tableColumn = colAndData.colNames;
 | 
					 | 
				
			||||||
                state.queryTab.loading = false;
 | 
					 | 
				
			||||||
            } catch (e: any) {
 | 
					 | 
				
			||||||
                state.queryTab.loading = false;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            closeExecBtns();
 | 
					 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /**
 | 
					        /**
 | 
				
			||||||
@@ -422,11 +458,12 @@ export default defineComponent({
 | 
				
			|||||||
         *
 | 
					         *
 | 
				
			||||||
         * @param sql 执行的sql
 | 
					         * @param sql 执行的sql
 | 
				
			||||||
         */
 | 
					         */
 | 
				
			||||||
        const runSql = (sql: string) => {
 | 
					        const runSql = async (sql: string, remark: string = '') => {
 | 
				
			||||||
            return dbApi.sqlExec.request({
 | 
					            return await dbApi.sqlExec.request({
 | 
				
			||||||
                id: state.dbId,
 | 
					                id: state.dbId,
 | 
				
			||||||
                db: state.db,
 | 
					                db: state.db,
 | 
				
			||||||
                sql: sql.trim(),
 | 
					                sql: sql.trim(),
 | 
				
			||||||
 | 
					                remark,
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -477,7 +514,7 @@ export default defineComponent({
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        // 获取sql文件上传执行url
 | 
					        // 获取sql文件上传执行url
 | 
				
			||||||
        const getUploadSqlFileUrl = () => {
 | 
					        const getUploadSqlFileUrl = () => {
 | 
				
			||||||
            return `${config.baseApiUrl}/dbs/${state.dbId}/exec-sql-file`;
 | 
					            return `${config.baseApiUrl}/dbs/${state.dbId}/exec-sql-file?db=${state.db}`;
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const flexColumnWidth = (str: any, tableData: any, flag = 'equal') => {
 | 
					        const flexColumnWidth = (str: any, tableData: any, flag = 'equal') => {
 | 
				
			||||||
@@ -495,8 +532,9 @@ export default defineComponent({
 | 
				
			|||||||
            if (flag === 'equal') {
 | 
					            if (flag === 'equal') {
 | 
				
			||||||
                // 获取该列中第一个不为空的数据(内容)
 | 
					                // 获取该列中第一个不为空的数据(内容)
 | 
				
			||||||
                for (let i = 0; i < tableData.length; i++) {
 | 
					                for (let i = 0; i < tableData.length; i++) {
 | 
				
			||||||
                    if (tableData[i][str].length > 0) {
 | 
					                    // 转为字符串后比较
 | 
				
			||||||
                        columnContent = tableData[i][str];
 | 
					                    if ((tableData[i][str] + '').length > 0) {
 | 
				
			||||||
 | 
					                        columnContent = tableData[i][str] + '';
 | 
				
			||||||
                        break;
 | 
					                        break;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
@@ -513,31 +551,47 @@ export default defineComponent({
 | 
				
			|||||||
                        index = i;
 | 
					                        index = i;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                columnContent = tableData[index][str];
 | 
					                columnContent = tableData[index][str] + '';
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					            const contentWidth: number = getContentWidth(columnContent);
 | 
				
			||||||
 | 
					            // 获取列名称的长度 加上排序图标长度
 | 
				
			||||||
 | 
					            const columnWidth: number = getContentWidth(str) + 43;
 | 
				
			||||||
 | 
					            const flexWidth: number = contentWidth > columnWidth ? contentWidth : columnWidth;
 | 
				
			||||||
 | 
					            return flexWidth + 'px';
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * 获取内容所需要占用的宽度
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        const getContentWidth = (content: any): number => {
 | 
				
			||||||
            // 以下分配的单位长度可根据实际需求进行调整
 | 
					            // 以下分配的单位长度可根据实际需求进行调整
 | 
				
			||||||
            let flexWidth = 0;
 | 
					            let flexWidth = 0;
 | 
				
			||||||
            for (const char of columnContent) {
 | 
					            for (const char of content) {
 | 
				
			||||||
                if ((char >= 'A' && char <= 'Z') || (char >= 'a' && char <= 'z')) {
 | 
					                if (flexWidth > 500) {
 | 
				
			||||||
                    // 如果是英文字符,为字符分配8个单位宽度
 | 
					                    break;
 | 
				
			||||||
                    flexWidth += 8;
 | 
					                }
 | 
				
			||||||
                } else if (char >= '\u4e00' && char <= '\u9fa5') {
 | 
					                if ((char >= '0' && char <= '9') || (char >= 'a' && char <= 'z')) {
 | 
				
			||||||
                    // 如果是中文字符,为字符分配15个单位宽度
 | 
					                    // 如果是小写字母、数字字符,分配8个单位宽度
 | 
				
			||||||
 | 
					                    flexWidth += 8.5;
 | 
				
			||||||
 | 
					                    continue;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if (char >= 'A' && char <= 'Z') {
 | 
				
			||||||
 | 
					                    flexWidth += 9;
 | 
				
			||||||
 | 
					                    continue;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if (char >= '\u4e00' && char <= '\u9fa5') {
 | 
				
			||||||
 | 
					                    // 如果是中文字符,为字符分配16个单位宽度
 | 
				
			||||||
                    flexWidth += 16;
 | 
					                    flexWidth += 16;
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
                    // 其他种类字符,为字符分配10个单位宽度
 | 
					                    // 其他种类字符,为字符分配9个单位宽度
 | 
				
			||||||
                    flexWidth += 10;
 | 
					                    flexWidth += 8;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            if (flexWidth < 80) {
 | 
					 | 
				
			||||||
                // 设置最小宽度
 | 
					 | 
				
			||||||
                flexWidth = 80;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            if (flexWidth > 500) {
 | 
					            if (flexWidth > 500) {
 | 
				
			||||||
                // 设置最大宽度
 | 
					                // 设置最大宽度
 | 
				
			||||||
                flexWidth = 500;
 | 
					                flexWidth = 500;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            return flexWidth + 'px';
 | 
					            return flexWidth;
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const getColumnTip = (tableName: string, columnName: string) => {
 | 
					        const getColumnTip = (tableName: string, columnName: string) => {
 | 
				
			||||||
@@ -600,8 +654,6 @@ export default defineComponent({
 | 
				
			|||||||
            if (tableName == '') {
 | 
					            if (tableName == '') {
 | 
				
			||||||
                return;
 | 
					                return;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            state.columnMetadata = (await getColumns(tableName)) as any;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (!execSelectSql) {
 | 
					            if (!execSelectSql) {
 | 
				
			||||||
                return;
 | 
					                return;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@@ -618,40 +670,17 @@ export default defineComponent({
 | 
				
			|||||||
            tab = {
 | 
					            tab = {
 | 
				
			||||||
                label: tableName,
 | 
					                label: tableName,
 | 
				
			||||||
                name: tableName,
 | 
					                name: tableName,
 | 
				
			||||||
                execRes: {
 | 
					                datas: [],
 | 
				
			||||||
                    tableColumn: [],
 | 
					                columnNames: [],
 | 
				
			||||||
                    data: [],
 | 
					                pageNum: 1,
 | 
				
			||||||
                },
 | 
					                count: 0,
 | 
				
			||||||
                querySql: getDefaultSelectSql(tableName),
 | 
					 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					            tab.columnNames = await getColumnNames(tableName);
 | 
				
			||||||
            state.dataTabs[tableName] = tab;
 | 
					            state.dataTabs[tableName] = tab;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            state.dataTabs[tableName].execRes.tableColumn = [];
 | 
					 | 
				
			||||||
            state.dataTabs[tableName].execRes.data = [];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            onRefresh(tableName);
 | 
					            onRefresh(tableName);
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /**
 | 
					 | 
				
			||||||
         * 获取默认查询语句
 | 
					 | 
				
			||||||
         */
 | 
					 | 
				
			||||||
        const getDefaultSelectSql = (tableName: string, where: string = '', orderBy: string = '') => {
 | 
					 | 
				
			||||||
            return `SELECT * FROM \`${tableName}\` ${where ? 'WHERE ' + where : ''} ${orderBy ? orderBy : ''} LIMIT ${state.defalutLimit}`;
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        const selectByCondition = async (tableName: string, condition: string) => {
 | 
					 | 
				
			||||||
            notEmpty(condition, '条件不能为空');
 | 
					 | 
				
			||||||
            state.dataTabs[tableName].loading = true;
 | 
					 | 
				
			||||||
            try {
 | 
					 | 
				
			||||||
                const colAndData: any = await runSql(getDefaultSelectSql(tableName, condition));
 | 
					 | 
				
			||||||
                state.dataTabs[tableName].execRes.tableColumn = colAndData.colNames;
 | 
					 | 
				
			||||||
                state.dataTabs[tableName].execRes.data = colAndData.res;
 | 
					 | 
				
			||||||
                state.dataTabs[tableName].loading = false;
 | 
					 | 
				
			||||||
            } catch (err) {
 | 
					 | 
				
			||||||
                state.dataTabs[tableName].loading = false;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /**
 | 
					        /**
 | 
				
			||||||
         * 获取表的所有列信息
 | 
					         * 获取表的所有列信息
 | 
				
			||||||
         */
 | 
					         */
 | 
				
			||||||
@@ -675,6 +704,11 @@ export default defineComponent({
 | 
				
			|||||||
            return tableMap.get(tableName);
 | 
					            return tableMap.get(tableName);
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const getColumnNames = async (tableName: string) => {
 | 
				
			||||||
 | 
					            const columns = await getColumns(tableName);
 | 
				
			||||||
 | 
					            return columns.map((t: any) => t.columnName);
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /**
 | 
					        /**
 | 
				
			||||||
         * 条件查询,点击列信息后显示输入对应的值
 | 
					         * 条件查询,点击列信息后显示输入对应的值
 | 
				
			||||||
         */
 | 
					         */
 | 
				
			||||||
@@ -700,13 +734,70 @@ export default defineComponent({
 | 
				
			|||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const onRefresh = async (tableName: string) => {
 | 
					        const onRefresh = async (tableName: string) => {
 | 
				
			||||||
 | 
					            const dataTab = state.dataTabs[tableName];
 | 
				
			||||||
            // 查询条件置空
 | 
					            // 查询条件置空
 | 
				
			||||||
            state.dataTabs[tableName].condition = '';
 | 
					            dataTab.condition = '';
 | 
				
			||||||
            state.dataTabs[tableName].loading = true;
 | 
					            dataTab.pageNum = 1;
 | 
				
			||||||
            const colAndData: any = await runSql(state.dataTabs[tableName].querySql);
 | 
					            setDataTabDatas(dataTab);
 | 
				
			||||||
            state.dataTabs[tableName].execRes.tableColumn = colAndData.colNames;
 | 
					        };
 | 
				
			||||||
            state.dataTabs[tableName].execRes.data = colAndData.res;
 | 
					
 | 
				
			||||||
            state.dataTabs[tableName].loading = false;
 | 
					        /**
 | 
				
			||||||
 | 
					         * 数据tab修改页数
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        const handlePageChange = async (dataTab: any) => {
 | 
				
			||||||
 | 
					            setDataTabDatas(dataTab);
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * 根据条件查询数据
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        const selectByCondition = async (tableName: string, condition: string) => {
 | 
				
			||||||
 | 
					            notEmpty(condition, '条件不能为空');
 | 
				
			||||||
 | 
					            const dataTab = state.dataTabs[tableName];
 | 
				
			||||||
 | 
					            dataTab.pageNum = 1;
 | 
				
			||||||
 | 
					            setDataTabDatas(dataTab);
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * 设置data tab的表数据
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        const setDataTabDatas = async (dataTab: any) => {
 | 
				
			||||||
 | 
					            dataTab.loading = true;
 | 
				
			||||||
 | 
					            try {
 | 
				
			||||||
 | 
					                dataTab.count = await getTableCount(dataTab.name, dataTab.condition);
 | 
				
			||||||
 | 
					                if (dataTab.count > 0) {
 | 
				
			||||||
 | 
					                    const colAndData: any = await runSql(getDefaultSelectSql(dataTab.name, dataTab.condition, dataTab.orderBy, dataTab.pageNum));
 | 
				
			||||||
 | 
					                    dataTab.datas = colAndData.res;
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    dataTab.datas = [];
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            } finally {
 | 
				
			||||||
 | 
					                dataTab.loading = false;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * 获取表的统计数量
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        const getTableCount = async (tableName: string, condition: string = '') => {
 | 
				
			||||||
 | 
					            const countRes = await runSql(getDefaultCountSql(tableName, condition));
 | 
				
			||||||
 | 
					            return countRes.res[0].count;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * 获取默认查询语句
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        const getDefaultSelectSql = (tableName: string, where: string = '', orderBy: string = '', pageNum: number = 1) => {
 | 
				
			||||||
 | 
					            return `SELECT * FROM \`${tableName}\` ${where ? 'WHERE ' + where : ''} ${orderBy ? orderBy : ''} LIMIT ${
 | 
				
			||||||
 | 
					                (pageNum - 1) * state.defalutLimit
 | 
				
			||||||
 | 
					            }, ${state.defalutLimit}`;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * 获取默认查询统计语句
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        const getDefaultCountSql = (tableName: string, where: string = '') => {
 | 
				
			||||||
 | 
					            return `SELECT COUNT(*) count FROM \`${tableName}\` ${where ? 'WHERE ' + where : ''}`;
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /**
 | 
					        /**
 | 
				
			||||||
@@ -728,7 +819,8 @@ export default defineComponent({
 | 
				
			|||||||
            const tableName = state.activeName;
 | 
					            const tableName = state.activeName;
 | 
				
			||||||
            const sortType = sort.order == 'descending' ? 'DESC' : 'ASC';
 | 
					            const sortType = sort.order == 'descending' ? 'DESC' : 'ASC';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            state.dataTabs[state.activeName].querySql = getDefaultSelectSql(tableName, '', `ORDER BY \`${sort.prop}\` ${sortType}`);
 | 
					            const orderBy = `ORDER BY \`${sort.prop}\` ${sortType}`;
 | 
				
			||||||
 | 
					            state.dataTabs[state.activeName].orderBy = orderBy;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            onRefresh(tableName);
 | 
					            onRefresh(tableName);
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
@@ -819,7 +911,6 @@ export default defineComponent({
 | 
				
			|||||||
            state.tableName = '';
 | 
					            state.tableName = '';
 | 
				
			||||||
            state.nowTableName = '';
 | 
					            state.nowTableName = '';
 | 
				
			||||||
            state.tableMetadata = [];
 | 
					            state.tableMetadata = [];
 | 
				
			||||||
            state.columnMetadata = [];
 | 
					 | 
				
			||||||
            state.dataTabs = {};
 | 
					            state.dataTabs = {};
 | 
				
			||||||
            setCodermirrorValue('');
 | 
					            setCodermirrorValue('');
 | 
				
			||||||
            state.sqlNames = [];
 | 
					            state.sqlNames = [];
 | 
				
			||||||
@@ -854,10 +945,7 @@ export default defineComponent({
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            promptExeSql(sql, null, () => {
 | 
					            promptExeSql(sql, null, () => {
 | 
				
			||||||
                if (!queryTab) {
 | 
					                if (!queryTab) {
 | 
				
			||||||
                    state.dataTabs[state.activeName].execRes.data = state.dataTabs[state.activeName].execRes.data.filter(
 | 
					                    onRefresh(state.activeName);
 | 
				
			||||||
                        (d: any) => !(deleteDatas.findIndex((x: any) => x[primaryKeyColumnName] == d[primaryKeyColumnName]) != -1)
 | 
					 | 
				
			||||||
                    );
 | 
					 | 
				
			||||||
                    state.dataTabs[state.activeName].selectionDatas = [];
 | 
					 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
                    state.queryTab.execRes.data = state.queryTab.execRes.data.filter(
 | 
					                    state.queryTab.execRes.data = state.queryTab.execRes.data.filter(
 | 
				
			||||||
                        (d: any) => !(deleteDatas.findIndex((x: any) => x[primaryKeyColumnName] == d[primaryKeyColumnName]) != -1)
 | 
					                        (d: any) => !(deleteDatas.findIndex((x: any) => x[primaryKeyColumnName] == d[primaryKeyColumnName]) != -1)
 | 
				
			||||||
@@ -881,7 +969,8 @@ export default defineComponent({
 | 
				
			|||||||
            if (!state.nowTableName || !property) {
 | 
					            if (!state.nowTableName || !property) {
 | 
				
			||||||
                return;
 | 
					                return;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            let text = row[property];
 | 
					            // 转为字符串比较,可能存在数字等
 | 
				
			||||||
 | 
					            let text = (row[property] ? row[property] : '') + '';
 | 
				
			||||||
            let div = cell.children[0];
 | 
					            let div = cell.children[0];
 | 
				
			||||||
            if (div) {
 | 
					            if (div) {
 | 
				
			||||||
                let input = document.createElement('input');
 | 
					                let input = document.createElement('input');
 | 
				
			||||||
@@ -1033,6 +1122,7 @@ export default defineComponent({
 | 
				
			|||||||
            formatSql,
 | 
					            formatSql,
 | 
				
			||||||
            onBeforeChange,
 | 
					            onBeforeChange,
 | 
				
			||||||
            onRefresh,
 | 
					            onRefresh,
 | 
				
			||||||
 | 
					            handlePageChange,
 | 
				
			||||||
            selectByCondition,
 | 
					            selectByCondition,
 | 
				
			||||||
            onCommit,
 | 
					            onCommit,
 | 
				
			||||||
            addRow,
 | 
					            addRow,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,6 +5,7 @@ export const dbApi = {
 | 
				
			|||||||
    dbs: Api.create("/dbs", 'get'),
 | 
					    dbs: Api.create("/dbs", 'get'),
 | 
				
			||||||
    saveDb: Api.create("/dbs", 'post'),
 | 
					    saveDb: Api.create("/dbs", 'post'),
 | 
				
			||||||
    deleteDb: Api.create("/dbs/{id}", 'delete'),
 | 
					    deleteDb: Api.create("/dbs/{id}", 'delete'),
 | 
				
			||||||
 | 
					    dumpDb: Api.create("/dbs/{id}/dump", 'post'),
 | 
				
			||||||
    tableInfos: Api.create("/dbs/{id}/t-infos", 'get'),
 | 
					    tableInfos: Api.create("/dbs/{id}/t-infos", 'get'),
 | 
				
			||||||
    tableIndex: Api.create("/dbs/{id}/t-index", 'get'),
 | 
					    tableIndex: Api.create("/dbs/{id}/t-index", 'get'),
 | 
				
			||||||
    tableDdl: Api.create("/dbs/{id}/t-create-ddl", 'get'),
 | 
					    tableDdl: Api.create("/dbs/{id}/t-create-ddl", 'get'),
 | 
				
			||||||
@@ -12,7 +13,7 @@ export const dbApi = {
 | 
				
			|||||||
    columnMetadata: Api.create("/dbs/{id}/c-metadata", 'get'),
 | 
					    columnMetadata: Api.create("/dbs/{id}/c-metadata", 'get'),
 | 
				
			||||||
    // 获取表即列提示
 | 
					    // 获取表即列提示
 | 
				
			||||||
    hintTables: Api.create("/dbs/{id}/hint-tables", 'get'),
 | 
					    hintTables: Api.create("/dbs/{id}/hint-tables", 'get'),
 | 
				
			||||||
    sqlExec: Api.create("/dbs/{id}/exec-sql", 'get'),
 | 
					    sqlExec: Api.create("/dbs/{id}/exec-sql", 'post'),
 | 
				
			||||||
    // 保存sql
 | 
					    // 保存sql
 | 
				
			||||||
    saveSql: Api.create("/dbs/{id}/sql", 'post'),
 | 
					    saveSql: Api.create("/dbs/{id}/sql", 'post'),
 | 
				
			||||||
    // 获取保存的sql
 | 
					    // 获取保存的sql
 | 
				
			||||||
@@ -20,4 +21,6 @@ export const dbApi = {
 | 
				
			|||||||
    // 获取保存的sql names
 | 
					    // 获取保存的sql names
 | 
				
			||||||
    getSqlNames: Api.create("/dbs/{id}/sql-names", 'get'),
 | 
					    getSqlNames: Api.create("/dbs/{id}/sql-names", 'get'),
 | 
				
			||||||
    deleteDbSql: Api.create("/dbs/{id}/sql", 'delete'),
 | 
					    deleteDbSql: Api.create("/dbs/{id}/sql", 'delete'),
 | 
				
			||||||
 | 
					    // 获取数据库sql执行记录
 | 
				
			||||||
 | 
					    getSqlExecs: Api.create("/dbs/{id}/sql-execs", 'get'),
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -2,6 +2,7 @@
 | 
				
			|||||||
    <div>
 | 
					    <div>
 | 
				
			||||||
        <el-dialog title="待执行SQL" v-model="dialogVisible" :show-close="false" width="600px">
 | 
					        <el-dialog title="待执行SQL" v-model="dialogVisible" :show-close="false" width="600px">
 | 
				
			||||||
            <codemirror height="350px" class="codesql" ref="cmEditor" language="sql" v-model="sqlValue" :options="cmOptions" />
 | 
					            <codemirror height="350px" class="codesql" ref="cmEditor" language="sql" v-model="sqlValue" :options="cmOptions" />
 | 
				
			||||||
 | 
					            <el-input ref="remarkInputRef" v-model="remark" placeholder="请输入执行备注" class="mt5" />
 | 
				
			||||||
            <template #footer>
 | 
					            <template #footer>
 | 
				
			||||||
                <span class="dialog-footer">
 | 
					                <span class="dialog-footer">
 | 
				
			||||||
                    <el-button @click="cancel">取 消</el-button>
 | 
					                    <el-button @click="cancel">取 消</el-button>
 | 
				
			||||||
@@ -13,9 +14,9 @@
 | 
				
			|||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script lang="ts">
 | 
					<script lang="ts">
 | 
				
			||||||
import { toRefs, reactive, defineComponent } from 'vue';
 | 
					import { toRefs, ref, nextTick, reactive, defineComponent } from 'vue';
 | 
				
			||||||
import { dbApi } from '../api';
 | 
					import { dbApi } from '../api';
 | 
				
			||||||
import { ElDialog, ElButton } from 'element-plus';
 | 
					import { ElDialog, ElButton, ElInput, ElMessage, InputInstance } from 'element-plus';
 | 
				
			||||||
// import base style
 | 
					// import base style
 | 
				
			||||||
import 'codemirror/lib/codemirror.css';
 | 
					import 'codemirror/lib/codemirror.css';
 | 
				
			||||||
// 引入主题后还需要在 options 中指定主题才会生效
 | 
					// 引入主题后还需要在 options 中指定主题才会生效
 | 
				
			||||||
@@ -32,6 +33,7 @@ export default defineComponent({
 | 
				
			|||||||
        codemirror,
 | 
					        codemirror,
 | 
				
			||||||
        ElButton,
 | 
					        ElButton,
 | 
				
			||||||
        ElDialog,
 | 
					        ElDialog,
 | 
				
			||||||
 | 
					        ElInput,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    props: {
 | 
					    props: {
 | 
				
			||||||
        visible: {
 | 
					        visible: {
 | 
				
			||||||
@@ -48,11 +50,13 @@ export default defineComponent({
 | 
				
			|||||||
        },
 | 
					        },
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    setup(props: any) {
 | 
					    setup(props: any) {
 | 
				
			||||||
 | 
					        const remarkInputRef = ref<InputInstance>();
 | 
				
			||||||
        const state = reactive({
 | 
					        const state = reactive({
 | 
				
			||||||
            dialogVisible: false,
 | 
					            dialogVisible: false,
 | 
				
			||||||
            sqlValue: '',
 | 
					            sqlValue: '',
 | 
				
			||||||
            dbId: 0,
 | 
					            dbId: 0,
 | 
				
			||||||
            db: '',
 | 
					            db: '',
 | 
				
			||||||
 | 
					            remark: '',
 | 
				
			||||||
            btnLoading: false,
 | 
					            btnLoading: false,
 | 
				
			||||||
            cmOptions: {
 | 
					            cmOptions: {
 | 
				
			||||||
                tabSize: 4,
 | 
					                tabSize: 4,
 | 
				
			||||||
@@ -77,14 +81,26 @@ export default defineComponent({
 | 
				
			|||||||
         * 执行sql
 | 
					         * 执行sql
 | 
				
			||||||
         */
 | 
					         */
 | 
				
			||||||
        const runSql = async () => {
 | 
					        const runSql = async () => {
 | 
				
			||||||
 | 
					            if (!state.remark) {
 | 
				
			||||||
 | 
					                ElMessage.error('请输入执行的备注信息');
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            try {
 | 
					            try {
 | 
				
			||||||
                state.btnLoading = true;
 | 
					                state.btnLoading = true;
 | 
				
			||||||
                await dbApi.sqlExec.request({
 | 
					                const res = await dbApi.sqlExec.request({
 | 
				
			||||||
                    id: state.dbId,
 | 
					                    id: state.dbId,
 | 
				
			||||||
                    db: state.db,
 | 
					                    db: state.db,
 | 
				
			||||||
 | 
					                    remark: state.remark,
 | 
				
			||||||
                    sql: state.sqlValue.trim(),
 | 
					                    sql: state.sqlValue.trim(),
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
                runSuccess = true;
 | 
					                if (parseInt(res.res[0].影响条数) >= 1) {
 | 
				
			||||||
 | 
					                    ElMessage.success('执行成功');
 | 
				
			||||||
 | 
					                    runSuccess = true;
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    ElMessage.error('执行失败');
 | 
				
			||||||
 | 
					                    runSuccess = false;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
            } catch (e) {
 | 
					            } catch (e) {
 | 
				
			||||||
                runSuccess = false;
 | 
					                runSuccess = false;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@@ -104,6 +120,7 @@ export default defineComponent({
 | 
				
			|||||||
            setTimeout(() => {
 | 
					            setTimeout(() => {
 | 
				
			||||||
                state.dbId = 0;
 | 
					                state.dbId = 0;
 | 
				
			||||||
                state.sqlValue = '';
 | 
					                state.sqlValue = '';
 | 
				
			||||||
 | 
					                state.remark = '';
 | 
				
			||||||
                runSuccessCallback = null;
 | 
					                runSuccessCallback = null;
 | 
				
			||||||
                cancelCallback = null;
 | 
					                cancelCallback = null;
 | 
				
			||||||
                runSuccess = false;
 | 
					                runSuccess = false;
 | 
				
			||||||
@@ -117,10 +134,14 @@ export default defineComponent({
 | 
				
			|||||||
            state.dbId = props.dbId;
 | 
					            state.dbId = props.dbId;
 | 
				
			||||||
            state.db = props.db;
 | 
					            state.db = props.db;
 | 
				
			||||||
            state.dialogVisible = true;
 | 
					            state.dialogVisible = true;
 | 
				
			||||||
 | 
					            nextTick(() => {
 | 
				
			||||||
 | 
					                remarkInputRef.value?.focus();
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return {
 | 
					        return {
 | 
				
			||||||
            ...toRefs(state),
 | 
					            ...toRefs(state),
 | 
				
			||||||
 | 
					            remarkInputRef,
 | 
				
			||||||
            open,
 | 
					            open,
 | 
				
			||||||
            runSql,
 | 
					            runSql,
 | 
				
			||||||
            cancel,
 | 
					            cancel,
 | 
				
			||||||
@@ -133,7 +154,4 @@ export default defineComponent({
 | 
				
			|||||||
    font-size: 9pt;
 | 
					    font-size: 9pt;
 | 
				
			||||||
    font-weight: 600;
 | 
					    font-weight: 600;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
.footer {
 | 
					 | 
				
			||||||
    float: right;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
</style>
 | 
					</style>
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										11
									
								
								mayfly_go_web/src/views/ops/db/enums.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								mayfly_go_web/src/views/ops/db/enums.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					import { Enum } from '@/common/Enum'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 枚举类
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export default {
 | 
				
			||||||
 | 
					    // 数据库sql执行类型
 | 
				
			||||||
 | 
					    DbSqlExecTypeEnum: new Enum().add('UPDATE', 'UPDATE', 1)
 | 
				
			||||||
 | 
					        .add('DELETE', 'DELETE', 2)
 | 
				
			||||||
 | 
					        .add('INSERT', 'INSERT', 3),
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -89,15 +89,11 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                                <template #dropdown>
 | 
					                                <template #dropdown>
 | 
				
			||||||
                                    <el-dropdown-menu>
 | 
					                                    <el-dropdown-menu>
 | 
				
			||||||
                                        <el-dropdown-item v-if="data.type == '-' && data.size < 1 * 1024 * 1024">
 | 
					                                        <el-dropdown-item
 | 
				
			||||||
                                            <el-link
 | 
					                                            @click="getFileContent(tree.folder.id, data.path)"
 | 
				
			||||||
                                                @click.prevent="getFileContent(tree.folder.id, data.path)"
 | 
					                                            v-if="data.type == '-' && data.size < 1 * 1024 * 1024"
 | 
				
			||||||
                                                type="info"
 | 
					                                        >
 | 
				
			||||||
                                                icon="view"
 | 
					                                            <el-link type="info" icon="view" :underline="false">查看</el-link>
 | 
				
			||||||
                                                :underline="false"
 | 
					 | 
				
			||||||
                                            >
 | 
					 | 
				
			||||||
                                                查看
 | 
					 | 
				
			||||||
                                            </el-link>
 | 
					 | 
				
			||||||
                                        </el-dropdown-item>
 | 
					                                        </el-dropdown-item>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                                        <span v-auth="'machine:file:upload'">
 | 
					                                        <span v-auth="'machine:file:upload'">
 | 
				
			||||||
@@ -112,34 +108,20 @@
 | 
				
			|||||||
                                                    name="file"
 | 
					                                                    name="file"
 | 
				
			||||||
                                                    style="display: inline-block; margin-left: 2px"
 | 
					                                                    style="display: inline-block; margin-left: 2px"
 | 
				
			||||||
                                                >
 | 
					                                                >
 | 
				
			||||||
                                                    <el-link icon="upload" :underline="false"> 上传 </el-link>
 | 
					                                                    <el-link icon="upload" :underline="false">上传</el-link>
 | 
				
			||||||
                                                </el-upload>
 | 
					                                                </el-upload>
 | 
				
			||||||
                                            </el-dropdown-item>
 | 
					                                            </el-dropdown-item>
 | 
				
			||||||
                                        </span>
 | 
					                                        </span>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                                        <span v-auth="'machine:file:write'">
 | 
					                                        <span v-auth="'machine:file:write'">
 | 
				
			||||||
                                            <el-dropdown-item v-if="data.type == '-'">
 | 
					                                            <el-dropdown-item @click="downloadFile(node, data)" v-if="data.type == '-'">
 | 
				
			||||||
                                                <el-link
 | 
					                                                <el-link type="primary" icon="download" :underline="false" style="margin-left: 2px">下载</el-link>
 | 
				
			||||||
                                                    @click.prevent="downloadFile(node, data)"
 | 
					 | 
				
			||||||
                                                    type="primary"
 | 
					 | 
				
			||||||
                                                    icon="download"
 | 
					 | 
				
			||||||
                                                    :underline="false"
 | 
					 | 
				
			||||||
                                                    style="margin-left: 2px"
 | 
					 | 
				
			||||||
                                                    >下载</el-link
 | 
					 | 
				
			||||||
                                                >
 | 
					 | 
				
			||||||
                                            </el-dropdown-item>
 | 
					                                            </el-dropdown-item>
 | 
				
			||||||
                                        </span>
 | 
					                                        </span>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                                        <span v-auth="'machine:file:rm'">
 | 
					                                        <span v-auth="'machine:file:rm'">
 | 
				
			||||||
                                            <el-dropdown-item v-if="!dontOperate(data)">
 | 
					                                            <el-dropdown-item @click="deleteFile(node, data)" v-if="!dontOperate(data)">
 | 
				
			||||||
                                                <el-link
 | 
					                                                <el-link type="danger" icon="delete" :underline="false" style="margin-left: 2px">删除</el-link>
 | 
				
			||||||
                                                    @click.prevent="deleteFile(node, data)"
 | 
					 | 
				
			||||||
                                                    type="danger"
 | 
					 | 
				
			||||||
                                                    icon="delete"
 | 
					 | 
				
			||||||
                                                    :underline="false"
 | 
					 | 
				
			||||||
                                                    style="margin-left: 2px"
 | 
					 | 
				
			||||||
                                                    >删除
 | 
					 | 
				
			||||||
                                                </el-link>
 | 
					 | 
				
			||||||
                                            </el-dropdown-item>
 | 
					                                            </el-dropdown-item>
 | 
				
			||||||
                                        </span>
 | 
					                                        </span>
 | 
				
			||||||
                                    </el-dropdown-menu>
 | 
					                                    </el-dropdown-menu>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -171,11 +171,6 @@ export default defineComponent({
 | 
				
			|||||||
        const cancel = () => {
 | 
					        const cancel = () => {
 | 
				
			||||||
            emit('update:visible', false);
 | 
					            emit('update:visible', false);
 | 
				
			||||||
            emit('cancel');
 | 
					            emit('cancel');
 | 
				
			||||||
            setTimeout(() => {
 | 
					 | 
				
			||||||
                machineForm.value.resetFields();
 | 
					 | 
				
			||||||
                //  重置对象属性为null
 | 
					 | 
				
			||||||
                state.form = {} as any;
 | 
					 | 
				
			||||||
            }, 200);
 | 
					 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return {
 | 
					        return {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -57,11 +57,10 @@
 | 
				
			|||||||
                            v-model="scope.row.status"
 | 
					                            v-model="scope.row.status"
 | 
				
			||||||
                            :active-value="1"
 | 
					                            :active-value="1"
 | 
				
			||||||
                            :inactive-value="-1"
 | 
					                            :inactive-value="-1"
 | 
				
			||||||
                            active-color="#13ce66"
 | 
					 | 
				
			||||||
                            inactive-color="#ff4949"
 | 
					 | 
				
			||||||
                            inline-prompt
 | 
					                            inline-prompt
 | 
				
			||||||
                            active-text="启用"
 | 
					                            active-text="启用"
 | 
				
			||||||
                            inactive-text="停用"
 | 
					                            inactive-text="停用"
 | 
				
			||||||
 | 
					                            style="--el-switch-on-color: #13ce66; --el-switch-off-color: #ff4949"
 | 
				
			||||||
                            @change="changeStatus(scope.row)"
 | 
					                            @change="changeStatus(scope.row)"
 | 
				
			||||||
                        ></el-switch>
 | 
					                        ></el-switch>
 | 
				
			||||||
                    </template>
 | 
					                    </template>
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										455
									
								
								mayfly_go_web/src/views/ops/mongo/MongoDataOp.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										455
									
								
								mayfly_go_web/src/views/ops/mongo/MongoDataOp.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,455 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					    <div>
 | 
				
			||||||
 | 
					        <div class="toolbar">
 | 
				
			||||||
 | 
					            <el-row type="flex" justify="space-between">
 | 
				
			||||||
 | 
					                <el-col :span="24">
 | 
				
			||||||
 | 
					                    <project-env-select @changeProjectEnv="changeProjectEnv">
 | 
				
			||||||
 | 
					                        <template #default>
 | 
				
			||||||
 | 
					                            <el-form-item label="实例" label-width="40px">
 | 
				
			||||||
 | 
					                                <el-select v-model="mongoId" placeholder="请选择mongo" @change="changeMongo">
 | 
				
			||||||
 | 
					                                    <el-option v-for="item in mongoList" :key="item.id" :label="item.name" :value="item.id">
 | 
				
			||||||
 | 
					                                        <span style="float: left">{{ item.name }}</span>
 | 
				
			||||||
 | 
					                                        <span style="float: right; color: #8492a6; margin-left: 6px; font-size: 13px">{{ ` [${item.uri}]` }}</span>
 | 
				
			||||||
 | 
					                                    </el-option>
 | 
				
			||||||
 | 
					                                </el-select>
 | 
				
			||||||
 | 
					                            </el-form-item>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            <el-form-item label="库" label-width="20px">
 | 
				
			||||||
 | 
					                                <el-select v-model="database" placeholder="请选择库" @change="changeDatabase">
 | 
				
			||||||
 | 
					                                    <el-option v-for="item in databases" :key="item.Name" :label="item.Name" :value="item.Name">
 | 
				
			||||||
 | 
					                                        <span style="float: left">{{ item.Name }}</span>
 | 
				
			||||||
 | 
					                                        <span style="float: right; color: #8492a6; margin-left: 4px; font-size: 13px">{{
 | 
				
			||||||
 | 
					                                            ` [${formatByteSize(item.SizeOnDisk)}]`
 | 
				
			||||||
 | 
					                                        }}</span>
 | 
				
			||||||
 | 
					                                    </el-option>
 | 
				
			||||||
 | 
					                                </el-select>
 | 
				
			||||||
 | 
					                            </el-form-item>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            <el-form-item label="集合" label-width="40px">
 | 
				
			||||||
 | 
					                                <el-select v-model="collection" placeholder="请选择集合" @change="changeCollection">
 | 
				
			||||||
 | 
					                                    <el-option v-for="item in collections" :key="item" :label="item" :value="item">
 | 
				
			||||||
 | 
					                                        <!-- <span style="float: left">{{ item.uri }}</span>
 | 
				
			||||||
 | 
					                                            <span style="float: right; color: #8492a6; margin-left: 6px; font-size: 13px">{{
 | 
				
			||||||
 | 
					                                                ` [${item.name}]`
 | 
				
			||||||
 | 
					                                            }}</span> -->
 | 
				
			||||||
 | 
					                                    </el-option>
 | 
				
			||||||
 | 
					                                </el-select>
 | 
				
			||||||
 | 
					                            </el-form-item>
 | 
				
			||||||
 | 
					                        </template>
 | 
				
			||||||
 | 
					                    </project-env-select>
 | 
				
			||||||
 | 
					                </el-col>
 | 
				
			||||||
 | 
					            </el-row>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <el-container id="data-exec" style="border: 1px solid #eee; margin-top: 1px">
 | 
				
			||||||
 | 
					            <el-tabs @tab-remove="removeDataTab" @tab-click="onDataTabClick" style="width: 100%; margin-left: 5px" v-model="activeName">
 | 
				
			||||||
 | 
					                <el-tab-pane closable v-for="dt in dataTabs" :key="dt.name" :label="dt.name" :name="dt.name">
 | 
				
			||||||
 | 
					                    <el-row v-if="mongoId">
 | 
				
			||||||
 | 
					                        <el-link @click="findCommand(activeName)" icon="refresh" :underline="false" class="ml5"></el-link>
 | 
				
			||||||
 | 
					                        <el-link @click="showInsertDocDialog" class="ml5" type="primary" icon="plus" :underline="false"></el-link>
 | 
				
			||||||
 | 
					                    </el-row>
 | 
				
			||||||
 | 
					                    <el-row class="mt5 mb5">
 | 
				
			||||||
 | 
					                        <el-input
 | 
				
			||||||
 | 
					                            ref="findParamInputRef"
 | 
				
			||||||
 | 
					                            v-model="dt.findParamStr"
 | 
				
			||||||
 | 
					                            placeholder="点击输入相应查询条件"
 | 
				
			||||||
 | 
					                            @focus="showFindDialog(dt.name)"
 | 
				
			||||||
 | 
					                        >
 | 
				
			||||||
 | 
					                            <template #prepend>查询参数</template>
 | 
				
			||||||
 | 
					                        </el-input>
 | 
				
			||||||
 | 
					                    </el-row>
 | 
				
			||||||
 | 
					                    <el-row>
 | 
				
			||||||
 | 
					                        <el-col :span="6" v-for="item in dt.datas" :key="item">
 | 
				
			||||||
 | 
					                            <el-card :body-style="{ padding: '0px', position: 'relative' }">
 | 
				
			||||||
 | 
					                                <el-input type="textarea" v-model="item.value" :rows="12" />
 | 
				
			||||||
 | 
					                                <div style="padding: 3px; float: right" class="mr5 mongo-doc-btns">
 | 
				
			||||||
 | 
					                                    <div>
 | 
				
			||||||
 | 
					                                        <el-link @click="onJsonEditor(item)" :underline="false" type="success" icon="MagicStick"></el-link>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                        <el-divider direction="vertical" border-style="dashed" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                        <el-link
 | 
				
			||||||
 | 
					                                            @click="onSaveDoc(item.value)"
 | 
				
			||||||
 | 
					                                            :underline="false"
 | 
				
			||||||
 | 
					                                            type="warning"
 | 
				
			||||||
 | 
					                                            icon="DocumentChecked"
 | 
				
			||||||
 | 
					                                        ></el-link>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                        <el-divider direction="vertical" border-style="dashed" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                        <el-popconfirm @confirm="onDeleteDoc(item.value)" title="确定删除该文档?">
 | 
				
			||||||
 | 
					                                            <template #reference>
 | 
				
			||||||
 | 
					                                                <el-link :underline="false" type="danger" icon="DocumentDelete"></el-link>
 | 
				
			||||||
 | 
					                                            </template>
 | 
				
			||||||
 | 
					                                        </el-popconfirm>
 | 
				
			||||||
 | 
					                                    </div>
 | 
				
			||||||
 | 
					                                </div>
 | 
				
			||||||
 | 
					                            </el-card>
 | 
				
			||||||
 | 
					                        </el-col>
 | 
				
			||||||
 | 
					                    </el-row>
 | 
				
			||||||
 | 
					                </el-tab-pane>
 | 
				
			||||||
 | 
					            </el-tabs>
 | 
				
			||||||
 | 
					        </el-container>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <el-dialog width="600px" title="find参数" v-model="findDialog.visible">
 | 
				
			||||||
 | 
					            <el-form label-width="70px">
 | 
				
			||||||
 | 
					                <el-form-item label="filter">
 | 
				
			||||||
 | 
					                    <el-input v-model="findDialog.findParam.filter" type="textarea" :rows="6" clearable auto-complete="off"></el-input>
 | 
				
			||||||
 | 
					                </el-form-item>
 | 
				
			||||||
 | 
					                <el-form-item label="sort">
 | 
				
			||||||
 | 
					                    <el-input v-model="findDialog.findParam.sort" type="textarea" :rows="3" clearable auto-complete="off"></el-input>
 | 
				
			||||||
 | 
					                </el-form-item>
 | 
				
			||||||
 | 
					                <el-form-item label="limit">
 | 
				
			||||||
 | 
					                    <el-input v-model.number="findDialog.findParam.limit" type="number" auto-complete="off"></el-input>
 | 
				
			||||||
 | 
					                </el-form-item>
 | 
				
			||||||
 | 
					                <el-form-item label="skip">
 | 
				
			||||||
 | 
					                    <el-input v-model.number="findDialog.findParam.skip" type="number" auto-complete="off"></el-input>
 | 
				
			||||||
 | 
					                </el-form-item>
 | 
				
			||||||
 | 
					            </el-form>
 | 
				
			||||||
 | 
					            <template #footer>
 | 
				
			||||||
 | 
					                <div>
 | 
				
			||||||
 | 
					                    <el-button @click="findDialog.visible = false">取 消</el-button>
 | 
				
			||||||
 | 
					                    <el-button @click="confirmFindDialog" type="primary">确 定</el-button>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </template>
 | 
				
			||||||
 | 
					        </el-dialog>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <el-dialog width="800px" :title="`新增'${activeName}'集合文档`" v-model="insertDocDialog.visible" :close-on-click-modal="false">
 | 
				
			||||||
 | 
					            <json-edit currentMode="code" v-model="insertDocDialog.doc" />
 | 
				
			||||||
 | 
					            <template #footer>
 | 
				
			||||||
 | 
					                <div>
 | 
				
			||||||
 | 
					                    <el-button @click="insertDocDialog.visible = false">取 消</el-button>
 | 
				
			||||||
 | 
					                    <el-button @click="onInsertDoc" type="primary">确 定</el-button>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </template>
 | 
				
			||||||
 | 
					        </el-dialog>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <el-dialog width="800px" title="json编辑器" v-model="jsoneditorDialog.visible" @close="onCloseJsonEditDialog" :close-on-click-modal="false">
 | 
				
			||||||
 | 
					            <json-edit v-model="jsoneditorDialog.doc" />
 | 
				
			||||||
 | 
					        </el-dialog>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <div style="text-align: center; margin-top: 10px"></div>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script lang="ts">
 | 
				
			||||||
 | 
					import { mongoApi } from './api';
 | 
				
			||||||
 | 
					import { toRefs, ref, reactive, defineComponent } from 'vue';
 | 
				
			||||||
 | 
					import { ElMessage } from 'element-plus';
 | 
				
			||||||
 | 
					import ProjectEnvSelect from '../component/ProjectEnvSelect.vue';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { isTrue, notBlank, notNull } from '@/common/assert';
 | 
				
			||||||
 | 
					import { formatByteSize } from '@/common/utils/format';
 | 
				
			||||||
 | 
					import JsonEdit from '@/components/jsonedit/index.vue';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default defineComponent({
 | 
				
			||||||
 | 
					    name: 'MongoDataOp',
 | 
				
			||||||
 | 
					    components: {
 | 
				
			||||||
 | 
					        ProjectEnvSelect,
 | 
				
			||||||
 | 
					        JsonEdit,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    setup() {
 | 
				
			||||||
 | 
					        const findParamInputRef: any = ref(null);
 | 
				
			||||||
 | 
					        const state = reactive({
 | 
				
			||||||
 | 
					            loading: false,
 | 
				
			||||||
 | 
					            mongoList: [],
 | 
				
			||||||
 | 
					            query: {
 | 
				
			||||||
 | 
					                envId: 0,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            mongoId: null, // 当前选择操作的mongo
 | 
				
			||||||
 | 
					            database: '', // 当前选择操作的库
 | 
				
			||||||
 | 
					            collection: '', //当前选中的collection
 | 
				
			||||||
 | 
					            activeName: '', // 当前操作的tab
 | 
				
			||||||
 | 
					            databases: [],
 | 
				
			||||||
 | 
					            collections: [],
 | 
				
			||||||
 | 
					            dataTabs: {}, // 数据tabs
 | 
				
			||||||
 | 
					            findDialog: {
 | 
				
			||||||
 | 
					                visible: false,
 | 
				
			||||||
 | 
					                findParam: {
 | 
				
			||||||
 | 
					                    filter: '',
 | 
				
			||||||
 | 
					                    sort: '',
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            insertDocDialog: {
 | 
				
			||||||
 | 
					                visible: false,
 | 
				
			||||||
 | 
					                doc: '',
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            jsoneditorDialog: {
 | 
				
			||||||
 | 
					                visible: false,
 | 
				
			||||||
 | 
					                doc: '',
 | 
				
			||||||
 | 
					                item: {} as any,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const searchMongo = async () => {
 | 
				
			||||||
 | 
					            notNull(state.query.envId, '请先选择项目环境');
 | 
				
			||||||
 | 
					            const res = await mongoApi.mongoList.request(state.query);
 | 
				
			||||||
 | 
					            state.mongoList = res.list;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const changeProjectEnv = (projectId: any, envId: any) => {
 | 
				
			||||||
 | 
					            state.databases = [];
 | 
				
			||||||
 | 
					            state.collections = [];
 | 
				
			||||||
 | 
					            state.mongoId = null;
 | 
				
			||||||
 | 
					            state.collection = '';
 | 
				
			||||||
 | 
					            state.database = '';
 | 
				
			||||||
 | 
					            state.dataTabs = {};
 | 
				
			||||||
 | 
					            if (envId != null) {
 | 
				
			||||||
 | 
					                state.query.envId = envId;
 | 
				
			||||||
 | 
					                searchMongo();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const changeMongo = () => {
 | 
				
			||||||
 | 
					            state.databases = [];
 | 
				
			||||||
 | 
					            state.collections = [];
 | 
				
			||||||
 | 
					            state.dataTabs = {};
 | 
				
			||||||
 | 
					            getDatabases();
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const getDatabases = async () => {
 | 
				
			||||||
 | 
					            const res = await mongoApi.databases.request({ id: state.mongoId });
 | 
				
			||||||
 | 
					            state.databases = res.Databases;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const changeDatabase = () => {
 | 
				
			||||||
 | 
					            state.collections = [];
 | 
				
			||||||
 | 
					            state.collection = '';
 | 
				
			||||||
 | 
					            state.dataTabs = {};
 | 
				
			||||||
 | 
					            getCollections();
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const getCollections = async () => {
 | 
				
			||||||
 | 
					            state.collections = await mongoApi.collections.request({ id: state.mongoId, database: state.database });
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const changeCollection = () => {
 | 
				
			||||||
 | 
					            const collection = state.collection;
 | 
				
			||||||
 | 
					            let dataTab = state.dataTabs[collection];
 | 
				
			||||||
 | 
					            if (!dataTab) {
 | 
				
			||||||
 | 
					                // 默认查询参数
 | 
				
			||||||
 | 
					                const findParam = {
 | 
				
			||||||
 | 
					                        filter: '{}',
 | 
				
			||||||
 | 
					                        sort: '{"_id": -1}',
 | 
				
			||||||
 | 
					                        skip: 0,
 | 
				
			||||||
 | 
					                        limit: 12,
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    dataTab = {
 | 
				
			||||||
 | 
					                        name: collection,
 | 
				
			||||||
 | 
					                        datas: [],
 | 
				
			||||||
 | 
					                        findParamStr: JSON.stringify(findParam),
 | 
				
			||||||
 | 
					                        findParam,
 | 
				
			||||||
 | 
					                    };
 | 
				
			||||||
 | 
					                state.dataTabs[collection] = dataTab;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            state.activeName = collection;
 | 
				
			||||||
 | 
					            findCommand(collection);
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const showFindDialog = (collection: string) => {
 | 
				
			||||||
 | 
					            // 获取当前tab的索引位置,将其输入框失去焦点,防止输入以及重复获取焦点
 | 
				
			||||||
 | 
					            const dataTabNames = Object.keys(state.dataTabs);
 | 
				
			||||||
 | 
					            for (let i = 0; i < dataTabNames.length; i++) {
 | 
				
			||||||
 | 
					                if (collection == dataTabNames[i]) {
 | 
				
			||||||
 | 
					                    findParamInputRef.value[i].blur();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            state.findDialog.findParam = state.dataTabs[collection].findParam;
 | 
				
			||||||
 | 
					            state.findDialog.visible = true;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const confirmFindDialog = () => {
 | 
				
			||||||
 | 
					            state.dataTabs[state.activeName].findParam = state.findDialog.findParam;
 | 
				
			||||||
 | 
					            state.dataTabs[state.activeName].findParamStr = JSON.stringify(state.findDialog.findParam);
 | 
				
			||||||
 | 
					            state.findDialog.visible = false;
 | 
				
			||||||
 | 
					            findCommand(state.activeName);
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const findCommand = async (collection: string) => {
 | 
				
			||||||
 | 
					            const dataTab = state.dataTabs[collection];
 | 
				
			||||||
 | 
					            const findParma = dataTab.findParam;
 | 
				
			||||||
 | 
					            let filter, sort;
 | 
				
			||||||
 | 
					            try {
 | 
				
			||||||
 | 
					                filter = findParma.filter ? JSON.parse(findParma.filter) : {};
 | 
				
			||||||
 | 
					                sort = findParma.sort ? JSON.parse(findParma.sort) : {};
 | 
				
			||||||
 | 
					            } catch (e) {
 | 
				
			||||||
 | 
					                ElMessage.error('filter或sort字段json字符串值错误。注意: json key需双引号');
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            const datas = await mongoApi.findCommand.request({
 | 
				
			||||||
 | 
					                id: state.mongoId,
 | 
				
			||||||
 | 
					                database: state.database,
 | 
				
			||||||
 | 
					                collection,
 | 
				
			||||||
 | 
					                filter,
 | 
				
			||||||
 | 
					                sort,
 | 
				
			||||||
 | 
					                limit: findParma.limit || 12,
 | 
				
			||||||
 | 
					                skip: findParma.skip || 0,
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            state.dataTabs[collection].datas = wrapDatas(datas);
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * 包装mongo查询回来的对象,即将其都转为json字符串并用value属性值描述,方便显示
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        const wrapDatas = (datas: any) => {
 | 
				
			||||||
 | 
					            const wrapDatas = [] as any;
 | 
				
			||||||
 | 
					            if (!datas) {
 | 
				
			||||||
 | 
					                return wrapDatas;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            for (let data of datas) {
 | 
				
			||||||
 | 
					                wrapDatas.push({ value: JSON.stringify(data, null, 4) });
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return wrapDatas;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const showInsertDocDialog = () => {
 | 
				
			||||||
 | 
					            // tab数据中的第一个文档,因为该集合的文档都类似,故使用第一个文档赋值至需要新增的文档输入框,方便直接修改新增
 | 
				
			||||||
 | 
					            const datasFirstDoc = state.dataTabs[state.activeName].datas[0];
 | 
				
			||||||
 | 
					            let doc = '';
 | 
				
			||||||
 | 
					            if (datasFirstDoc) {
 | 
				
			||||||
 | 
					                // 移除_id字段,因为新增无需该字段
 | 
				
			||||||
 | 
					                const docObj = JSON.parse(datasFirstDoc.value);
 | 
				
			||||||
 | 
					                delete docObj['_id'];
 | 
				
			||||||
 | 
					                doc = JSON.stringify(docObj, null, 4);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            state.insertDocDialog.doc = doc;
 | 
				
			||||||
 | 
					            state.insertDocDialog.visible = true;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const onInsertDoc = async () => {
 | 
				
			||||||
 | 
					            let docObj;
 | 
				
			||||||
 | 
					            try {
 | 
				
			||||||
 | 
					                docObj = JSON.parse(state.insertDocDialog.doc);
 | 
				
			||||||
 | 
					            } catch (e) {
 | 
				
			||||||
 | 
					                ElMessage.error('文档内容错误,无法解析为json对象');
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            const res = await mongoApi.insertCommand.request({
 | 
				
			||||||
 | 
					                id: state.mongoId,
 | 
				
			||||||
 | 
					                database: state.database,
 | 
				
			||||||
 | 
					                collection: state.activeName,
 | 
				
			||||||
 | 
					                doc: docObj,
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            isTrue(res.InsertedID, '新增失败');
 | 
				
			||||||
 | 
					            ElMessage.success('新增成功');
 | 
				
			||||||
 | 
					            findCommand(state.activeName);
 | 
				
			||||||
 | 
					            state.insertDocDialog.visible = false;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const onJsonEditor = (item: any) => {
 | 
				
			||||||
 | 
					            state.jsoneditorDialog.item = item;
 | 
				
			||||||
 | 
					            state.jsoneditorDialog.doc = item.value;
 | 
				
			||||||
 | 
					            state.jsoneditorDialog.visible = true;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const onCloseJsonEditDialog = () => {
 | 
				
			||||||
 | 
					            state.jsoneditorDialog.item.value = JSON.stringify(JSON.parse(state.jsoneditorDialog.doc), null, 4);
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const onSaveDoc = async (doc: string) => {
 | 
				
			||||||
 | 
					            const docObj = parseDocJsonString(doc);
 | 
				
			||||||
 | 
					            const id = docObj._id;
 | 
				
			||||||
 | 
					            notBlank(id, '文档的_id属性不存在');
 | 
				
			||||||
 | 
					            delete docObj['_id'];
 | 
				
			||||||
 | 
					            const res = await mongoApi.updateByIdCommand.request({
 | 
				
			||||||
 | 
					                id: state.mongoId,
 | 
				
			||||||
 | 
					                database: state.database,
 | 
				
			||||||
 | 
					                collection: state.collection,
 | 
				
			||||||
 | 
					                docId: id,
 | 
				
			||||||
 | 
					                update: { $set: docObj },
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            isTrue(res.ModifiedCount == 1, '修改失败');
 | 
				
			||||||
 | 
					            ElMessage.success('保存成功');
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const onDeleteDoc = async (doc: string) => {
 | 
				
			||||||
 | 
					            const docObj = parseDocJsonString(doc);
 | 
				
			||||||
 | 
					            const id = docObj._id;
 | 
				
			||||||
 | 
					            notBlank(id, '文档的_id属性不存在');
 | 
				
			||||||
 | 
					            const res = await mongoApi.deleteByIdCommand.request({
 | 
				
			||||||
 | 
					                id: state.mongoId,
 | 
				
			||||||
 | 
					                database: state.database,
 | 
				
			||||||
 | 
					                collection: state.collection,
 | 
				
			||||||
 | 
					                docId: id,
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            isTrue(res.DeletedCount == 1, '删除失败');
 | 
				
			||||||
 | 
					            ElMessage.success('删除成功');
 | 
				
			||||||
 | 
					            findCommand(state.activeName);
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * 将json字符串解析为json对象
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        const parseDocJsonString = (doc: string) => {
 | 
				
			||||||
 | 
					            try {
 | 
				
			||||||
 | 
					                return JSON.parse(doc);
 | 
				
			||||||
 | 
					            } catch (e) {
 | 
				
			||||||
 | 
					                ElMessage.error('文档内容解析为json对象失败');
 | 
				
			||||||
 | 
					                throw e;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * 数据tab点击
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        const onDataTabClick = (tab: any) => {
 | 
				
			||||||
 | 
					            const name = tab.props.name;
 | 
				
			||||||
 | 
					            // 修改选择框绑定的表信息
 | 
				
			||||||
 | 
					            state.collection = name;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const removeDataTab = (targetName: string) => {
 | 
				
			||||||
 | 
					            const tabNames = Object.keys(state.dataTabs);
 | 
				
			||||||
 | 
					            let activeName = state.activeName;
 | 
				
			||||||
 | 
					            tabNames.forEach((name, index) => {
 | 
				
			||||||
 | 
					                if (name === targetName) {
 | 
				
			||||||
 | 
					                    const nextTab = tabNames[index + 1] || tabNames[index - 1];
 | 
				
			||||||
 | 
					                    if (nextTab) {
 | 
				
			||||||
 | 
					                        activeName = nextTab;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            state.activeName = activeName;
 | 
				
			||||||
 | 
					            // 如果移除最后一个数据tab,则将选择框绑定的collection置空
 | 
				
			||||||
 | 
					            if (activeName == targetName) {
 | 
				
			||||||
 | 
					                state.collection = '';
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                state.collection = activeName;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            delete state.dataTabs[targetName];
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return {
 | 
				
			||||||
 | 
					            ...toRefs(state),
 | 
				
			||||||
 | 
					            findParamInputRef,
 | 
				
			||||||
 | 
					            changeProjectEnv,
 | 
				
			||||||
 | 
					            changeMongo,
 | 
				
			||||||
 | 
					            changeDatabase,
 | 
				
			||||||
 | 
					            changeCollection,
 | 
				
			||||||
 | 
					            onDataTabClick,
 | 
				
			||||||
 | 
					            removeDataTab,
 | 
				
			||||||
 | 
					            showFindDialog,
 | 
				
			||||||
 | 
					            confirmFindDialog,
 | 
				
			||||||
 | 
					            findCommand,
 | 
				
			||||||
 | 
					            showInsertDocDialog,
 | 
				
			||||||
 | 
					            onInsertDoc,
 | 
				
			||||||
 | 
					            onSaveDoc,
 | 
				
			||||||
 | 
					            onDeleteDoc,
 | 
				
			||||||
 | 
					            onJsonEditor,
 | 
				
			||||||
 | 
					            onCloseJsonEditDialog,
 | 
				
			||||||
 | 
					            formatByteSize,
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style>
 | 
				
			||||||
 | 
					.mongo-doc-btns {
 | 
				
			||||||
 | 
					    position: absolute;
 | 
				
			||||||
 | 
					    z-index: 2;
 | 
				
			||||||
 | 
					    right: 3px;
 | 
				
			||||||
 | 
					    top: 2px;
 | 
				
			||||||
 | 
					    max-width: 120px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
							
								
								
									
										183
									
								
								mayfly_go_web/src/views/ops/mongo/MongoEdit.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										183
									
								
								mayfly_go_web/src/views/ops/mongo/MongoEdit.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,183 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					    <div>
 | 
				
			||||||
 | 
					        <el-dialog :title="title" v-model="dialogVisible" :before-close="cancel" :close-on-click-modal="false" width="35%" :destroy-on-close="true">
 | 
				
			||||||
 | 
					            <el-form :model="form" ref="mongoForm" :rules="rules" label-width="65px">
 | 
				
			||||||
 | 
					                <el-form-item prop="projectId" label="项目" required>
 | 
				
			||||||
 | 
					                    <el-select style="width: 100%" v-model="form.projectId" placeholder="请选择项目" @change="changeProject" filterable>
 | 
				
			||||||
 | 
					                        <el-option v-for="item in projects" :key="item.id" :label="`${item.name} [${item.remark}]`" :value="item.id"> </el-option>
 | 
				
			||||||
 | 
					                    </el-select>
 | 
				
			||||||
 | 
					                </el-form-item>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                <el-form-item prop="envId" label="环境" required>
 | 
				
			||||||
 | 
					                    <el-select @change="changeEnv" style="width: 100%" v-model="form.envId" placeholder="请选择环境">
 | 
				
			||||||
 | 
					                        <el-option v-for="item in envs" :key="item.id" :label="`${item.name} [${item.remark}]`" :value="item.id"> </el-option>
 | 
				
			||||||
 | 
					                    </el-select>
 | 
				
			||||||
 | 
					                </el-form-item>
 | 
				
			||||||
 | 
					                <el-form-item prop="name" label="名称" required>
 | 
				
			||||||
 | 
					                    <el-input v-model.trim="form.name" placeholder="请输入名称" auto-complete="off"></el-input>
 | 
				
			||||||
 | 
					                </el-form-item>
 | 
				
			||||||
 | 
					                <el-form-item prop="uri" label="uri" required>
 | 
				
			||||||
 | 
					                    <el-input
 | 
				
			||||||
 | 
					                        type="textarea"
 | 
				
			||||||
 | 
					                        :rows="2"
 | 
				
			||||||
 | 
					                        v-model.trim="form.uri"
 | 
				
			||||||
 | 
					                        placeholder="形如 mongodb://username:password@host1:port1"
 | 
				
			||||||
 | 
					                        auto-complete="off"
 | 
				
			||||||
 | 
					                    ></el-input>
 | 
				
			||||||
 | 
					                </el-form-item>
 | 
				
			||||||
 | 
					            </el-form>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <template #footer>
 | 
				
			||||||
 | 
					                <div class="dialog-footer">
 | 
				
			||||||
 | 
					                    <el-button @click="cancel()">取 消</el-button>
 | 
				
			||||||
 | 
					                    <el-button type="primary" :loading="btnLoading" @click="btnOk">确 定</el-button>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </template>
 | 
				
			||||||
 | 
					        </el-dialog>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script lang="ts">
 | 
				
			||||||
 | 
					import { toRefs, reactive, watch, defineComponent, ref } from 'vue';
 | 
				
			||||||
 | 
					import { mongoApi } from './api';
 | 
				
			||||||
 | 
					import { projectApi } from '../project/api.ts';
 | 
				
			||||||
 | 
					import { ElMessage } from 'element-plus';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default defineComponent({
 | 
				
			||||||
 | 
					    name: 'MongoEdit',
 | 
				
			||||||
 | 
					    props: {
 | 
				
			||||||
 | 
					        visible: {
 | 
				
			||||||
 | 
					            type: Boolean,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        projects: {
 | 
				
			||||||
 | 
					            type: Array,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        mongo: {
 | 
				
			||||||
 | 
					            type: [Boolean, Object],
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        title: {
 | 
				
			||||||
 | 
					            type: String,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    setup(props: any, { emit }) {
 | 
				
			||||||
 | 
					        const mongoForm: any = ref(null);
 | 
				
			||||||
 | 
					        const state = reactive({
 | 
				
			||||||
 | 
					            dialogVisible: false,
 | 
				
			||||||
 | 
					            projects: [],
 | 
				
			||||||
 | 
					            envs: [],
 | 
				
			||||||
 | 
					            form: {
 | 
				
			||||||
 | 
					                id: null,
 | 
				
			||||||
 | 
					                name: null,
 | 
				
			||||||
 | 
					                uri: null,
 | 
				
			||||||
 | 
					                project: null,
 | 
				
			||||||
 | 
					                projectId: null,
 | 
				
			||||||
 | 
					                envId: null,
 | 
				
			||||||
 | 
					                env: null,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            btnLoading: false,
 | 
				
			||||||
 | 
					            rules: {
 | 
				
			||||||
 | 
					                projectId: [
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        required: true,
 | 
				
			||||||
 | 
					                        message: '请选择项目',
 | 
				
			||||||
 | 
					                        trigger: ['change', 'blur'],
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                envId: [
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        required: true,
 | 
				
			||||||
 | 
					                        message: '请选择环境',
 | 
				
			||||||
 | 
					                        trigger: ['change', 'blur'],
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                name: [
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        required: true,
 | 
				
			||||||
 | 
					                        message: '请输入名称',
 | 
				
			||||||
 | 
					                        trigger: ['change', 'blur'],
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                uri: [
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        required: true,
 | 
				
			||||||
 | 
					                        message: '请输入mongo uri',
 | 
				
			||||||
 | 
					                        trigger: ['change', 'blur'],
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        watch(props, async (newValue) => {
 | 
				
			||||||
 | 
					            state.dialogVisible = newValue.visible;
 | 
				
			||||||
 | 
					            state.projects = newValue.projects;
 | 
				
			||||||
 | 
					            if (newValue.mongo) {
 | 
				
			||||||
 | 
					                getEnvs(newValue.mongo.projectId);
 | 
				
			||||||
 | 
					                state.form = { ...newValue.mongo };
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                state.envs = [];
 | 
				
			||||||
 | 
					                state.form = { db: 0 } as any;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const getEnvs = async (projectId: any) => {
 | 
				
			||||||
 | 
					            state.envs = await projectApi.projectEnvs.request({ projectId });
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const changeProject = (projectId: number) => {
 | 
				
			||||||
 | 
					            for (let p of state.projects as any) {
 | 
				
			||||||
 | 
					                if (p.id == projectId) {
 | 
				
			||||||
 | 
					                    state.form.project = p.name;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            state.form.envId = null;
 | 
				
			||||||
 | 
					            state.form.env = null;
 | 
				
			||||||
 | 
					            state.envs = [];
 | 
				
			||||||
 | 
					            getEnvs(projectId);
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const changeEnv = (envId: number) => {
 | 
				
			||||||
 | 
					            for (let p of state.envs as any) {
 | 
				
			||||||
 | 
					                if (p.id == envId) {
 | 
				
			||||||
 | 
					                    state.form.env = p.name;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const btnOk = async () => {
 | 
				
			||||||
 | 
					            mongoForm.value.validate((valid: boolean) => {
 | 
				
			||||||
 | 
					                if (valid) {
 | 
				
			||||||
 | 
					                    mongoApi.saveMongo.request(state.form).then(() => {
 | 
				
			||||||
 | 
					                        ElMessage.success('保存成功');
 | 
				
			||||||
 | 
					                        emit('val-change', state.form);
 | 
				
			||||||
 | 
					                        state.btnLoading = true;
 | 
				
			||||||
 | 
					                        setTimeout(() => {
 | 
				
			||||||
 | 
					                            state.btnLoading = false;
 | 
				
			||||||
 | 
					                        }, 1000);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        cancel();
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    ElMessage.error('请正确填写信息');
 | 
				
			||||||
 | 
					                    return false;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const cancel = () => {
 | 
				
			||||||
 | 
					            emit('update:visible', false);
 | 
				
			||||||
 | 
					            emit('cancel');
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return {
 | 
				
			||||||
 | 
					            ...toRefs(state),
 | 
				
			||||||
 | 
					            mongoForm,
 | 
				
			||||||
 | 
					            changeProject,
 | 
				
			||||||
 | 
					            changeEnv,
 | 
				
			||||||
 | 
					            btnOk,
 | 
				
			||||||
 | 
					            cancel,
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					<style lang="scss">
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
							
								
								
									
										427
									
								
								mayfly_go_web/src/views/ops/mongo/MongoList.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										427
									
								
								mayfly_go_web/src/views/ops/mongo/MongoList.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,427 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					    <div>
 | 
				
			||||||
 | 
					        <el-card>
 | 
				
			||||||
 | 
					            <el-button type="primary" icon="plus" @click="editMongo(true)" plain>添加</el-button>
 | 
				
			||||||
 | 
					            <el-button type="primary" icon="edit" :disabled="currentId == null" @click="editMongo(false)" plain>编辑</el-button>
 | 
				
			||||||
 | 
					            <el-button type="danger" icon="delete" :disabled="currentId == null" @click="deleteMongo" plain>删除</el-button>
 | 
				
			||||||
 | 
					            <div style="float: right">
 | 
				
			||||||
 | 
					                <el-select v-model="query.projectId" placeholder="请选择项目" filterable clearable>
 | 
				
			||||||
 | 
					                    <el-option v-for="item in projects" :key="item.id" :label="`${item.name} [${item.remark}]`" :value="item.id"> </el-option>
 | 
				
			||||||
 | 
					                </el-select>
 | 
				
			||||||
 | 
					                <el-button class="ml5" @click="search" type="success" icon="search"></el-button>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					            <el-table :data="list" style="width: 100%" @current-change="choose" stripe>
 | 
				
			||||||
 | 
					                <el-table-column label="选择" width="60px">
 | 
				
			||||||
 | 
					                    <template #default="scope">
 | 
				
			||||||
 | 
					                        <el-radio v-model="currentId" :label="scope.row.id">
 | 
				
			||||||
 | 
					                            <i></i>
 | 
				
			||||||
 | 
					                        </el-radio>
 | 
				
			||||||
 | 
					                    </template>
 | 
				
			||||||
 | 
					                </el-table-column>
 | 
				
			||||||
 | 
					                <el-table-column prop="project" label="项目" width></el-table-column>
 | 
				
			||||||
 | 
					                <el-table-column prop="env" label="环境" width></el-table-column>
 | 
				
			||||||
 | 
					                <el-table-column prop="name" label="名称" width></el-table-column>
 | 
				
			||||||
 | 
					                <el-table-column prop="uri" label="连接uri" min-width="150" show-overflow-tooltip>
 | 
				
			||||||
 | 
					                    <template #default="scope">
 | 
				
			||||||
 | 
					                        {{ scope.row.uri.split('@')[1] }}
 | 
				
			||||||
 | 
					                    </template>
 | 
				
			||||||
 | 
					                </el-table-column>
 | 
				
			||||||
 | 
					                <el-table-column prop="createTime" label="创建时间" min-width="150">
 | 
				
			||||||
 | 
					                    <template #default="scope">
 | 
				
			||||||
 | 
					                        {{ $filters.dateFormat(scope.row.createTime) }}
 | 
				
			||||||
 | 
					                    </template>
 | 
				
			||||||
 | 
					                </el-table-column>
 | 
				
			||||||
 | 
					                <el-table-column prop="creator" label="创建人"></el-table-column>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                <el-table-column label="操作" width>
 | 
				
			||||||
 | 
					                    <template #default="scope">
 | 
				
			||||||
 | 
					                        <el-link type="primary" @click="showDatabases(scope.row.id)" plain size="small" :underline="false">数据库</el-link>
 | 
				
			||||||
 | 
					                    </template>
 | 
				
			||||||
 | 
					                </el-table-column>
 | 
				
			||||||
 | 
					            </el-table>
 | 
				
			||||||
 | 
					            <el-row style="margin-top: 20px" type="flex" justify="end">
 | 
				
			||||||
 | 
					                <el-pagination
 | 
				
			||||||
 | 
					                    style="text-align: right"
 | 
				
			||||||
 | 
					                    @current-change="handlePageChange"
 | 
				
			||||||
 | 
					                    :total="total"
 | 
				
			||||||
 | 
					                    layout="prev, pager, next, total, jumper"
 | 
				
			||||||
 | 
					                    v-model:current-page="query.pageNum"
 | 
				
			||||||
 | 
					                    :page-size="query.pageSize"
 | 
				
			||||||
 | 
					                ></el-pagination>
 | 
				
			||||||
 | 
					            </el-row>
 | 
				
			||||||
 | 
					        </el-card>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <el-dialog width="800px" :title="databaseDialog.title" v-model="databaseDialog.visible">
 | 
				
			||||||
 | 
					            <el-table :data="databaseDialog.data" size="small">
 | 
				
			||||||
 | 
					                <el-table-column min-width="130" property="Name" label="库名" />
 | 
				
			||||||
 | 
					                <el-table-column min-width="90" property="SizeOnDisk" label="size">
 | 
				
			||||||
 | 
					                    <template #default="scope">
 | 
				
			||||||
 | 
					                        {{ formatByteSize(scope.row.SizeOnDisk) }}
 | 
				
			||||||
 | 
					                    </template>
 | 
				
			||||||
 | 
					                </el-table-column>
 | 
				
			||||||
 | 
					                <el-table-column min-width="80" property="Empty" label="是否为空" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                <el-table-column min-width="80" label="操作">
 | 
				
			||||||
 | 
					                    <template #default="scope">
 | 
				
			||||||
 | 
					                        <el-link type="success" @click="showDatabaseStats(scope.row.Name)" plain size="small" :underline="false">stats</el-link>
 | 
				
			||||||
 | 
					                        <el-divider direction="vertical" border-style="dashed" />
 | 
				
			||||||
 | 
					                        <el-link type="primary" @click="showCollections(scope.row.Name)" plain size="small" :underline="false">集合</el-link>
 | 
				
			||||||
 | 
					                    </template>
 | 
				
			||||||
 | 
					                </el-table-column>
 | 
				
			||||||
 | 
					            </el-table>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <el-dialog width="700px" :title="databaseDialog.statsDialog.title" v-model="databaseDialog.statsDialog.visible">
 | 
				
			||||||
 | 
					                <el-descriptions title="库状态信息" :column="3" border size="small">
 | 
				
			||||||
 | 
					                    <el-descriptions-item label="db" label-align="right" align="center">
 | 
				
			||||||
 | 
					                        {{ databaseDialog.statsDialog.data.db }}
 | 
				
			||||||
 | 
					                    </el-descriptions-item>
 | 
				
			||||||
 | 
					                    <el-descriptions-item label="collections" label-align="right" align="center">
 | 
				
			||||||
 | 
					                        {{ databaseDialog.statsDialog.data.collections }}
 | 
				
			||||||
 | 
					                    </el-descriptions-item>
 | 
				
			||||||
 | 
					                    <el-descriptions-item label="objects" label-align="right" align="center">
 | 
				
			||||||
 | 
					                        {{ databaseDialog.statsDialog.data.objects }}
 | 
				
			||||||
 | 
					                    </el-descriptions-item>
 | 
				
			||||||
 | 
					                    <el-descriptions-item label="indexes" label-align="right" align="center">
 | 
				
			||||||
 | 
					                        {{ databaseDialog.statsDialog.data.indexes }}
 | 
				
			||||||
 | 
					                    </el-descriptions-item>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    <el-descriptions-item label="avgObjSize" label-align="right" align="center">
 | 
				
			||||||
 | 
					                        {{ formatByteSize(databaseDialog.statsDialog.data.avgObjSize) }}
 | 
				
			||||||
 | 
					                    </el-descriptions-item>
 | 
				
			||||||
 | 
					                    <el-descriptions-item label="dataSize" label-align="right" align="center">
 | 
				
			||||||
 | 
					                        {{ formatByteSize(databaseDialog.statsDialog.data.dataSize) }}
 | 
				
			||||||
 | 
					                    </el-descriptions-item>
 | 
				
			||||||
 | 
					                    <el-descriptions-item label="totalSize" label-align="right" align="center">
 | 
				
			||||||
 | 
					                        {{ formatByteSize(databaseDialog.statsDialog.data.totalSize) }}
 | 
				
			||||||
 | 
					                    </el-descriptions-item>
 | 
				
			||||||
 | 
					                    <el-descriptions-item label="storageSize" label-align="right" align="center">
 | 
				
			||||||
 | 
					                        {{ formatByteSize(databaseDialog.statsDialog.data.storageSize) }}
 | 
				
			||||||
 | 
					                    </el-descriptions-item>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    <el-descriptions-item label="fsTotalSize" label-align="right" align="center">
 | 
				
			||||||
 | 
					                        {{ formatByteSize(databaseDialog.statsDialog.data.fsTotalSize) }}
 | 
				
			||||||
 | 
					                    </el-descriptions-item>
 | 
				
			||||||
 | 
					                    <el-descriptions-item label="fsUsedSize" label-align="right" align="center">
 | 
				
			||||||
 | 
					                        {{ formatByteSize(databaseDialog.statsDialog.data.fsUsedSize) }}
 | 
				
			||||||
 | 
					                    </el-descriptions-item>
 | 
				
			||||||
 | 
					                    <el-descriptions-item label="indexSize" label-align="right" align="center">
 | 
				
			||||||
 | 
					                        {{ formatByteSize(databaseDialog.statsDialog.data.indexSize) }}
 | 
				
			||||||
 | 
					                    </el-descriptions-item>
 | 
				
			||||||
 | 
					                </el-descriptions>
 | 
				
			||||||
 | 
					            </el-dialog>
 | 
				
			||||||
 | 
					        </el-dialog>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <el-dialog width="600px" :title="collectionsDialog.title" v-model="collectionsDialog.visible">
 | 
				
			||||||
 | 
					            <div>
 | 
				
			||||||
 | 
					                <el-button @click="showCreateCollectionDialog" type="primary" icon="plus" size="small">新建</el-button>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					            <el-table border stripe :data="collectionsDialog.data" size="small">
 | 
				
			||||||
 | 
					                <el-table-column prop="name" label="名称" show-overflow-tooltip> </el-table-column>
 | 
				
			||||||
 | 
					                <el-table-column min-width="80" label="操作">
 | 
				
			||||||
 | 
					                    <template #default="scope">
 | 
				
			||||||
 | 
					                        <el-link type="success" @click="showCollectionStats(scope.row.name)" plain size="small" :underline="false">stats</el-link>
 | 
				
			||||||
 | 
					                        <el-divider direction="vertical" border-style="dashed" />
 | 
				
			||||||
 | 
					                        <el-popconfirm @confirm="onDeleteCollection(scope.row.name)" title="确定删除该集合?">
 | 
				
			||||||
 | 
					                            <template #reference>
 | 
				
			||||||
 | 
					                                <el-link type="danger" plain size="small" :underline="false">删除</el-link>
 | 
				
			||||||
 | 
					                            </template>
 | 
				
			||||||
 | 
					                        </el-popconfirm>
 | 
				
			||||||
 | 
					                    </template>
 | 
				
			||||||
 | 
					                </el-table-column>
 | 
				
			||||||
 | 
					            </el-table>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <el-dialog width="700px" :title="collectionsDialog.statsDialog.title" v-model="collectionsDialog.statsDialog.visible">
 | 
				
			||||||
 | 
					                <el-descriptions title="集合状态信息" :column="3" border size="small">
 | 
				
			||||||
 | 
					                    <el-descriptions-item label="ns" label-align="right" :span="2" align="center">
 | 
				
			||||||
 | 
					                        {{ collectionsDialog.statsDialog.data.ns }}
 | 
				
			||||||
 | 
					                    </el-descriptions-item>
 | 
				
			||||||
 | 
					                    <el-descriptions-item label="count" label-align="right" align="center">
 | 
				
			||||||
 | 
					                        {{ collectionsDialog.statsDialog.data.count }}
 | 
				
			||||||
 | 
					                    </el-descriptions-item>
 | 
				
			||||||
 | 
					                    <el-descriptions-item label="avgObjSize" label-align="right" align="center">
 | 
				
			||||||
 | 
					                        {{ formatByteSize(collectionsDialog.statsDialog.data.avgObjSize) }}
 | 
				
			||||||
 | 
					                    </el-descriptions-item>
 | 
				
			||||||
 | 
					                    <el-descriptions-item label="nindexes" label-align="right" align="center">
 | 
				
			||||||
 | 
					                        {{ collectionsDialog.statsDialog.data.nindexes }}
 | 
				
			||||||
 | 
					                    </el-descriptions-item>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    <el-descriptions-item label="size" label-align="right" align="center">
 | 
				
			||||||
 | 
					                        {{ formatByteSize(collectionsDialog.statsDialog.data.size) }}
 | 
				
			||||||
 | 
					                    </el-descriptions-item>
 | 
				
			||||||
 | 
					                    <el-descriptions-item label="totalSize" label-align="right" align="center">
 | 
				
			||||||
 | 
					                        {{ formatByteSize(collectionsDialog.statsDialog.data.totalSize) }}
 | 
				
			||||||
 | 
					                    </el-descriptions-item>
 | 
				
			||||||
 | 
					                    <el-descriptions-item label="storageSize" label-align="right" align="center">
 | 
				
			||||||
 | 
					                        {{ formatByteSize(collectionsDialog.statsDialog.data.storageSize) }}
 | 
				
			||||||
 | 
					                    </el-descriptions-item>
 | 
				
			||||||
 | 
					                    <el-descriptions-item label="freeStorageSize" label-align="right" align="center">
 | 
				
			||||||
 | 
					                        {{ formatByteSize(collectionsDialog.statsDialog.data.freeStorageSize) }}
 | 
				
			||||||
 | 
					                    </el-descriptions-item>
 | 
				
			||||||
 | 
					                </el-descriptions>
 | 
				
			||||||
 | 
					            </el-dialog>
 | 
				
			||||||
 | 
					        </el-dialog>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <el-dialog width="400px" title="新建集合" v-model="createCollectionDialog.visible" :destroy-on-close="true">
 | 
				
			||||||
 | 
					            <el-form :model="createCollectionDialog.form" label-width="70px">
 | 
				
			||||||
 | 
					                <el-form-item prop="name" label="集合名" required>
 | 
				
			||||||
 | 
					                    <el-input v-model="createCollectionDialog.form.name" clearable></el-input>
 | 
				
			||||||
 | 
					                </el-form-item>
 | 
				
			||||||
 | 
					                <!-- <el-form-item label="描述:">
 | 
				
			||||||
 | 
					                    <el-input v-model="showEnvDialog.envForm.remark" auto-complete="off"></el-input>
 | 
				
			||||||
 | 
					                </el-form-item> -->
 | 
				
			||||||
 | 
					            </el-form>
 | 
				
			||||||
 | 
					            <template #footer>
 | 
				
			||||||
 | 
					                <div>
 | 
				
			||||||
 | 
					                    <el-button @click="createCollectionDialog.visible = false">取 消</el-button>
 | 
				
			||||||
 | 
					                    <el-button @click="onCreateCollection" type="primary">确 定</el-button>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </template>
 | 
				
			||||||
 | 
					        </el-dialog>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <mongo-edit
 | 
				
			||||||
 | 
					            @val-change="valChange"
 | 
				
			||||||
 | 
					            :projects="projects"
 | 
				
			||||||
 | 
					            :title="mongoEditDialog.title"
 | 
				
			||||||
 | 
					            v-model:visible="mongoEditDialog.visible"
 | 
				
			||||||
 | 
					            v-model:mongo="mongoEditDialog.data"
 | 
				
			||||||
 | 
					        ></mongo-edit>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script lang="ts">
 | 
				
			||||||
 | 
					import { mongoApi } from './api';
 | 
				
			||||||
 | 
					import { toRefs, reactive, defineComponent, onMounted } from 'vue';
 | 
				
			||||||
 | 
					import { ElMessage, ElMessageBox } from 'element-plus';
 | 
				
			||||||
 | 
					import { projectApi } from '../project/api.ts';
 | 
				
			||||||
 | 
					import MongoEdit from './MongoEdit.vue';
 | 
				
			||||||
 | 
					import { formatByteSize } from '@/common/utils/format';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default defineComponent({
 | 
				
			||||||
 | 
					    name: 'MongoList',
 | 
				
			||||||
 | 
					    components: {
 | 
				
			||||||
 | 
					        MongoEdit,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    setup() {
 | 
				
			||||||
 | 
					        const state = reactive({
 | 
				
			||||||
 | 
					            projects: [],
 | 
				
			||||||
 | 
					            list: [],
 | 
				
			||||||
 | 
					            total: 0,
 | 
				
			||||||
 | 
					            currentId: null,
 | 
				
			||||||
 | 
					            currentData: null,
 | 
				
			||||||
 | 
					            query: {
 | 
				
			||||||
 | 
					                pageNum: 1,
 | 
				
			||||||
 | 
					                pageSize: 10,
 | 
				
			||||||
 | 
					                prjectId: null,
 | 
				
			||||||
 | 
					                clusterId: null,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            mongoEditDialog: {
 | 
				
			||||||
 | 
					                visible: false,
 | 
				
			||||||
 | 
					                data: null,
 | 
				
			||||||
 | 
					                title: '新增mongo',
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            databaseDialog: {
 | 
				
			||||||
 | 
					                visible: false,
 | 
				
			||||||
 | 
					                data: [],
 | 
				
			||||||
 | 
					                title: '',
 | 
				
			||||||
 | 
					                statsDialog: {
 | 
				
			||||||
 | 
					                    visible: false,
 | 
				
			||||||
 | 
					                    data: {},
 | 
				
			||||||
 | 
					                    title: '',
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            collectionsDialog: {
 | 
				
			||||||
 | 
					                database: '',
 | 
				
			||||||
 | 
					                visible: false,
 | 
				
			||||||
 | 
					                data: [],
 | 
				
			||||||
 | 
					                title: '',
 | 
				
			||||||
 | 
					                statsDialog: {
 | 
				
			||||||
 | 
					                    visible: false,
 | 
				
			||||||
 | 
					                    data: {},
 | 
				
			||||||
 | 
					                    title: '',
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            createCollectionDialog: {
 | 
				
			||||||
 | 
					                visible: false,
 | 
				
			||||||
 | 
					                form: {
 | 
				
			||||||
 | 
					                    name: '',
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        onMounted(async () => {
 | 
				
			||||||
 | 
					            search();
 | 
				
			||||||
 | 
					            state.projects = (await projectApi.projects.request({ pageNum: 1, pageSize: 100 })).list;
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const handlePageChange = (curPage: number) => {
 | 
				
			||||||
 | 
					            state.query.pageNum = curPage;
 | 
				
			||||||
 | 
					            search();
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const choose = (item: any) => {
 | 
				
			||||||
 | 
					            if (!item) {
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            state.currentId = item.id;
 | 
				
			||||||
 | 
					            state.currentData = item;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // connect() {
 | 
				
			||||||
 | 
					        //   Req.post('/open/redis/connect', this.form, res => {
 | 
				
			||||||
 | 
					        //     this.redisInfo = res
 | 
				
			||||||
 | 
					        //   })
 | 
				
			||||||
 | 
					        // }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const showDatabases = async (id: number) => {
 | 
				
			||||||
 | 
					            state.databaseDialog.data = (await mongoApi.databases.request({ id })).Databases;
 | 
				
			||||||
 | 
					            state.databaseDialog.title = `数据库列表`;
 | 
				
			||||||
 | 
					            state.databaseDialog.visible = true;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const showDatabaseStats = async (dbName: string) => {
 | 
				
			||||||
 | 
					            state.databaseDialog.statsDialog.data = await mongoApi.runCommand.request({
 | 
				
			||||||
 | 
					                id: state.currentId,
 | 
				
			||||||
 | 
					                database: dbName,
 | 
				
			||||||
 | 
					                command: {
 | 
				
			||||||
 | 
					                    dbStats: 1,
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            state.databaseDialog.statsDialog.title = `'${dbName}' stats`;
 | 
				
			||||||
 | 
					            state.databaseDialog.statsDialog.visible = true;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const showCollections = async (database: string) => {
 | 
				
			||||||
 | 
					            state.collectionsDialog.database = database;
 | 
				
			||||||
 | 
					            state.collectionsDialog.data = [];
 | 
				
			||||||
 | 
					            setCollections(database);
 | 
				
			||||||
 | 
					            state.collectionsDialog.title = `'${database}' 集合`;
 | 
				
			||||||
 | 
					            state.collectionsDialog.visible = true;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const setCollections = async (database: string) => {
 | 
				
			||||||
 | 
					            const res = await mongoApi.collections.request({ id: state.currentId, database });
 | 
				
			||||||
 | 
					            const collections = [] as any;
 | 
				
			||||||
 | 
					            for (let r of res) {
 | 
				
			||||||
 | 
					                collections.push({ name: r });
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            state.collectionsDialog.data = collections;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * 显示集合状态
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        const showCollectionStats = async (collection: string) => {
 | 
				
			||||||
 | 
					            state.collectionsDialog.statsDialog.data = await mongoApi.runCommand.request({
 | 
				
			||||||
 | 
					                id: state.currentId,
 | 
				
			||||||
 | 
					                database: state.collectionsDialog.database,
 | 
				
			||||||
 | 
					                command: {
 | 
				
			||||||
 | 
					                    collStats: collection,
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            state.collectionsDialog.statsDialog.title = `'${collection}' stats`;
 | 
				
			||||||
 | 
					            state.collectionsDialog.statsDialog.visible = true;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * 删除集合
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        const onDeleteCollection = async (collection: string) => {
 | 
				
			||||||
 | 
					            await mongoApi.runCommand.request({
 | 
				
			||||||
 | 
					                id: state.currentId,
 | 
				
			||||||
 | 
					                database: state.collectionsDialog.database,
 | 
				
			||||||
 | 
					                command: {
 | 
				
			||||||
 | 
					                    drop: collection,
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            ElMessage.success('集合删除成功');
 | 
				
			||||||
 | 
					            setCollections(state.collectionsDialog.database);
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const showCreateCollectionDialog = () => {
 | 
				
			||||||
 | 
					            state.createCollectionDialog.visible = true;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const onCreateCollection = async () => {
 | 
				
			||||||
 | 
					            const form = state.createCollectionDialog.form;
 | 
				
			||||||
 | 
					            await mongoApi.runCommand.request({
 | 
				
			||||||
 | 
					                id: state.currentId,
 | 
				
			||||||
 | 
					                database: state.collectionsDialog.database,
 | 
				
			||||||
 | 
					                command: {
 | 
				
			||||||
 | 
					                    create: form.name,
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            ElMessage.success('集合创建成功');
 | 
				
			||||||
 | 
					            state.createCollectionDialog.visible = false;
 | 
				
			||||||
 | 
					            state.createCollectionDialog.form = {} as any;
 | 
				
			||||||
 | 
					            setCollections(state.collectionsDialog.database);
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const deleteMongo = async () => {
 | 
				
			||||||
 | 
					            try {
 | 
				
			||||||
 | 
					                await ElMessageBox.confirm(`确定删除该mongo?`, '提示', {
 | 
				
			||||||
 | 
					                    confirmButtonText: '确定',
 | 
				
			||||||
 | 
					                    cancelButtonText: '取消',
 | 
				
			||||||
 | 
					                    type: 'warning',
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					                await mongoApi.deleteMongo.request({ id: state.currentId });
 | 
				
			||||||
 | 
					                ElMessage.success('删除成功');
 | 
				
			||||||
 | 
					                state.currentData = null;
 | 
				
			||||||
 | 
					                state.currentId = null;
 | 
				
			||||||
 | 
					                search();
 | 
				
			||||||
 | 
					            } catch (err) {}
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // const info = (redis: any) => {
 | 
				
			||||||
 | 
					        //     redisApi.redisInfo.request({ id: redis.id }).then((res: any) => {
 | 
				
			||||||
 | 
					        //         state.infoDialog.info = res;
 | 
				
			||||||
 | 
					        //         state.infoDialog.title = `'${redis.host}' info`;
 | 
				
			||||||
 | 
					        //         state.infoDialog.visible = true;
 | 
				
			||||||
 | 
					        //     });
 | 
				
			||||||
 | 
					        // };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const search = async () => {
 | 
				
			||||||
 | 
					            const res = await mongoApi.mongoList.request(state.query);
 | 
				
			||||||
 | 
					            state.list = res.list;
 | 
				
			||||||
 | 
					            state.total = res.total;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const editMongo = (isAdd = false) => {
 | 
				
			||||||
 | 
					            if (isAdd) {
 | 
				
			||||||
 | 
					                state.mongoEditDialog.data = null;
 | 
				
			||||||
 | 
					                state.mongoEditDialog.title = '新增mongo';
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                state.mongoEditDialog.data = state.currentData;
 | 
				
			||||||
 | 
					                state.mongoEditDialog.title = '修改mongo';
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            state.mongoEditDialog.visible = true;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const valChange = () => {
 | 
				
			||||||
 | 
					            state.currentId = null;
 | 
				
			||||||
 | 
					            state.currentData = null;
 | 
				
			||||||
 | 
					            search();
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return {
 | 
				
			||||||
 | 
					            ...toRefs(state),
 | 
				
			||||||
 | 
					            search,
 | 
				
			||||||
 | 
					            handlePageChange,
 | 
				
			||||||
 | 
					            choose,
 | 
				
			||||||
 | 
					            showDatabases,
 | 
				
			||||||
 | 
					            showDatabaseStats,
 | 
				
			||||||
 | 
					            showCollections,
 | 
				
			||||||
 | 
					            showCollectionStats,
 | 
				
			||||||
 | 
					            onDeleteCollection,
 | 
				
			||||||
 | 
					            showCreateCollectionDialog,
 | 
				
			||||||
 | 
					            onCreateCollection,
 | 
				
			||||||
 | 
					            formatByteSize,
 | 
				
			||||||
 | 
					            deleteMongo,
 | 
				
			||||||
 | 
					            editMongo,
 | 
				
			||||||
 | 
					            valChange,
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style>
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
							
								
								
									
										14
									
								
								mayfly_go_web/src/views/ops/mongo/api.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								mayfly_go_web/src/views/ops/mongo/api.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					import Api from '@/common/Api';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const mongoApi = {
 | 
				
			||||||
 | 
					    mongoList : Api.create("/mongos", 'get'),
 | 
				
			||||||
 | 
					    saveMongo : Api.create("/mongos", 'post'),
 | 
				
			||||||
 | 
					    deleteMongo : Api.create("/mongos/{id}", 'delete'),
 | 
				
			||||||
 | 
					    databases: Api.create("/mongos/{id}/databases", 'get'),
 | 
				
			||||||
 | 
					    collections: Api.create("/mongos/{id}/collections", 'get'),
 | 
				
			||||||
 | 
					    runCommand: Api.create("/mongos/{id}/run-command", 'post'),
 | 
				
			||||||
 | 
					    findCommand: Api.create("/mongos/{id}/command/find", 'post'),
 | 
				
			||||||
 | 
					    updateByIdCommand: Api.create("/mongos/{id}/command/update-by-id", 'post'),
 | 
				
			||||||
 | 
					    deleteByIdCommand: Api.create("/mongos/{id}/command/delete-by-id", 'post'),
 | 
				
			||||||
 | 
					    insertCommand: Api.create("/mongos/{id}/command/insert", 'post'),
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
<template>
 | 
					<template>
 | 
				
			||||||
    <div>
 | 
					    <div>
 | 
				
			||||||
        <el-dialog :title="title" v-model="dialogVisible" :before-close="cancel" :close-on-click-modal="false" width="35%">
 | 
					        <el-dialog :title="title" v-model="dialogVisible" :before-close="cancel" :close-on-click-modal="false" :destroy-on-close="true" width="35%">
 | 
				
			||||||
            <el-form :model="form" ref="redisForm" :rules="rules" label-width="85px">
 | 
					            <el-form :model="form" ref="redisForm" :rules="rules" label-width="85px">
 | 
				
			||||||
                <el-form-item prop="projectId" label="项目:" required>
 | 
					                <el-form-item prop="projectId" label="项目:" required>
 | 
				
			||||||
                    <el-select style="width: 100%" v-model="form.projectId" placeholder="请选择项目" @change="changeProject" filterable>
 | 
					                    <el-select style="width: 100%" v-model="form.projectId" placeholder="请选择项目" @change="changeProject" filterable>
 | 
				
			||||||
@@ -170,11 +170,6 @@ export default defineComponent({
 | 
				
			|||||||
        const cancel = () => {
 | 
					        const cancel = () => {
 | 
				
			||||||
            emit('update:visible', false);
 | 
					            emit('update:visible', false);
 | 
				
			||||||
            emit('cancel');
 | 
					            emit('cancel');
 | 
				
			||||||
            setTimeout(() => {
 | 
					 | 
				
			||||||
                redisForm.value.resetFields();
 | 
					 | 
				
			||||||
                //  重置对象属性为null
 | 
					 | 
				
			||||||
                state.form = {} as any;
 | 
					 | 
				
			||||||
            }, 200);
 | 
					 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return {
 | 
					        return {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
<template>
 | 
					<template>
 | 
				
			||||||
    <div class="account-dialog">
 | 
					    <div class="account-dialog">
 | 
				
			||||||
        <el-dialog :title="title" v-model="dialogVisible" :before-close="cancel" :show-close="false" width="35%">
 | 
					        <el-dialog :title="title" v-model="dialogVisible" :before-close="cancel" :show-close="false" width="35%" :destroy-on-close="true">
 | 
				
			||||||
            <el-form :model="form" ref="accountForm" :rules="rules" label-width="85px">
 | 
					            <el-form :model="form" ref="accountForm" :rules="rules" label-width="85px">
 | 
				
			||||||
                <el-form-item prop="username" label="用户名:" required>
 | 
					                <el-form-item prop="username" label="用户名:" required>
 | 
				
			||||||
                    <el-input :disabled="edit" v-model.trim="form.username" placeholder="请输入账号用户名" auto-complete="off"></el-input>
 | 
					                    <el-input :disabled="edit" v-model.trim="form.username" placeholder="请输入账号用户名" auto-complete="off"></el-input>
 | 
				
			||||||
@@ -105,15 +105,7 @@ export default defineComponent({
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        const cancel = () => {
 | 
					        const cancel = () => {
 | 
				
			||||||
            emit('update:visible', false);
 | 
					            emit('update:visible', false);
 | 
				
			||||||
            setTimeout(() => {
 | 
					 | 
				
			||||||
                emit('update:account', null);
 | 
					 | 
				
			||||||
            }, 800);
 | 
					 | 
				
			||||||
            emit('cancel');
 | 
					            emit('cancel');
 | 
				
			||||||
            setTimeout(() => {
 | 
					 | 
				
			||||||
                accountForm.value.resetFields();
 | 
					 | 
				
			||||||
                //  重置对象属性为null
 | 
					 | 
				
			||||||
                state.form = {} as any;
 | 
					 | 
				
			||||||
            }, 200);
 | 
					 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return {
 | 
					        return {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,7 +2,7 @@
 | 
				
			|||||||
    <div class="account-dialog">
 | 
					    <div class="account-dialog">
 | 
				
			||||||
        <el-dialog
 | 
					        <el-dialog
 | 
				
			||||||
            :title="account == null ? '' : '分配“' + account.username + '”的角色'"
 | 
					            :title="account == null ? '' : '分配“' + account.username + '”的角色'"
 | 
				
			||||||
            v-model="visible"
 | 
					            v-model="dialogVisible"
 | 
				
			||||||
            :before-close="cancel"
 | 
					            :before-close="cancel"
 | 
				
			||||||
            :show-close="false"
 | 
					            :show-close="false"
 | 
				
			||||||
        >
 | 
					        >
 | 
				
			||||||
@@ -15,7 +15,7 @@
 | 
				
			|||||||
            <el-table :data="allRole" border ref="roleTable" @select="select" style="width: 100%">
 | 
					            <el-table :data="allRole" border ref="roleTable" @select="select" style="width: 100%">
 | 
				
			||||||
                <el-table-column :selectable="selectable" type="selection" width="40"></el-table-column>
 | 
					                <el-table-column :selectable="selectable" type="selection" width="40"></el-table-column>
 | 
				
			||||||
                <el-table-column prop="name" label="角色名称"></el-table-column>
 | 
					                <el-table-column prop="name" label="角色名称"></el-table-column>
 | 
				
			||||||
                 <el-table-column prop="code" label="角色code"></el-table-column>
 | 
					                <el-table-column prop="code" label="角色code"></el-table-column>
 | 
				
			||||||
                <el-table-column prop="remark" label="角色描述">
 | 
					                <el-table-column prop="remark" label="角色描述">
 | 
				
			||||||
                    <template #default="scope">
 | 
					                    <template #default="scope">
 | 
				
			||||||
                        {{ scope.row.remark ? scope.row.remark : '暂无描述' }}
 | 
					                        {{ scope.row.remark ? scope.row.remark : '暂无描述' }}
 | 
				
			||||||
@@ -59,7 +59,7 @@ export default defineComponent({
 | 
				
			|||||||
    setup(props: any, { emit }) {
 | 
					    setup(props: any, { emit }) {
 | 
				
			||||||
        const roleTable: any = ref(null);
 | 
					        const roleTable: any = ref(null);
 | 
				
			||||||
        const state = reactive({
 | 
					        const state = reactive({
 | 
				
			||||||
            visible: false,
 | 
					            dialogVisible: false,
 | 
				
			||||||
            btnLoading: false,
 | 
					            btnLoading: false,
 | 
				
			||||||
            // 所有角色
 | 
					            // 所有角色
 | 
				
			||||||
            allRole: [] as any,
 | 
					            allRole: [] as any,
 | 
				
			||||||
@@ -73,8 +73,8 @@ export default defineComponent({
 | 
				
			|||||||
            total: 0,
 | 
					            total: 0,
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        watch(props, (newValue, oldValue) => {
 | 
					        watch(props, (newValue) => {
 | 
				
			||||||
            state.visible = newValue.visible;
 | 
					            state.dialogVisible = newValue.visible;
 | 
				
			||||||
            if (newValue.account && newValue.account.id != 0) {
 | 
					            if (newValue.account && newValue.account.id != 0) {
 | 
				
			||||||
                accountApi.roleIds
 | 
					                accountApi.roleIds
 | 
				
			||||||
                    .request({
 | 
					                    .request({
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,7 +5,7 @@
 | 
				
			|||||||
                <el-row :gutter="10">
 | 
					                <el-row :gutter="10">
 | 
				
			||||||
                    <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb10">
 | 
					                    <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb10">
 | 
				
			||||||
                        <el-form-item prop="type" label="类型" required>
 | 
					                        <el-form-item prop="type" label="类型" required>
 | 
				
			||||||
                            <el-select v-model="form.type" :disabled="typeDisabled" placeholder="请选择" width="w100">
 | 
					                            <el-select v-model="form.type" :disabled="typeDisabled" placeholder="请选择" >
 | 
				
			||||||
                                <el-option v-for="item in enums.ResourceTypeEnum" :key="item.value" :label="item.label" :value="item.value">
 | 
					                                <el-option v-for="item in enums.ResourceTypeEnum" :key="item.value" :label="item.label" :value="item.value">
 | 
				
			||||||
                                </el-option>
 | 
					                                </el-option>
 | 
				
			||||||
                            </el-select>
 | 
					                            </el-select>
 | 
				
			||||||
@@ -83,7 +83,7 @@
 | 
				
			|||||||
            </el-form>
 | 
					            </el-form>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <template #footer>
 | 
					            <template #footer>
 | 
				
			||||||
                <div class="dialog-footer mt10">
 | 
					                <div>
 | 
				
			||||||
                    <el-button @click="cancel()">取 消</el-button>
 | 
					                    <el-button @click="cancel()">取 消</el-button>
 | 
				
			||||||
                    <el-button type="primary" :loading="btnLoading" @click="btnOk">确 定</el-button>
 | 
					                    <el-button type="primary" :loading="btnLoading" @click="btnOk">确 定</el-button>
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
@@ -284,11 +284,6 @@ export default defineComponent({
 | 
				
			|||||||
        const cancel = () => {
 | 
					        const cancel = () => {
 | 
				
			||||||
            emit('update:visible', false);
 | 
					            emit('update:visible', false);
 | 
				
			||||||
            emit('cancel');
 | 
					            emit('cancel');
 | 
				
			||||||
            setTimeout(() => {
 | 
					 | 
				
			||||||
                menuForm.value.resetFields();
 | 
					 | 
				
			||||||
                //  重置对象属性为null
 | 
					 | 
				
			||||||
                state.form = {} as any;
 | 
					 | 
				
			||||||
            }, 200);
 | 
					 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return {
 | 
					        return {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -109,9 +109,7 @@ export default defineComponent({
 | 
				
			|||||||
        const cancel = () => {
 | 
					        const cancel = () => {
 | 
				
			||||||
            // 更新父组件visible prop对应的值为false
 | 
					            // 更新父组件visible prop对应的值为false
 | 
				
			||||||
            emit('update:visible', false);
 | 
					            emit('update:visible', false);
 | 
				
			||||||
            setTimeout(() => {
 | 
					            emit('cancel');
 | 
				
			||||||
                emit('cancel');
 | 
					 | 
				
			||||||
            }, 700);
 | 
					 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return {
 | 
					        return {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,12 +1,17 @@
 | 
				
			|||||||
<template>
 | 
					<template>
 | 
				
			||||||
    <div class="role-dialog">
 | 
					    <div class="role-dialog">
 | 
				
			||||||
        <el-dialog :title="title" v-model="dvisible" :show-close="false" :before-close="cancel" width="500px">
 | 
					        <el-dialog :title="title" v-model="dvisible" :show-close="false" :before-close="cancel" width="500px" :destroy-on-close="true">
 | 
				
			||||||
            <el-form :model="form" label-width="90px">
 | 
					            <el-form :model="form" label-width="90px">
 | 
				
			||||||
                <el-form-item prop="name" label="角色名称:" required>
 | 
					                <el-form-item prop="name" label="角色名称:" required>
 | 
				
			||||||
                    <el-input v-model="form.name" auto-complete="off"></el-input>
 | 
					                    <el-input v-model="form.name" auto-complete="off"></el-input>
 | 
				
			||||||
                </el-form-item>
 | 
					                </el-form-item>
 | 
				
			||||||
                <el-form-item prop="code" label="角色code:" required>
 | 
					                <el-form-item prop="code" label="角色code:" required>
 | 
				
			||||||
                    <el-input :disabled="form.id != null" v-model="form.code" placeholder="COMMON开头则为所有账号共有角色" auto-complete="off"></el-input>
 | 
					                    <el-input
 | 
				
			||||||
 | 
					                        :disabled="form.id != null"
 | 
				
			||||||
 | 
					                        v-model="form.code"
 | 
				
			||||||
 | 
					                        placeholder="COMMON开头则为所有账号共有角色"
 | 
				
			||||||
 | 
					                        auto-complete="off"
 | 
				
			||||||
 | 
					                    ></el-input>
 | 
				
			||||||
                </el-form-item>
 | 
					                </el-form-item>
 | 
				
			||||||
                <el-form-item label="角色描述:">
 | 
					                <el-form-item label="角色描述:">
 | 
				
			||||||
                    <el-input v-model="form.remark" type="textarea" :rows="3" placeholder="请输入角色描述"></el-input>
 | 
					                    <el-input v-model="form.remark" type="textarea" :rows="3" placeholder="请输入角色描述"></el-input>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,10 +12,10 @@
 | 
				
			|||||||
  resolved "https://registry.npmmirror.com/@ctrl/tinycolor/-/tinycolor-3.4.1.tgz#75b4c27948c81e88ccd3a8902047bcd797f38d32"
 | 
					  resolved "https://registry.npmmirror.com/@ctrl/tinycolor/-/tinycolor-3.4.1.tgz#75b4c27948c81e88ccd3a8902047bcd797f38d32"
 | 
				
			||||||
  integrity sha512-ej5oVy6lykXsvieQtqZxCOaLT+xD4+QNarq78cIYISHmZXshCvROLudpQN3lfL8G0NL7plMSSK+zlyvCaIJ4Iw==
 | 
					  integrity sha512-ej5oVy6lykXsvieQtqZxCOaLT+xD4+QNarq78cIYISHmZXshCvROLudpQN3lfL8G0NL7plMSSK+zlyvCaIJ4Iw==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"@element-plus/icons-vue@^1.1.3", "@element-plus/icons-vue@^1.1.4":
 | 
					"@element-plus/icons-vue@^2.0.6":
 | 
				
			||||||
  version "1.1.4"
 | 
					  version "2.0.6"
 | 
				
			||||||
  resolved "https://registry.npmmirror.com/@element-plus/icons-vue/-/icons-vue-1.1.4.tgz#5d2788ea356f1458068e6d400e724ca5f3d29aca"
 | 
					  resolved "https://registry.npmmirror.com/@element-plus/icons-vue/-/icons-vue-2.0.6.tgz#8490e7a3193c17515d10c3be0544d800afe6a228"
 | 
				
			||||||
  integrity sha512-Iz/nHqdp1sFPmdzRwHkEQQA3lKvoObk8azgABZ81QUOpW9s/lUyQVUSh0tNtEPZXQlKwlSh7SPgoVxzrE0uuVQ==
 | 
					  integrity sha512-lPpG8hYkjL/Z97DH5Ei6w6o22Z4YdNglWCNYOPcB33JCF2A4wye6HFgSI7hEt9zdLyxlSpiqtgf9XcYU+m5mew==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"@eslint/eslintrc@^1.0.5":
 | 
					"@eslint/eslintrc@^1.0.5":
 | 
				
			||||||
  version "1.0.5"
 | 
					  version "1.0.5"
 | 
				
			||||||
@@ -32,17 +32,17 @@
 | 
				
			|||||||
    minimatch "^3.0.4"
 | 
					    minimatch "^3.0.4"
 | 
				
			||||||
    strip-json-comments "^3.1.1"
 | 
					    strip-json-comments "^3.1.1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"@floating-ui/core@^0.6.2":
 | 
					"@floating-ui/core@^0.7.3":
 | 
				
			||||||
  version "0.6.2"
 | 
					  version "0.7.3"
 | 
				
			||||||
  resolved "https://registry.npmmirror.com/@floating-ui/core/-/core-0.6.2.tgz#f2813f0e5f3d5ed7af5029e1a082203dadf02b7d"
 | 
					  resolved "https://registry.npmmirror.com/@floating-ui/core/-/core-0.7.3.tgz#d274116678ffae87f6b60e90f88cc4083eefab86"
 | 
				
			||||||
  integrity sha512-jktYRmZwmau63adUG3GKOAVCofBXkk55S/zQ94XOorAHhwqFIOFAy1rSp2N0Wp6/tGbe9V3u/ExlGZypyY17rg==
 | 
					  integrity sha512-buc8BXHmG9l82+OQXOFU3Kr2XQx9ys01U/Q9HMIrZ300iLc8HLMgh7dcCqgYzAzf4BkoQvDcXf5Y+CuEZ5JBYg==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"@floating-ui/dom@^0.4.5":
 | 
					"@floating-ui/dom@^0.5.4":
 | 
				
			||||||
  version "0.4.5"
 | 
					  version "0.5.4"
 | 
				
			||||||
  resolved "https://registry.npmmirror.com/@floating-ui/dom/-/dom-0.4.5.tgz#2e88d16646119cc67d44683f75ee99840475bbfa"
 | 
					  resolved "https://registry.npmmirror.com/@floating-ui/dom/-/dom-0.5.4.tgz#4eae73f78bcd4bd553ae2ade30e6f1f9c73fe3f1"
 | 
				
			||||||
  integrity sha512-b+prvQgJt8pieaKYMSJBXHxX/DYwdLsAWxKYqnO5dO2V4oo/TYBZJAUQCVNjTWWsrs6o4VDrNcP9+E70HAhJdw==
 | 
					  integrity sha512-419BMceRLq0RrmTSDxn8hf9R3VCJv2K9PUfugh5JyEFmdjzDo+e8U5EdR8nzKq8Yj1htzLm3b6eQEEam3/rrtg==
 | 
				
			||||||
  dependencies:
 | 
					  dependencies:
 | 
				
			||||||
    "@floating-ui/core" "^0.6.2"
 | 
					    "@floating-ui/core" "^0.7.3"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"@humanwhocodes/config-array@^0.9.2":
 | 
					"@humanwhocodes/config-array@^0.9.2":
 | 
				
			||||||
  version "0.9.2"
 | 
					  version "0.9.2"
 | 
				
			||||||
@@ -79,10 +79,15 @@
 | 
				
			|||||||
    "@nodelib/fs.scandir" "2.1.5"
 | 
					    "@nodelib/fs.scandir" "2.1.5"
 | 
				
			||||||
    fastq "^1.6.0"
 | 
					    fastq "^1.6.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"@popperjs/core@npm:@sxzz/popperjs-es@^2.11.6":
 | 
					"@popperjs/core@npm:@sxzz/popperjs-es@^2.11.7":
 | 
				
			||||||
  version "2.11.6"
 | 
					  version "2.11.7"
 | 
				
			||||||
  resolved "https://registry.npmmirror.com/@sxzz/popperjs-es/-/popperjs-es-2.11.6.tgz#932711b897e7a67d940c024e0bd93931cb61338c"
 | 
					  resolved "https://registry.npmmirror.com/@sxzz/popperjs-es/-/popperjs-es-2.11.7.tgz#a7f69e3665d3da9b115f9e71671dae1b97e13671"
 | 
				
			||||||
  integrity sha512-V8W+eJiInGq8roHR8xYR+lxojL022LyUI9E4FRav4+1Ih+875ONcLNK3XIs809fyxk1lNzrZO5OAy6xpvEafNw==
 | 
					  integrity sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"@sphinxxxx/color-conversion@^2.2.2":
 | 
				
			||||||
 | 
					  version "2.2.2"
 | 
				
			||||||
 | 
					  resolved "https://registry.npmmirror.com/@sphinxxxx/color-conversion/-/color-conversion-2.2.2.tgz#03ecc29279e3c0c832f6185a5bfa3497858ac8ca"
 | 
				
			||||||
 | 
					  integrity sha512-XExJS3cLqgrmNBIP3bBw6+1oQ1ksGjFh0+oClDKFYpCCqx/hlqwWO5KO/S63fzUo67SxI9dMrF0y5T/Ey7h8Zw==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"@types/json-schema@^7.0.7":
 | 
					"@types/json-schema@^7.0.7":
 | 
				
			||||||
  version "7.0.9"
 | 
					  version "7.0.9"
 | 
				
			||||||
@@ -121,6 +126,11 @@
 | 
				
			|||||||
  resolved "https://registry.npmmirror.com/@types/sortablejs/download/@types/sortablejs-1.10.7.tgz#ab9039c85429f0516955ec6dbc0bb20139417b15"
 | 
					  resolved "https://registry.npmmirror.com/@types/sortablejs/download/@types/sortablejs-1.10.7.tgz#ab9039c85429f0516955ec6dbc0bb20139417b15"
 | 
				
			||||||
  integrity sha1-q5A5yFQp8FFpVextvAuyATlBexU=
 | 
					  integrity sha1-q5A5yFQp8FFpVextvAuyATlBexU=
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"@types/web-bluetooth@^0.0.14":
 | 
				
			||||||
 | 
					  version "0.0.14"
 | 
				
			||||||
 | 
					  resolved "https://registry.npmmirror.com/@types/web-bluetooth/-/web-bluetooth-0.0.14.tgz#94e175b53623384bff1f354cdb3197a8d63cdbe5"
 | 
				
			||||||
 | 
					  integrity sha512-5d2RhCard1nQUC3aHcq/gHzWYO6K0WJmAbjO7mQJgCQKtZpgXxv1rOM6O/dBDhDYYVutk1sciOgNSe+5YyfM8A==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"@typescript-eslint/eslint-plugin@^4.23.0":
 | 
					"@typescript-eslint/eslint-plugin@^4.23.0":
 | 
				
			||||||
  version "4.33.0"
 | 
					  version "4.33.0"
 | 
				
			||||||
  resolved "https://registry.npmmirror.com/@typescript-eslint/eslint-plugin/download/@typescript-eslint/eslint-plugin-4.33.0.tgz#c24dc7c8069c7706bc40d99f6fa87edcb2005276"
 | 
					  resolved "https://registry.npmmirror.com/@typescript-eslint/eslint-plugin/download/@typescript-eslint/eslint-plugin-4.33.0.tgz#c24dc7c8069c7706bc40d99f6fa87edcb2005276"
 | 
				
			||||||
@@ -191,10 +201,10 @@
 | 
				
			|||||||
    "@typescript-eslint/types" "4.33.0"
 | 
					    "@typescript-eslint/types" "4.33.0"
 | 
				
			||||||
    eslint-visitor-keys "^2.0.0"
 | 
					    eslint-visitor-keys "^2.0.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"@vitejs/plugin-vue@^1.2.2":
 | 
					"@vitejs/plugin-vue@^2.3.3":
 | 
				
			||||||
  version "1.10.2"
 | 
					  version "2.3.3"
 | 
				
			||||||
  resolved "https://registry.npmmirror.com/@vitejs/plugin-vue/download/@vitejs/plugin-vue-1.10.2.tgz#d718479e2789d8a94b63e00f23f1898ba239253a"
 | 
					  resolved "https://registry.npmmirror.com/@vitejs/plugin-vue/-/plugin-vue-2.3.3.tgz#fbf80cc039b82ac21a1acb0f0478de8f61fbf600"
 | 
				
			||||||
  integrity sha512-/QJ0Z9qfhAFtKRY+r57ziY4BSbGUTGsPRMpB/Ron3QPwBZM4OZAZHdTa4a8PafCwU5DTatXG8TMDoP8z+oDqJw==
 | 
					  integrity sha512-SmQLDyhz+6lGJhPELsBdzXGc+AcaT8stgkbiTFGpXPe8Tl1tJaBw1A6pxDqDuRsVkD8uscrkx3hA7QDOoKYtyw==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"@vue/compiler-core@3.2.26":
 | 
					"@vue/compiler-core@3.2.26":
 | 
				
			||||||
  version "3.2.26"
 | 
					  version "3.2.26"
 | 
				
			||||||
@@ -206,13 +216,13 @@
 | 
				
			|||||||
    estree-walker "^2.0.2"
 | 
					    estree-walker "^2.0.2"
 | 
				
			||||||
    source-map "^0.6.1"
 | 
					    source-map "^0.6.1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"@vue/compiler-core@3.2.33":
 | 
					"@vue/compiler-core@3.2.37":
 | 
				
			||||||
  version "3.2.33"
 | 
					  version "3.2.37"
 | 
				
			||||||
  resolved "https://registry.npmmirror.com/@vue/compiler-core/-/compiler-core-3.2.33.tgz#e915d59cce85898f5c5cfebe4c09e539278c3d59"
 | 
					  resolved "https://registry.npmmirror.com/@vue/compiler-core/-/compiler-core-3.2.37.tgz#b3c42e04c0e0f2c496ff1784e543fbefe91e215a"
 | 
				
			||||||
  integrity sha512-AAmr52ji3Zhk7IKIuigX2osWWsb2nQE5xsdFYjdnmtQ4gymmqXbjLvkSE174+fF3A3kstYrTgGkqgOEbsdLDpw==
 | 
					  integrity sha512-81KhEjo7YAOh0vQJoSmAD68wLfYqJvoiD4ulyedzF+OEk/bk6/hx3fTNVfuzugIIaTrOx4PGx6pAiBRe5e9Zmg==
 | 
				
			||||||
  dependencies:
 | 
					  dependencies:
 | 
				
			||||||
    "@babel/parser" "^7.16.4"
 | 
					    "@babel/parser" "^7.16.4"
 | 
				
			||||||
    "@vue/shared" "3.2.33"
 | 
					    "@vue/shared" "3.2.37"
 | 
				
			||||||
    estree-walker "^2.0.2"
 | 
					    estree-walker "^2.0.2"
 | 
				
			||||||
    source-map "^0.6.1"
 | 
					    source-map "^0.6.1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -224,25 +234,25 @@
 | 
				
			|||||||
    "@vue/compiler-core" "3.2.26"
 | 
					    "@vue/compiler-core" "3.2.26"
 | 
				
			||||||
    "@vue/shared" "3.2.26"
 | 
					    "@vue/shared" "3.2.26"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"@vue/compiler-dom@3.2.33":
 | 
					"@vue/compiler-dom@3.2.37":
 | 
				
			||||||
  version "3.2.33"
 | 
					  version "3.2.37"
 | 
				
			||||||
  resolved "https://registry.npmmirror.com/@vue/compiler-dom/-/compiler-dom-3.2.33.tgz#6db84296f949f18e5d3e7fd5e80f943dbed7d5ec"
 | 
					  resolved "https://registry.npmmirror.com/@vue/compiler-dom/-/compiler-dom-3.2.37.tgz#10d2427a789e7c707c872da9d678c82a0c6582b5"
 | 
				
			||||||
  integrity sha512-GhiG1C8X98Xz9QUX/RlA6/kgPBWJkjq0Rq6//5XTAGSYrTMBgcLpP9+CnlUg1TFxnnCVughAG+KZl28XJqw8uQ==
 | 
					  integrity sha512-yxJLH167fucHKxaqXpYk7x8z7mMEnXOw3G2q62FTkmsvNxu4FQSu5+3UMb+L7fjKa26DEzhrmCxAgFLLIzVfqQ==
 | 
				
			||||||
  dependencies:
 | 
					  dependencies:
 | 
				
			||||||
    "@vue/compiler-core" "3.2.33"
 | 
					    "@vue/compiler-core" "3.2.37"
 | 
				
			||||||
    "@vue/shared" "3.2.33"
 | 
					    "@vue/shared" "3.2.37"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"@vue/compiler-sfc@3.2.33":
 | 
					"@vue/compiler-sfc@3.2.37":
 | 
				
			||||||
  version "3.2.33"
 | 
					  version "3.2.37"
 | 
				
			||||||
  resolved "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-3.2.33.tgz#7ce01dc947a8b76c099811dc6ca58494d4dc773d"
 | 
					  resolved "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-3.2.37.tgz#3103af3da2f40286edcd85ea495dcb35bc7f5ff4"
 | 
				
			||||||
  integrity sha512-H8D0WqagCr295pQjUYyO8P3IejM3vEzeCO1apzByAEaAR/WimhMYczHfZVvlCE/9yBaEu/eu9RdiWr0kF8b71Q==
 | 
					  integrity sha512-+7i/2+9LYlpqDv+KTtWhOZH+pa8/HnX/905MdVmAcI/mPQOBwkHHIzrsEsucyOIZQYMkXUiTkmZq5am/NyXKkg==
 | 
				
			||||||
  dependencies:
 | 
					  dependencies:
 | 
				
			||||||
    "@babel/parser" "^7.16.4"
 | 
					    "@babel/parser" "^7.16.4"
 | 
				
			||||||
    "@vue/compiler-core" "3.2.33"
 | 
					    "@vue/compiler-core" "3.2.37"
 | 
				
			||||||
    "@vue/compiler-dom" "3.2.33"
 | 
					    "@vue/compiler-dom" "3.2.37"
 | 
				
			||||||
    "@vue/compiler-ssr" "3.2.33"
 | 
					    "@vue/compiler-ssr" "3.2.37"
 | 
				
			||||||
    "@vue/reactivity-transform" "3.2.33"
 | 
					    "@vue/reactivity-transform" "3.2.37"
 | 
				
			||||||
    "@vue/shared" "3.2.33"
 | 
					    "@vue/shared" "3.2.37"
 | 
				
			||||||
    estree-walker "^2.0.2"
 | 
					    estree-walker "^2.0.2"
 | 
				
			||||||
    magic-string "^0.25.7"
 | 
					    magic-string "^0.25.7"
 | 
				
			||||||
    postcss "^8.1.10"
 | 
					    postcss "^8.1.10"
 | 
				
			||||||
@@ -272,15 +282,20 @@
 | 
				
			|||||||
    "@vue/compiler-dom" "3.2.26"
 | 
					    "@vue/compiler-dom" "3.2.26"
 | 
				
			||||||
    "@vue/shared" "3.2.26"
 | 
					    "@vue/shared" "3.2.26"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"@vue/compiler-ssr@3.2.33":
 | 
					"@vue/compiler-ssr@3.2.37":
 | 
				
			||||||
  version "3.2.33"
 | 
					  version "3.2.37"
 | 
				
			||||||
  resolved "https://registry.npmmirror.com/@vue/compiler-ssr/-/compiler-ssr-3.2.33.tgz#3e820267e4eea48fde9519f006dedca3f5e42e71"
 | 
					  resolved "https://registry.npmmirror.com/@vue/compiler-ssr/-/compiler-ssr-3.2.37.tgz#4899d19f3a5fafd61524a9d1aee8eb0505313cff"
 | 
				
			||||||
  integrity sha512-XQh1Xdk3VquDpXsnoCd7JnMoWec9CfAzQDQsaMcSU79OrrO2PNR0ErlIjm/mGq3GmBfkQjzZACV+7GhfRB8xMQ==
 | 
					  integrity sha512-7mQJD7HdXxQjktmsWp/J67lThEIcxLemz1Vb5I6rYJHR5vI+lON3nPGOH3ubmbvYGt8xEUaAr1j7/tIFWiEOqw==
 | 
				
			||||||
  dependencies:
 | 
					  dependencies:
 | 
				
			||||||
    "@vue/compiler-dom" "3.2.33"
 | 
					    "@vue/compiler-dom" "3.2.37"
 | 
				
			||||||
    "@vue/shared" "3.2.33"
 | 
					    "@vue/shared" "3.2.37"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"@vue/devtools-api@^6.0.0-beta.11", "@vue/devtools-api@^6.0.0-beta.18":
 | 
					"@vue/devtools-api@^6.0.0":
 | 
				
			||||||
 | 
					  version "6.1.4"
 | 
				
			||||||
 | 
					  resolved "https://registry.npmmirror.com/@vue/devtools-api/-/devtools-api-6.1.4.tgz#b4aec2f4b4599e11ba774a50c67fa378c9824e53"
 | 
				
			||||||
 | 
					  integrity sha512-IiA0SvDrJEgXvVxjNkHPFfDx6SXw0b/TUkqMcDZWNg9fnCAHbTpoo59YfJ9QLFkwa3raau5vSlRVzMSLDnfdtQ==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"@vue/devtools-api@^6.0.0-beta.11":
 | 
				
			||||||
  version "6.0.0-beta.20.1"
 | 
					  version "6.0.0-beta.20.1"
 | 
				
			||||||
  resolved "https://registry.npmmirror.com/@vue/devtools-api/download/@vue/devtools-api-6.0.0-beta.20.1.tgz#5b499647e929c35baf2a66a399578f9aa4601142"
 | 
					  resolved "https://registry.npmmirror.com/@vue/devtools-api/download/@vue/devtools-api-6.0.0-beta.20.1.tgz#5b499647e929c35baf2a66a399578f9aa4601142"
 | 
				
			||||||
  integrity sha512-R2rfiRY+kZugzWh9ZyITaovx+jpU4vgivAEAiz80kvh3yviiTU3CBuGuyWpSwGz9/C7TkSWVM/FtQRGlZ16n8Q==
 | 
					  integrity sha512-R2rfiRY+kZugzWh9ZyITaovx+jpU4vgivAEAiz80kvh3yviiTU3CBuGuyWpSwGz9/C7TkSWVM/FtQRGlZ16n8Q==
 | 
				
			||||||
@@ -296,84 +311,85 @@
 | 
				
			|||||||
    estree-walker "^2.0.2"
 | 
					    estree-walker "^2.0.2"
 | 
				
			||||||
    magic-string "^0.25.7"
 | 
					    magic-string "^0.25.7"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"@vue/reactivity-transform@3.2.33":
 | 
					"@vue/reactivity-transform@3.2.37":
 | 
				
			||||||
  version "3.2.33"
 | 
					  version "3.2.37"
 | 
				
			||||||
  resolved "https://registry.npmmirror.com/@vue/reactivity-transform/-/reactivity-transform-3.2.33.tgz#286063f44ca56150ae9b52f8346a26e5913fa699"
 | 
					  resolved "https://registry.npmmirror.com/@vue/reactivity-transform/-/reactivity-transform-3.2.37.tgz#0caa47c4344df4ae59f5a05dde2a8758829f8eca"
 | 
				
			||||||
  integrity sha512-4UL5KOIvSQb254aqenW4q34qMXbfZcmEsV/yVidLUgvwYQQ/D21bGX3DlgPUGI3c4C+iOnNmDCkIxkILoX/Pyw==
 | 
					  integrity sha512-IWopkKEb+8qpu/1eMKVeXrK0NLw9HicGviJzhJDEyfxTR9e1WtpnnbYkJWurX6WwoFP0sz10xQg8yL8lgskAZg==
 | 
				
			||||||
  dependencies:
 | 
					  dependencies:
 | 
				
			||||||
    "@babel/parser" "^7.16.4"
 | 
					    "@babel/parser" "^7.16.4"
 | 
				
			||||||
    "@vue/compiler-core" "3.2.33"
 | 
					    "@vue/compiler-core" "3.2.37"
 | 
				
			||||||
    "@vue/shared" "3.2.33"
 | 
					    "@vue/shared" "3.2.37"
 | 
				
			||||||
    estree-walker "^2.0.2"
 | 
					    estree-walker "^2.0.2"
 | 
				
			||||||
    magic-string "^0.25.7"
 | 
					    magic-string "^0.25.7"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"@vue/reactivity@3.2.33":
 | 
					"@vue/reactivity@3.2.37":
 | 
				
			||||||
  version "3.2.33"
 | 
					  version "3.2.37"
 | 
				
			||||||
  resolved "https://registry.npmmirror.com/@vue/reactivity/-/reactivity-3.2.33.tgz#c84eedb5225138dbfc2472864c151d3efbb4b673"
 | 
					  resolved "https://registry.npmmirror.com/@vue/reactivity/-/reactivity-3.2.37.tgz#5bc3847ac58828e2b78526e08219e0a1089f8848"
 | 
				
			||||||
  integrity sha512-62Sq0mp9/0bLmDuxuLD5CIaMG2susFAGARLuZ/5jkU1FCf9EDbwUuF+BO8Ub3Rbodx0ziIecM/NsmyjardBxfQ==
 | 
					  integrity sha512-/7WRafBOshOc6m3F7plwzPeCu/RCVv9uMpOwa/5PiY1Zz+WLVRWiy0MYKwmg19KBdGtFWsmZ4cD+LOdVPcs52A==
 | 
				
			||||||
  dependencies:
 | 
					  dependencies:
 | 
				
			||||||
    "@vue/shared" "3.2.33"
 | 
					    "@vue/shared" "3.2.37"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"@vue/runtime-core@3.2.33":
 | 
					"@vue/runtime-core@3.2.37":
 | 
				
			||||||
  version "3.2.33"
 | 
					  version "3.2.37"
 | 
				
			||||||
  resolved "https://registry.npmmirror.com/@vue/runtime-core/-/runtime-core-3.2.33.tgz#2df8907c85c37c3419fbd1bdf1a2df097fa40df2"
 | 
					  resolved "https://registry.npmmirror.com/@vue/runtime-core/-/runtime-core-3.2.37.tgz#7ba7c54bb56e5d70edfc2f05766e1ca8519966e3"
 | 
				
			||||||
  integrity sha512-N2D2vfaXsBPhzCV3JsXQa2NECjxP3eXgZlFqKh4tgakp3iX6LCGv76DLlc+IfFZq+TW10Y8QUfeihXOupJ1dGw==
 | 
					  integrity sha512-JPcd9kFyEdXLl/i0ClS7lwgcs0QpUAWj+SKX2ZC3ANKi1U4DOtiEr6cRqFXsPwY5u1L9fAjkinIdB8Rz3FoYNQ==
 | 
				
			||||||
  dependencies:
 | 
					  dependencies:
 | 
				
			||||||
    "@vue/reactivity" "3.2.33"
 | 
					    "@vue/reactivity" "3.2.37"
 | 
				
			||||||
    "@vue/shared" "3.2.33"
 | 
					    "@vue/shared" "3.2.37"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"@vue/runtime-dom@3.2.33":
 | 
					"@vue/runtime-dom@3.2.37":
 | 
				
			||||||
  version "3.2.33"
 | 
					  version "3.2.37"
 | 
				
			||||||
  resolved "https://registry.npmmirror.com/@vue/runtime-dom/-/runtime-dom-3.2.33.tgz#123b8969247029ea0d9c1983676d4706a962d848"
 | 
					  resolved "https://registry.npmmirror.com/@vue/runtime-dom/-/runtime-dom-3.2.37.tgz#002bdc8228fa63949317756fb1e92cdd3f9f4bbd"
 | 
				
			||||||
  integrity sha512-LSrJ6W7CZTSUygX5s8aFkraDWlO6K4geOwA3quFF2O+hC3QuAMZt/0Xb7JKE3C4JD4pFwCSO7oCrZmZ0BIJUnw==
 | 
					  integrity sha512-HimKdh9BepShW6YozwRKAYjYQWg9mQn63RGEiSswMbW+ssIht1MILYlVGkAGGQbkhSh31PCdoUcfiu4apXJoPw==
 | 
				
			||||||
  dependencies:
 | 
					  dependencies:
 | 
				
			||||||
    "@vue/runtime-core" "3.2.33"
 | 
					    "@vue/runtime-core" "3.2.37"
 | 
				
			||||||
    "@vue/shared" "3.2.33"
 | 
					    "@vue/shared" "3.2.37"
 | 
				
			||||||
    csstype "^2.6.8"
 | 
					    csstype "^2.6.8"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"@vue/server-renderer@3.2.33":
 | 
					"@vue/server-renderer@3.2.37":
 | 
				
			||||||
  version "3.2.33"
 | 
					  version "3.2.37"
 | 
				
			||||||
  resolved "https://registry.npmmirror.com/@vue/server-renderer/-/server-renderer-3.2.33.tgz#4b45d6d2ae10ea4e3d2cf8e676804cf60f331979"
 | 
					  resolved "https://registry.npmmirror.com/@vue/server-renderer/-/server-renderer-3.2.37.tgz#840a29c8dcc29bddd9b5f5ffa22b95c0e72afdfc"
 | 
				
			||||||
  integrity sha512-4jpJHRD4ORv8PlbYi+/MfP8ec1okz6rybe36MdpkDrGIdEItHEUyaHSKvz+ptNEyQpALmmVfRteHkU9F8vxOew==
 | 
					  integrity sha512-kLITEJvaYgZQ2h47hIzPh2K3jG8c1zCVbp/o/bzQOyvzaKiCquKS7AaioPI28GNxIsE/zSx+EwWYsNxDCX95MA==
 | 
				
			||||||
  dependencies:
 | 
					  dependencies:
 | 
				
			||||||
    "@vue/compiler-ssr" "3.2.33"
 | 
					    "@vue/compiler-ssr" "3.2.37"
 | 
				
			||||||
    "@vue/shared" "3.2.33"
 | 
					    "@vue/shared" "3.2.37"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"@vue/shared@3.2.26":
 | 
					"@vue/shared@3.2.26":
 | 
				
			||||||
  version "3.2.26"
 | 
					  version "3.2.26"
 | 
				
			||||||
  resolved "https://registry.npmmirror.com/@vue/shared/download/@vue/shared-3.2.26.tgz#7acd1621783571b9a82eca1f041b4a0a983481d9"
 | 
					  resolved "https://registry.npmmirror.com/@vue/shared/download/@vue/shared-3.2.26.tgz#7acd1621783571b9a82eca1f041b4a0a983481d9"
 | 
				
			||||||
  integrity sha512-vPV6Cq+NIWbH5pZu+V+2QHE9y1qfuTq49uNWw4f7FDEeZaDU2H2cx5jcUZOAKW7qTrUS4k6qZPbMy1x4N96nbA==
 | 
					  integrity sha512-vPV6Cq+NIWbH5pZu+V+2QHE9y1qfuTq49uNWw4f7FDEeZaDU2H2cx5jcUZOAKW7qTrUS4k6qZPbMy1x4N96nbA==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"@vue/shared@3.2.33":
 | 
					"@vue/shared@3.2.37":
 | 
				
			||||||
  version "3.2.33"
 | 
					  version "3.2.37"
 | 
				
			||||||
  resolved "https://registry.npmmirror.com/@vue/shared/-/shared-3.2.33.tgz#69a8c99ceb37c1b031d5cc4aec2ff1dc77e1161e"
 | 
					  resolved "https://registry.npmmirror.com/@vue/shared/-/shared-3.2.37.tgz#8e6adc3f2759af52f0e85863dfb0b711ecc5c702"
 | 
				
			||||||
  integrity sha512-UBc1Pg1T3yZ97vsA2ueER0F6GbJebLHYlEi4ou1H5YL4KWvMOOWwpYo9/QpWq93wxKG6Wo13IY74Hcn/f7c7Bg==
 | 
					  integrity sha512-4rSJemR2NQIo9Klm1vabqWjD8rs/ZaJSzMxkMNeJS6lHiUjjUeYFbooN19NgFjztubEKh3WlZUeOLVdbbUWHsw==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"@vueuse/core@^8.2.6":
 | 
					"@vueuse/core@^8.7.5":
 | 
				
			||||||
  version "8.3.1"
 | 
					  version "8.7.5"
 | 
				
			||||||
  resolved "https://registry.npmmirror.com/@vueuse/core/-/core-8.3.1.tgz#7f2c5977cc0690a803f44c3f5c291536ad7880d1"
 | 
					  resolved "https://registry.npmmirror.com/@vueuse/core/-/core-8.7.5.tgz#e74a888251ea11a9d432068ce18cbdfc4f810251"
 | 
				
			||||||
  integrity sha512-WiXUgVyPG9elGx3G8UV8g+zqbEJ2hYacrPICogAxDdW6hnxxcUFdF7FtvDroJ/DxWmo2pg8XNNz07ybfnZyJbw==
 | 
					  integrity sha512-tqgzeZGoZcXzoit4kOGLWJibDMLp0vdm6ZO41SSUQhkhtrPhAg6dbIEPiahhUu6sZAmSYvVrZgEr5aKD51nrLA==
 | 
				
			||||||
  dependencies:
 | 
					  dependencies:
 | 
				
			||||||
    "@vueuse/metadata" "8.3.1"
 | 
					    "@types/web-bluetooth" "^0.0.14"
 | 
				
			||||||
    "@vueuse/shared" "8.3.1"
 | 
					    "@vueuse/metadata" "8.7.5"
 | 
				
			||||||
 | 
					    "@vueuse/shared" "8.7.5"
 | 
				
			||||||
    vue-demi "*"
 | 
					    vue-demi "*"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"@vueuse/metadata@8.3.1":
 | 
					"@vueuse/metadata@8.7.5":
 | 
				
			||||||
  version "8.3.1"
 | 
					  version "8.7.5"
 | 
				
			||||||
  resolved "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-8.3.1.tgz#acc0ff9ad686c68dfc7b4869639c43e71ae2682b"
 | 
					  resolved "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-8.7.5.tgz#c7f2b21d873d1604a8860ed9c5728d8f3295f00a"
 | 
				
			||||||
  integrity sha512-1aZaFL44HzXXkfN6Q7KMDOXBFKTHDClHlOJBxtN8rTBXIIScoGOrJCpxWiQ4kuVg95MzG/pHrd3P4wd8poL9XQ==
 | 
					  integrity sha512-emJZKRQSaEnVqmlu39NpNp8iaW+bPC2kWykWoWOZMSlO/0QVEmO/rt8A5VhOEJTKLX3vwTevqbiRy9WJRwVOQg==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"@vueuse/shared@8.3.1":
 | 
					"@vueuse/shared@8.7.5":
 | 
				
			||||||
  version "8.3.1"
 | 
					  version "8.7.5"
 | 
				
			||||||
  resolved "https://registry.npmmirror.com/@vueuse/shared/-/shared-8.3.1.tgz#a941ef6a0eaf483ecb0e88a062163d506c22cc4b"
 | 
					  resolved "https://registry.npmmirror.com/@vueuse/shared/-/shared-8.7.5.tgz#06fb08f6f8fc9e90be9d1e033fa443de927172b0"
 | 
				
			||||||
  integrity sha512-7HKLCcxp4dtONq6QSSoavblo9riYgqzw7jhqiC0/VUYMXKzqj1G/GznOzTmY8Wi8uKKT197JqjKQ1DKt2j/0+A==
 | 
					  integrity sha512-THXPvMBFmg6Gf6AwRn/EdTh2mhqwjGsB2Yfp374LNQSQVKRHtnJ0I42bsZTn7nuEliBxqUrGQm/lN6qUHmhJLw==
 | 
				
			||||||
  dependencies:
 | 
					  dependencies:
 | 
				
			||||||
    vue-demi "*"
 | 
					    vue-demi "*"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
JSV@^4.0.x:
 | 
					ace-builds@^1.6.0:
 | 
				
			||||||
  version "4.0.2"
 | 
					  version "1.7.1"
 | 
				
			||||||
  resolved "https://registry.npm.taobao.org/JSV/download/JSV-4.0.2.tgz#d077f6825571f82132f9dffaed587b4029feff57"
 | 
					  resolved "https://registry.npmmirror.com/ace-builds/-/ace-builds-1.7.1.tgz#be796fbd98610dda5e138aed98d309cac2ab0872"
 | 
				
			||||||
  integrity sha1-0Hf2glVx+CEy+d/67Vh7QCn+/1c=
 | 
					  integrity sha512-1mcbP5kXvr729sJ9dA/8tul0pjuvKbma0LF/ZMRwPEwjoNWNpe/x0OXpaPJo36aRpZCjRZMl5zsME3hAKTiaNw==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
acorn-jsx@^5.3.1:
 | 
					acorn-jsx@^5.3.1:
 | 
				
			||||||
  version "5.3.2"
 | 
					  version "5.3.2"
 | 
				
			||||||
@@ -385,7 +401,7 @@ acorn@^8.7.0:
 | 
				
			|||||||
  resolved "https://registry.npmmirror.com/acorn/download/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf"
 | 
					  resolved "https://registry.npmmirror.com/acorn/download/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf"
 | 
				
			||||||
  integrity sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==
 | 
					  integrity sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ajv@^6.10.0, ajv@^6.12.4:
 | 
					ajv@^6.10.0, ajv@^6.12.4, ajv@^6.12.6:
 | 
				
			||||||
  version "6.12.6"
 | 
					  version "6.12.6"
 | 
				
			||||||
  resolved "https://registry.npmmirror.com/ajv/download/ajv-6.12.6.tgz?cache=0&sync_timestamp=1637522259668&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fajv%2Fdownload%2Fajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
 | 
					  resolved "https://registry.npmmirror.com/ajv/download/ajv-6.12.6.tgz?cache=0&sync_timestamp=1637522259668&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fajv%2Fdownload%2Fajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
 | 
				
			||||||
  integrity sha1-uvWmLoArB9l3A0WG+MO69a3ybfQ=
 | 
					  integrity sha1-uvWmLoArB9l3A0WG+MO69a3ybfQ=
 | 
				
			||||||
@@ -412,11 +428,6 @@ ansi-styles@^4.1.0:
 | 
				
			|||||||
  dependencies:
 | 
					  dependencies:
 | 
				
			||||||
    color-convert "^2.0.1"
 | 
					    color-convert "^2.0.1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ansi-styles@~1.0.0:
 | 
					 | 
				
			||||||
  version "1.0.0"
 | 
					 | 
				
			||||||
  resolved "https://registry.nlark.com/ansi-styles/download/ansi-styles-1.0.0.tgz#cb102df1c56f5123eab8b67cd7b98027a0279178"
 | 
					 | 
				
			||||||
  integrity sha1-yxAt8cVvUSPquLZ817mAJ6AnkXg=
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
anymatch@~3.1.2:
 | 
					anymatch@~3.1.2:
 | 
				
			||||||
  version "3.1.2"
 | 
					  version "3.1.2"
 | 
				
			||||||
  resolved "https://registry.nlark.com/anymatch/download/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716"
 | 
					  resolved "https://registry.nlark.com/anymatch/download/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716"
 | 
				
			||||||
@@ -435,17 +446,23 @@ array-union@^2.1.0:
 | 
				
			|||||||
  resolved "https://registry.npm.taobao.org/array-union/download/array-union-2.1.0.tgz?cache=0&sync_timestamp=1614624262896&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Farray-union%2Fdownload%2Farray-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d"
 | 
					  resolved "https://registry.npm.taobao.org/array-union/download/array-union-2.1.0.tgz?cache=0&sync_timestamp=1614624262896&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Farray-union%2Fdownload%2Farray-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d"
 | 
				
			||||||
  integrity sha1-t5hCCtvrHego2ErNii4j0+/oXo0=
 | 
					  integrity sha1-t5hCCtvrHego2ErNii4j0+/oXo0=
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async-validator@^4.0.7:
 | 
					async-validator@^4.2.5:
 | 
				
			||||||
  version "4.0.7"
 | 
					  version "4.2.5"
 | 
				
			||||||
  resolved "https://registry.npmmirror.com/async-validator/download/async-validator-4.0.7.tgz?cache=0&sync_timestamp=1634529574100&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fasync-validator%2Fdownload%2Fasync-validator-4.0.7.tgz#034a0fd2103a6b2ebf010da75183bec299247afe"
 | 
					  resolved "https://registry.npmmirror.com/async-validator/-/async-validator-4.2.5.tgz#c96ea3332a521699d0afaaceed510a54656c6339"
 | 
				
			||||||
  integrity sha1-A0oP0hA6ay6/AQ2nUYO+wpkkev4=
 | 
					  integrity sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
axios@^0.26.1:
 | 
					asynckit@^0.4.0:
 | 
				
			||||||
  version "0.26.1"
 | 
					  version "0.4.0"
 | 
				
			||||||
  resolved "https://registry.npmmirror.com/axios/-/axios-0.26.1.tgz#1ede41c51fcf51bbbd6fd43669caaa4f0495aaa9"
 | 
					  resolved "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
 | 
				
			||||||
  integrity sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==
 | 
					  integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					axios@^0.27.2:
 | 
				
			||||||
 | 
					  version "0.27.2"
 | 
				
			||||||
 | 
					  resolved "https://registry.npmmirror.com/axios/-/axios-0.27.2.tgz#207658cc8621606e586c85db4b41a750e756d972"
 | 
				
			||||||
 | 
					  integrity sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==
 | 
				
			||||||
  dependencies:
 | 
					  dependencies:
 | 
				
			||||||
    follow-redirects "^1.14.8"
 | 
					    follow-redirects "^1.14.9"
 | 
				
			||||||
 | 
					    form-data "^4.0.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
balanced-match@^1.0.0:
 | 
					balanced-match@^1.0.0:
 | 
				
			||||||
  version "1.0.2"
 | 
					  version "1.0.2"
 | 
				
			||||||
@@ -485,15 +502,6 @@ chalk@^4.0.0:
 | 
				
			|||||||
    ansi-styles "^4.1.0"
 | 
					    ansi-styles "^4.1.0"
 | 
				
			||||||
    supports-color "^7.1.0"
 | 
					    supports-color "^7.1.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
chalk@~0.4.0:
 | 
					 | 
				
			||||||
  version "0.4.0"
 | 
					 | 
				
			||||||
  resolved "https://registry.npmmirror.com/chalk/download/chalk-0.4.0.tgz#5199a3ddcd0c1efe23bc08c1b027b06176e0c64f"
 | 
					 | 
				
			||||||
  integrity sha1-UZmj3c0MHv4jvAjBsCewYXbgxk8=
 | 
					 | 
				
			||||||
  dependencies:
 | 
					 | 
				
			||||||
    ansi-styles "~1.0.0"
 | 
					 | 
				
			||||||
    has-color "~0.1.0"
 | 
					 | 
				
			||||||
    strip-ansi "~0.1.0"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
"chokidar@>=3.0.0 <4.0.0":
 | 
					"chokidar@>=3.0.0 <4.0.0":
 | 
				
			||||||
  version "3.5.2"
 | 
					  version "3.5.2"
 | 
				
			||||||
  resolved "https://registry.npmmirror.com/chokidar/download/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75"
 | 
					  resolved "https://registry.npmmirror.com/chokidar/download/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75"
 | 
				
			||||||
@@ -518,10 +526,10 @@ clipboard@^2.0.6:
 | 
				
			|||||||
    select "^1.1.2"
 | 
					    select "^1.1.2"
 | 
				
			||||||
    tiny-emitter "^2.0.0"
 | 
					    tiny-emitter "^2.0.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
codemirror@^5.65.2:
 | 
					codemirror@^5.65.5:
 | 
				
			||||||
  version "5.65.3"
 | 
					  version "5.65.5"
 | 
				
			||||||
  resolved "https://registry.npmmirror.com/codemirror/-/codemirror-5.65.3.tgz#2d029930d5a293bc5fb96ceea64654803c0d4ac7"
 | 
					  resolved "https://registry.npmmirror.com/codemirror/-/codemirror-5.65.5.tgz#f38f0e29945c3464df0c81f946fcd9a063fa2024"
 | 
				
			||||||
  integrity sha512-kCC0iwGZOVZXHEKW3NDTObvM7pTIyowjty4BUqeREROc/3I6bWbgZDA3fGDwlA+rbgRjvnRnfqs9SfXynel1AQ==
 | 
					  integrity sha512-HNyhvGLnYz5c+kIsB9QKVitiZUevha3ovbIYaQiGzKo7ECSL/elWD9RXt3JgNr0NdnyqE9/Rc/7uLfkJQL638w==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
color-convert@^2.0.1:
 | 
					color-convert@^2.0.1:
 | 
				
			||||||
  version "2.0.1"
 | 
					  version "2.0.1"
 | 
				
			||||||
@@ -535,6 +543,13 @@ color-name@~1.1.4:
 | 
				
			|||||||
  resolved "https://registry.npm.taobao.org/color-name/download/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
 | 
					  resolved "https://registry.npm.taobao.org/color-name/download/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
 | 
				
			||||||
  integrity sha1-wqCah6y95pVD3m9j+jmVyCbFNqI=
 | 
					  integrity sha1-wqCah6y95pVD3m9j+jmVyCbFNqI=
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					combined-stream@^1.0.8:
 | 
				
			||||||
 | 
					  version "1.0.8"
 | 
				
			||||||
 | 
					  resolved "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
 | 
				
			||||||
 | 
					  integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
 | 
				
			||||||
 | 
					  dependencies:
 | 
				
			||||||
 | 
					    delayed-stream "~1.0.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
concat-map@0.0.1:
 | 
					concat-map@0.0.1:
 | 
				
			||||||
  version "0.0.1"
 | 
					  version "0.0.1"
 | 
				
			||||||
  resolved "https://registry.npm.taobao.org/concat-map/download/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
 | 
					  resolved "https://registry.npm.taobao.org/concat-map/download/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
 | 
				
			||||||
@@ -564,10 +579,10 @@ csstype@^2.6.8:
 | 
				
			|||||||
  resolved "https://registry.npmmirror.com/csstype/download/csstype-2.6.19.tgz?cache=0&sync_timestamp=1637224514674&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fcsstype%2Fdownload%2Fcsstype-2.6.19.tgz#feeb5aae89020bb389e1f63669a5ed490e391caa"
 | 
					  resolved "https://registry.npmmirror.com/csstype/download/csstype-2.6.19.tgz?cache=0&sync_timestamp=1637224514674&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fcsstype%2Fdownload%2Fcsstype-2.6.19.tgz#feeb5aae89020bb389e1f63669a5ed490e391caa"
 | 
				
			||||||
  integrity sha512-ZVxXaNy28/k3kJg0Fou5MiYpp88j7H9hLZp8PDC3jV0WFjfH5E9xHb56L0W59cPbKbcHXeP4qyT8PrHp8t6LcQ==
 | 
					  integrity sha512-ZVxXaNy28/k3kJg0Fou5MiYpp88j7H9hLZp8PDC3jV0WFjfH5E9xHb56L0W59cPbKbcHXeP4qyT8PrHp8t6LcQ==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
dayjs@^1.11.1:
 | 
					dayjs@^1.11.3:
 | 
				
			||||||
  version "1.11.1"
 | 
					  version "1.11.3"
 | 
				
			||||||
  resolved "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.1.tgz#90b33a3dda3417258d48ad2771b415def6545eb0"
 | 
					  resolved "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.3.tgz#4754eb694a624057b9ad2224b67b15d552589258"
 | 
				
			||||||
  integrity sha512-ER7EjqVAMkRRsxNCC5YqJ9d9VQYuWdGt7aiH2qA5R5wt8ZmWaP2dLUSIK6y/kVzLMlmh1Tvu5xUf4M/wdGJ5KA==
 | 
					  integrity sha512-xxwlswWOlGhzgQ4TKzASQkUhqERI3egRNqgV4ScR8wlANA/A9tZ7miXa44vTTKEq5l7vWoL5G57bG3zA+Kow0A==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
debug@^4.1.1, debug@^4.3.1, debug@^4.3.2:
 | 
					debug@^4.1.1, debug@^4.3.1, debug@^4.3.2:
 | 
				
			||||||
  version "4.3.3"
 | 
					  version "4.3.3"
 | 
				
			||||||
@@ -581,6 +596,11 @@ deep-is@^0.1.3:
 | 
				
			|||||||
  resolved "https://registry.nlark.com/deep-is/download/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831"
 | 
					  resolved "https://registry.nlark.com/deep-is/download/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831"
 | 
				
			||||||
  integrity sha1-pvLc5hL63S7x9Rm3NVHxfoUZmDE=
 | 
					  integrity sha1-pvLc5hL63S7x9Rm3NVHxfoUZmDE=
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					delayed-stream@~1.0.0:
 | 
				
			||||||
 | 
					  version "1.0.0"
 | 
				
			||||||
 | 
					  resolved "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
 | 
				
			||||||
 | 
					  integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
delegate@^3.1.2:
 | 
					delegate@^3.1.2:
 | 
				
			||||||
  version "3.2.0"
 | 
					  version "3.2.0"
 | 
				
			||||||
  resolved "https://registry.nlark.com/delegate/download/delegate-3.2.0.tgz#b66b71c3158522e8ab5744f720d8ca0c2af59166"
 | 
					  resolved "https://registry.nlark.com/delegate/download/delegate-3.2.0.tgz#b66b71c3158522e8ab5744f720d8ca0c2af59166"
 | 
				
			||||||
@@ -605,28 +625,28 @@ dotenv@^10.0.0:
 | 
				
			|||||||
  resolved "https://registry.nlark.com/dotenv/download/dotenv-10.0.0.tgz#3d4227b8fb95f81096cdd2b66653fb2c7085ba81"
 | 
					  resolved "https://registry.nlark.com/dotenv/download/dotenv-10.0.0.tgz#3d4227b8fb95f81096cdd2b66653fb2c7085ba81"
 | 
				
			||||||
  integrity sha1-PUInuPuV+BCWzdK2ZlP7LHCFuoE=
 | 
					  integrity sha1-PUInuPuV+BCWzdK2ZlP7LHCFuoE=
 | 
				
			||||||
 | 
					
 | 
				
			||||||
echarts@^5.3.2:
 | 
					echarts@^5.3.3:
 | 
				
			||||||
  version "5.3.2"
 | 
					  version "5.3.3"
 | 
				
			||||||
  resolved "https://registry.npmmirror.com/echarts/-/echarts-5.3.2.tgz#0a7b3be8c48a48b2e7cb1b82121df0c208d42d2c"
 | 
					  resolved "https://registry.npmmirror.com/echarts/-/echarts-5.3.3.tgz#df97b09c4c0e2ffcdfb44acf518d50c50e0b838e"
 | 
				
			||||||
  integrity sha512-LWCt7ohOKdJqyiBJ0OGBmE9szLdfA9sGcsMEi+GGoc6+Xo75C+BkcT/6NNGRHAWtnQl2fNow05AQjznpap28TQ==
 | 
					  integrity sha512-BRw2serInRwO5SIwRviZ6Xgm5Lb7irgz+sLiFMmy/HOaf4SQ+7oYqxKzRHAKp4xHQ05AuHw1xvoQWJjDQq/FGw==
 | 
				
			||||||
  dependencies:
 | 
					  dependencies:
 | 
				
			||||||
    tslib "2.3.0"
 | 
					    tslib "2.3.0"
 | 
				
			||||||
    zrender "5.3.1"
 | 
					    zrender "5.3.2"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
element-plus@^2.1.11:
 | 
					element-plus@^2.2.8:
 | 
				
			||||||
  version "2.1.11"
 | 
					  version "2.2.8"
 | 
				
			||||||
  resolved "https://registry.npmmirror.com/element-plus/-/element-plus-2.1.11.tgz#6c1be29f5d78ea78720e0dda519960fd0c7d8fde"
 | 
					  resolved "https://registry.npmmirror.com/element-plus/-/element-plus-2.2.8.tgz#6bba6285c20d8bea42247977d8f605611fc2da93"
 | 
				
			||||||
  integrity sha512-s4X0I8s787tv+9UdekBC1g7v42Fj4bucPAmu03EjbgrGrV7BJvkoBGuK52lNfu4yC76bl6Uyjesd5Fu8CMakSw==
 | 
					  integrity sha512-+cubFh1rgeGcc2LeBm7hv/1BKFJre/LIIdRntm9OLaIhysCxigjEwcxk9gbVT4KsbcjmoqZUr4/mwhIhQV6mvw==
 | 
				
			||||||
  dependencies:
 | 
					  dependencies:
 | 
				
			||||||
    "@ctrl/tinycolor" "^3.4.1"
 | 
					    "@ctrl/tinycolor" "^3.4.1"
 | 
				
			||||||
    "@element-plus/icons-vue" "^1.1.4"
 | 
					    "@element-plus/icons-vue" "^2.0.6"
 | 
				
			||||||
    "@floating-ui/dom" "^0.4.5"
 | 
					    "@floating-ui/dom" "^0.5.4"
 | 
				
			||||||
    "@popperjs/core" "npm:@sxzz/popperjs-es@^2.11.6"
 | 
					    "@popperjs/core" "npm:@sxzz/popperjs-es@^2.11.7"
 | 
				
			||||||
    "@types/lodash" "^4.14.182"
 | 
					    "@types/lodash" "^4.14.182"
 | 
				
			||||||
    "@types/lodash-es" "^4.17.6"
 | 
					    "@types/lodash-es" "^4.17.6"
 | 
				
			||||||
    "@vueuse/core" "^8.2.6"
 | 
					    "@vueuse/core" "^8.7.5"
 | 
				
			||||||
    async-validator "^4.0.7"
 | 
					    async-validator "^4.2.5"
 | 
				
			||||||
    dayjs "^1.11.1"
 | 
					    dayjs "^1.11.3"
 | 
				
			||||||
    escape-html "^1.0.3"
 | 
					    escape-html "^1.0.3"
 | 
				
			||||||
    lodash "^4.17.21"
 | 
					    lodash "^4.17.21"
 | 
				
			||||||
    lodash-es "^4.17.21"
 | 
					    lodash-es "^4.17.21"
 | 
				
			||||||
@@ -975,10 +995,19 @@ flatted@^3.1.0:
 | 
				
			|||||||
  resolved "https://registry.npmmirror.com/flatted/download/flatted-3.2.4.tgz#28d9969ea90661b5134259f312ab6aa7929ac5e2"
 | 
					  resolved "https://registry.npmmirror.com/flatted/download/flatted-3.2.4.tgz#28d9969ea90661b5134259f312ab6aa7929ac5e2"
 | 
				
			||||||
  integrity sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw==
 | 
					  integrity sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
follow-redirects@^1.14.8:
 | 
					follow-redirects@^1.14.9:
 | 
				
			||||||
  version "1.14.9"
 | 
					  version "1.15.1"
 | 
				
			||||||
  resolved "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.14.9.tgz#dd4ea157de7bfaf9ea9b3fbd85aa16951f78d8d7"
 | 
					  resolved "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.1.tgz#0ca6a452306c9b276e4d3127483e29575e207ad5"
 | 
				
			||||||
  integrity sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==
 | 
					  integrity sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					form-data@^4.0.0:
 | 
				
			||||||
 | 
					  version "4.0.0"
 | 
				
			||||||
 | 
					  resolved "https://registry.npmmirror.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452"
 | 
				
			||||||
 | 
					  integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==
 | 
				
			||||||
 | 
					  dependencies:
 | 
				
			||||||
 | 
					    asynckit "^0.4.0"
 | 
				
			||||||
 | 
					    combined-stream "^1.0.8"
 | 
				
			||||||
 | 
					    mime-types "^2.1.12"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fs.realpath@^1.0.0:
 | 
					fs.realpath@^1.0.0:
 | 
				
			||||||
  version "1.0.0"
 | 
					  version "1.0.0"
 | 
				
			||||||
@@ -1052,11 +1081,6 @@ good-listener@^1.2.2:
 | 
				
			|||||||
  dependencies:
 | 
					  dependencies:
 | 
				
			||||||
    delegate "^3.1.2"
 | 
					    delegate "^3.1.2"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
has-color@~0.1.0:
 | 
					 | 
				
			||||||
  version "0.1.7"
 | 
					 | 
				
			||||||
  resolved "https://registry.npmmirror.com/has-color/download/has-color-0.1.7.tgz#67144a5260c34fc3cca677d041daf52fe7b78b2f"
 | 
					 | 
				
			||||||
  integrity sha1-ZxRKUmDDT8PMpnfQQdr1L+e3iy8=
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
has-flag@^4.0.0:
 | 
					has-flag@^4.0.0:
 | 
				
			||||||
  version "4.0.0"
 | 
					  version "4.0.0"
 | 
				
			||||||
  resolved "https://registry.nlark.com/has-flag/download/has-flag-4.0.0.tgz?cache=0&sync_timestamp=1626715907927&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fhas-flag%2Fdownload%2Fhas-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
 | 
					  resolved "https://registry.nlark.com/has-flag/download/has-flag-4.0.0.tgz?cache=0&sync_timestamp=1626715907927&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fhas-flag%2Fdownload%2Fhas-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
 | 
				
			||||||
@@ -1146,6 +1170,16 @@ isexe@^2.0.0:
 | 
				
			|||||||
  resolved "https://registry.npm.taobao.org/isexe/download/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
 | 
					  resolved "https://registry.npm.taobao.org/isexe/download/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
 | 
				
			||||||
  integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
 | 
					  integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					javascript-natural-sort@^0.7.1:
 | 
				
			||||||
 | 
					  version "0.7.1"
 | 
				
			||||||
 | 
					  resolved "https://registry.npmmirror.com/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz#f9e2303d4507f6d74355a73664d1440fb5a0ef59"
 | 
				
			||||||
 | 
					  integrity sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					jmespath@^0.16.0:
 | 
				
			||||||
 | 
					  version "0.16.0"
 | 
				
			||||||
 | 
					  resolved "https://registry.npmmirror.com/jmespath/-/jmespath-0.16.0.tgz#b15b0a85dfd4d930d43e69ed605943c802785076"
 | 
				
			||||||
 | 
					  integrity sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
js-yaml@^4.1.0:
 | 
					js-yaml@^4.1.0:
 | 
				
			||||||
  version "4.1.0"
 | 
					  version "4.1.0"
 | 
				
			||||||
  resolved "https://registry.npmmirror.com/js-yaml/download/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
 | 
					  resolved "https://registry.npmmirror.com/js-yaml/download/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
 | 
				
			||||||
@@ -1158,18 +1192,35 @@ json-schema-traverse@^0.4.1:
 | 
				
			|||||||
  resolved "https://registry.npm.taobao.org/json-schema-traverse/download/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
 | 
					  resolved "https://registry.npm.taobao.org/json-schema-traverse/download/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
 | 
				
			||||||
  integrity sha1-afaofZUTq4u4/mO9sJecRI5oRmA=
 | 
					  integrity sha1-afaofZUTq4u4/mO9sJecRI5oRmA=
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					json-source-map@^0.6.1:
 | 
				
			||||||
 | 
					  version "0.6.1"
 | 
				
			||||||
 | 
					  resolved "https://registry.npmmirror.com/json-source-map/-/json-source-map-0.6.1.tgz#e0b1f6f4ce13a9ad57e2ae165a24d06e62c79a0f"
 | 
				
			||||||
 | 
					  integrity sha512-1QoztHPsMQqhDq0hlXY5ZqcEdUzxQEIxgFkKl4WUp2pgShObl+9ovi4kRh2TfvAfxAoHOJ9vIMEqk3k4iex7tg==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
json-stable-stringify-without-jsonify@^1.0.1:
 | 
					json-stable-stringify-without-jsonify@^1.0.1:
 | 
				
			||||||
  version "1.0.1"
 | 
					  version "1.0.1"
 | 
				
			||||||
  resolved "https://registry.nlark.com/json-stable-stringify-without-jsonify/download/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
 | 
					  resolved "https://registry.nlark.com/json-stable-stringify-without-jsonify/download/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
 | 
				
			||||||
  integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=
 | 
					  integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=
 | 
				
			||||||
 | 
					
 | 
				
			||||||
jsonlint@^1.6.3:
 | 
					jsoneditor@^9.9.0:
 | 
				
			||||||
  version "1.6.3"
 | 
					  version "9.9.0"
 | 
				
			||||||
  resolved "https://registry.npm.taobao.org/jsonlint/download/jsonlint-1.6.3.tgz#cb5e31efc0b78291d0d862fbef05900adf212988"
 | 
					  resolved "https://registry.npmmirror.com/jsoneditor/-/jsoneditor-9.9.0.tgz#671e1231e23c43ebc6e1eb43fe97b2f97b156faf"
 | 
				
			||||||
  integrity sha1-y14x78C3gpHQ2GL77wWQCt8hKYg=
 | 
					  integrity sha512-NHJhyaqcc5U33ah6dEcd0S9b14Auocpe9nydvC9ui7Uq/vjEFnsd7ot6O9Jqwv53B7DmHFUWq5cT4qeWh4MEoA==
 | 
				
			||||||
  dependencies:
 | 
					  dependencies:
 | 
				
			||||||
    JSV "^4.0.x"
 | 
					    ace-builds "^1.6.0"
 | 
				
			||||||
    nomnom "^1.5.x"
 | 
					    ajv "^6.12.6"
 | 
				
			||||||
 | 
					    javascript-natural-sort "^0.7.1"
 | 
				
			||||||
 | 
					    jmespath "^0.16.0"
 | 
				
			||||||
 | 
					    json-source-map "^0.6.1"
 | 
				
			||||||
 | 
					    jsonrepair "^2.2.1"
 | 
				
			||||||
 | 
					    mobius1-selectr "^2.4.13"
 | 
				
			||||||
 | 
					    picomodal "^3.0.0"
 | 
				
			||||||
 | 
					    vanilla-picker "^2.12.1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					jsonrepair@^2.2.1:
 | 
				
			||||||
 | 
					  version "2.2.1"
 | 
				
			||||||
 | 
					  resolved "https://registry.npmmirror.com/jsonrepair/-/jsonrepair-2.2.1.tgz#7c6257c36550a310150c41ab7d5d4cab71828456"
 | 
				
			||||||
 | 
					  integrity sha512-o9Je8TceILo872uQC9fIBJm957j1Io7z8Ca1iWIqY6S5S65HGE9XN7XEEw7+tUviB9Vq4sygV89MVTxl+rhZyg==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
klona@^2.0.4:
 | 
					klona@^2.0.4:
 | 
				
			||||||
  version "2.0.5"
 | 
					  version "2.0.5"
 | 
				
			||||||
@@ -1236,6 +1287,18 @@ micromatch@^4.0.4:
 | 
				
			|||||||
    braces "^3.0.1"
 | 
					    braces "^3.0.1"
 | 
				
			||||||
    picomatch "^2.2.3"
 | 
					    picomatch "^2.2.3"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					mime-db@1.52.0:
 | 
				
			||||||
 | 
					  version "1.52.0"
 | 
				
			||||||
 | 
					  resolved "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
 | 
				
			||||||
 | 
					  integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					mime-types@^2.1.12:
 | 
				
			||||||
 | 
					  version "2.1.35"
 | 
				
			||||||
 | 
					  resolved "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
 | 
				
			||||||
 | 
					  integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
 | 
				
			||||||
 | 
					  dependencies:
 | 
				
			||||||
 | 
					    mime-db "1.52.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
minimatch@^3.0.4:
 | 
					minimatch@^3.0.4:
 | 
				
			||||||
  version "3.0.4"
 | 
					  version "3.0.4"
 | 
				
			||||||
  resolved "https://registry.npm.taobao.org/minimatch/download/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
 | 
					  resolved "https://registry.npm.taobao.org/minimatch/download/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
 | 
				
			||||||
@@ -1248,6 +1311,11 @@ mitt@^3.0.0:
 | 
				
			|||||||
  resolved "https://registry.npmmirror.com/mitt/download/mitt-3.0.0.tgz#69ef9bd5c80ff6f57473e8d89326d01c414be0bd"
 | 
					  resolved "https://registry.npmmirror.com/mitt/download/mitt-3.0.0.tgz#69ef9bd5c80ff6f57473e8d89326d01c414be0bd"
 | 
				
			||||||
  integrity sha512-7dX2/10ITVyqh4aOSVI9gdape+t9l2/8QxHrFmUXu4EEUpdlxl6RudZUPZoc+zuY2hk1j7XxVroIVIan/pD/SQ==
 | 
					  integrity sha512-7dX2/10ITVyqh4aOSVI9gdape+t9l2/8QxHrFmUXu4EEUpdlxl6RudZUPZoc+zuY2hk1j7XxVroIVIan/pD/SQ==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					mobius1-selectr@^2.4.13:
 | 
				
			||||||
 | 
					  version "2.4.13"
 | 
				
			||||||
 | 
					  resolved "https://registry.npmmirror.com/mobius1-selectr/-/mobius1-selectr-2.4.13.tgz#0019dfd9f984840d6e40f70683ab3ec78ce3b5df"
 | 
				
			||||||
 | 
					  integrity sha512-Mk9qDrvU44UUL0EBhbAA1phfQZ7aMZPjwtL7wkpiBzGh8dETGqfsh50mWoX9EkjDlkONlErWXArHCKfoxVg0Bw==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ms@2.1.2:
 | 
					ms@2.1.2:
 | 
				
			||||||
  version "2.1.2"
 | 
					  version "2.1.2"
 | 
				
			||||||
  resolved "https://registry.npmmirror.com/ms/download/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
 | 
					  resolved "https://registry.npmmirror.com/ms/download/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
 | 
				
			||||||
@@ -1258,10 +1326,10 @@ nanoid@^3.1.30:
 | 
				
			|||||||
  resolved "https://registry.npmmirror.com/nanoid/download/nanoid-3.1.30.tgz#63f93cc548d2a113dc5dfbc63bfa09e2b9b64362"
 | 
					  resolved "https://registry.npmmirror.com/nanoid/download/nanoid-3.1.30.tgz#63f93cc548d2a113dc5dfbc63bfa09e2b9b64362"
 | 
				
			||||||
  integrity sha1-Y/k8xUjSoRPcXfvGO/oJ4rm2Q2I=
 | 
					  integrity sha1-Y/k8xUjSoRPcXfvGO/oJ4rm2Q2I=
 | 
				
			||||||
 | 
					
 | 
				
			||||||
nanoid@^3.3.1:
 | 
					nanoid@^3.3.4:
 | 
				
			||||||
  version "3.3.3"
 | 
					  version "3.3.4"
 | 
				
			||||||
  resolved "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.3.tgz#fd8e8b7aa761fe807dba2d1b98fb7241bb724a25"
 | 
					  resolved "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab"
 | 
				
			||||||
  integrity sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==
 | 
					  integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
natural-compare@^1.4.0:
 | 
					natural-compare@^1.4.0:
 | 
				
			||||||
  version "1.4.0"
 | 
					  version "1.4.0"
 | 
				
			||||||
@@ -1273,14 +1341,6 @@ neo-async@^2.6.2:
 | 
				
			|||||||
  resolved "https://registry.npm.taobao.org/neo-async/download/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f"
 | 
					  resolved "https://registry.npm.taobao.org/neo-async/download/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f"
 | 
				
			||||||
  integrity sha1-tKr7k+OustgXTKU88WOrfXMIMF8=
 | 
					  integrity sha1-tKr7k+OustgXTKU88WOrfXMIMF8=
 | 
				
			||||||
 | 
					
 | 
				
			||||||
nomnom@^1.5.x:
 | 
					 | 
				
			||||||
  version "1.8.1"
 | 
					 | 
				
			||||||
  resolved "https://registry.npm.taobao.org/nomnom/download/nomnom-1.8.1.tgz#2151f722472ba79e50a76fc125bb8c8f2e4dc2a7"
 | 
					 | 
				
			||||||
  integrity sha1-IVH3Ikcrp55Qp2/BJbuMjy5Nwqc=
 | 
					 | 
				
			||||||
  dependencies:
 | 
					 | 
				
			||||||
    chalk "~0.4.0"
 | 
					 | 
				
			||||||
    underscore "~1.6.0"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
normalize-path@^3.0.0, normalize-path@~3.0.0:
 | 
					normalize-path@^3.0.0, normalize-path@~3.0.0:
 | 
				
			||||||
  version "3.0.0"
 | 
					  version "3.0.0"
 | 
				
			||||||
  resolved "https://registry.npm.taobao.org/normalize-path/download/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
 | 
					  resolved "https://registry.npm.taobao.org/normalize-path/download/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
 | 
				
			||||||
@@ -1352,6 +1412,11 @@ picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3:
 | 
				
			|||||||
  resolved "https://registry.nlark.com/picomatch/download/picomatch-2.3.0.tgz?cache=0&sync_timestamp=1621648246651&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpicomatch%2Fdownload%2Fpicomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972"
 | 
					  resolved "https://registry.nlark.com/picomatch/download/picomatch-2.3.0.tgz?cache=0&sync_timestamp=1621648246651&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpicomatch%2Fdownload%2Fpicomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972"
 | 
				
			||||||
  integrity sha1-8fBh3o9qS/AiiS4tEoI0+5gwKXI=
 | 
					  integrity sha1-8fBh3o9qS/AiiS4tEoI0+5gwKXI=
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					picomodal@^3.0.0:
 | 
				
			||||||
 | 
					  version "3.0.0"
 | 
				
			||||||
 | 
					  resolved "https://registry.npmmirror.com/picomodal/-/picomodal-3.0.0.tgz#facd30f4fbf34a809c1e04ea525f004f399c0b82"
 | 
				
			||||||
 | 
					  integrity sha512-FoR3TDfuLlqUvcEeK5ifpKSVVns6B4BQvc8SDF6THVMuadya6LLtji0QgUDSStw0ZR2J7I6UGi5V2V23rnPWTw==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
postcss@^8.1.10:
 | 
					postcss@^8.1.10:
 | 
				
			||||||
  version "8.4.5"
 | 
					  version "8.4.5"
 | 
				
			||||||
  resolved "https://registry.npmmirror.com/postcss/download/postcss-8.4.5.tgz#bae665764dfd4c6fcc24dc0fdf7e7aa00cc77f95"
 | 
					  resolved "https://registry.npmmirror.com/postcss/download/postcss-8.4.5.tgz#bae665764dfd4c6fcc24dc0fdf7e7aa00cc77f95"
 | 
				
			||||||
@@ -1361,12 +1426,12 @@ postcss@^8.1.10:
 | 
				
			|||||||
    picocolors "^1.0.0"
 | 
					    picocolors "^1.0.0"
 | 
				
			||||||
    source-map-js "^1.0.1"
 | 
					    source-map-js "^1.0.1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
postcss@^8.4.12:
 | 
					postcss@^8.4.13:
 | 
				
			||||||
  version "8.4.12"
 | 
					  version "8.4.14"
 | 
				
			||||||
  resolved "https://registry.npmmirror.com/postcss/-/postcss-8.4.12.tgz#1e7de78733b28970fa4743f7da6f3763648b1905"
 | 
					  resolved "https://registry.npmmirror.com/postcss/-/postcss-8.4.14.tgz#ee9274d5622b4858c1007a74d76e42e56fd21caf"
 | 
				
			||||||
  integrity sha512-lg6eITwYe9v6Hr5CncVbK70SoioNQIq81nsaG86ev5hAidQvmOeETBqs7jm43K2F5/Ley3ytDtriImV6TpNiSg==
 | 
					  integrity sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==
 | 
				
			||||||
  dependencies:
 | 
					  dependencies:
 | 
				
			||||||
    nanoid "^3.3.1"
 | 
					    nanoid "^3.3.4"
 | 
				
			||||||
    picocolors "^1.0.0"
 | 
					    picocolors "^1.0.0"
 | 
				
			||||||
    source-map-js "^1.0.2"
 | 
					    source-map-js "^1.0.2"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1523,10 +1588,10 @@ sourcemap-codec@^1.4.4:
 | 
				
			|||||||
  resolved "https://registry.npm.taobao.org/sourcemap-codec/download/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4"
 | 
					  resolved "https://registry.npm.taobao.org/sourcemap-codec/download/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4"
 | 
				
			||||||
  integrity sha1-6oBL2UhXQC5pktBaOO8a41qatMQ=
 | 
					  integrity sha1-6oBL2UhXQC5pktBaOO8a41qatMQ=
 | 
				
			||||||
 | 
					
 | 
				
			||||||
sql-formatter@^4.0.2:
 | 
					sql-formatter@^7.0.3:
 | 
				
			||||||
  version "4.0.2"
 | 
					  version "7.0.3"
 | 
				
			||||||
  resolved "https://registry.npm.taobao.org/sql-formatter/download/sql-formatter-4.0.2.tgz#2b359e5a4c611498d327b9659da7329d71724607"
 | 
					  resolved "https://registry.npmmirror.com/sql-formatter/-/sql-formatter-7.0.3.tgz#6c78f1e550cfa8419fa6f50c2c6140178484c3a7"
 | 
				
			||||||
  integrity sha1-KzWeWkxhFJjTJ7llnacynXFyRgc=
 | 
					  integrity sha512-E9zotLB0dy9ZZhs1sY4ZqzSzJGF2uC4Vzj0mEzXJC9rlE+Jjmz6t64qT2dzm/IPQosYvZknDbBOrWkygIJz67A==
 | 
				
			||||||
  dependencies:
 | 
					  dependencies:
 | 
				
			||||||
    argparse "^2.0.1"
 | 
					    argparse "^2.0.1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1537,11 +1602,6 @@ strip-ansi@^6.0.1:
 | 
				
			|||||||
  dependencies:
 | 
					  dependencies:
 | 
				
			||||||
    ansi-regex "^5.0.1"
 | 
					    ansi-regex "^5.0.1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
strip-ansi@~0.1.0:
 | 
					 | 
				
			||||||
  version "0.1.1"
 | 
					 | 
				
			||||||
  resolved "https://registry.npmmirror.com/strip-ansi/download/strip-ansi-0.1.1.tgz#39e8a98d044d150660abe4a6808acf70bb7bc991"
 | 
					 | 
				
			||||||
  integrity sha1-OeipjQRNFQZgq+SmgIrPcLt7yZE=
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
strip-json-comments@^3.1.0, strip-json-comments@^3.1.1:
 | 
					strip-json-comments@^3.1.0, strip-json-comments@^3.1.1:
 | 
				
			||||||
  version "3.1.1"
 | 
					  version "3.1.1"
 | 
				
			||||||
  resolved "https://registry.nlark.com/strip-json-comments/download/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
 | 
					  resolved "https://registry.nlark.com/strip-json-comments/download/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
 | 
				
			||||||
@@ -1605,15 +1665,10 @@ type-fest@^0.20.2:
 | 
				
			|||||||
  resolved "https://registry.npmmirror.com/type-fest/download/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4"
 | 
					  resolved "https://registry.npmmirror.com/type-fest/download/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4"
 | 
				
			||||||
  integrity sha1-G/IH9LKPkVg2ZstfvTJ4hzAc1fQ=
 | 
					  integrity sha1-G/IH9LKPkVg2ZstfvTJ4hzAc1fQ=
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typescript@^4.2.4:
 | 
					typescript@^4.7.4:
 | 
				
			||||||
  version "4.5.4"
 | 
					  version "4.7.4"
 | 
				
			||||||
  resolved "https://registry.npmmirror.com/typescript/download/typescript-4.5.4.tgz#a17d3a0263bf5c8723b9c52f43c5084edf13c2e8"
 | 
					  resolved "https://registry.npmmirror.com/typescript/-/typescript-4.7.4.tgz#1a88596d1cf47d59507a1bcdfb5b9dfe4d488235"
 | 
				
			||||||
  integrity sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg==
 | 
					  integrity sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==
 | 
				
			||||||
 | 
					 | 
				
			||||||
underscore@~1.6.0:
 | 
					 | 
				
			||||||
  version "1.6.0"
 | 
					 | 
				
			||||||
  resolved "https://registry.npmmirror.com/underscore/download/underscore-1.6.0.tgz#8b38b10cacdef63337b8b24e4ff86d45aea529a8"
 | 
					 | 
				
			||||||
  integrity sha1-izixDKze9jM3uLJOT/htRa6lKag=
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
uri-js@^4.2.2:
 | 
					uri-js@^4.2.2:
 | 
				
			||||||
  version "4.4.1"
 | 
					  version "4.4.1"
 | 
				
			||||||
@@ -1627,13 +1682,20 @@ v8-compile-cache@^2.0.3:
 | 
				
			|||||||
  resolved "https://registry.nlark.com/v8-compile-cache/download/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee"
 | 
					  resolved "https://registry.nlark.com/v8-compile-cache/download/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee"
 | 
				
			||||||
  integrity sha1-LeGWGMZtwkfc+2+ZM4A12CRaLO4=
 | 
					  integrity sha1-LeGWGMZtwkfc+2+ZM4A12CRaLO4=
 | 
				
			||||||
 | 
					
 | 
				
			||||||
vite@^2.8.6:
 | 
					vanilla-picker@^2.12.1:
 | 
				
			||||||
  version "2.9.5"
 | 
					  version "2.12.1"
 | 
				
			||||||
  resolved "https://registry.npmmirror.com/vite/-/vite-2.9.5.tgz#08ef37ac7a6d879c96f328b791732c9a00ea25ea"
 | 
					  resolved "https://registry.npmmirror.com/vanilla-picker/-/vanilla-picker-2.12.1.tgz#6e619eecf553891b8d2d042b745a23c91f19f34c"
 | 
				
			||||||
  integrity sha512-dvMN64X2YEQgSXF1lYabKXw3BbN6e+BL67+P3Vy4MacnY+UzT1AfkHiioFSi9+uiDUiaDy7Ax/LQqivk6orilg==
 | 
					  integrity sha512-2qrEP9VYylKXbyzXKsbu2dferBTvqnlsr29XjHwFE+/MEp0VNj6oEUESLDtKZ7DWzGdSv1x/+ujqFZF+KsO3cg==
 | 
				
			||||||
 | 
					  dependencies:
 | 
				
			||||||
 | 
					    "@sphinxxxx/color-conversion" "^2.2.2"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					vite@^2.9.13:
 | 
				
			||||||
 | 
					  version "2.9.13"
 | 
				
			||||||
 | 
					  resolved "https://registry.npmmirror.com/vite/-/vite-2.9.13.tgz#859cb5d4c316c0d8c6ec9866045c0f7858ca6abc"
 | 
				
			||||||
 | 
					  integrity sha512-AsOBAaT0AD7Mhe8DuK+/kE4aWYFMx/i0ZNi98hJclxb4e0OhQcZYUrvLjIaQ8e59Ui7txcvKMiJC1yftqpQoDw==
 | 
				
			||||||
  dependencies:
 | 
					  dependencies:
 | 
				
			||||||
    esbuild "^0.14.27"
 | 
					    esbuild "^0.14.27"
 | 
				
			||||||
    postcss "^8.4.12"
 | 
					    postcss "^8.4.13"
 | 
				
			||||||
    resolve "^1.22.0"
 | 
					    resolve "^1.22.0"
 | 
				
			||||||
    rollup "^2.59.0"
 | 
					    rollup "^2.59.0"
 | 
				
			||||||
  optionalDependencies:
 | 
					  optionalDependencies:
 | 
				
			||||||
@@ -1664,23 +1726,23 @@ vue-eslint-parser@^8.0.1:
 | 
				
			|||||||
    lodash "^4.17.21"
 | 
					    lodash "^4.17.21"
 | 
				
			||||||
    semver "^7.3.5"
 | 
					    semver "^7.3.5"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
vue-router@^4.0.12:
 | 
					vue-router@^4.0.16:
 | 
				
			||||||
  version "4.0.12"
 | 
					  version "4.0.16"
 | 
				
			||||||
  resolved "https://registry.npmmirror.com/vue-router/download/vue-router-4.0.12.tgz#8dc792cddf5bb1abcc3908f9064136de7e13c460"
 | 
					  resolved "https://registry.npmmirror.com/vue-router/-/vue-router-4.0.16.tgz#9477beeeef36e80e04d041a1738801a55e6e862e"
 | 
				
			||||||
  integrity sha512-CPXvfqe+mZLB1kBWssssTiWg4EQERyqJZes7USiqfW9B5N2x+nHlnsM1D3b5CaJ6qgCvMmYJnz+G0iWjNCvXrg==
 | 
					  integrity sha512-JcO7cb8QJLBWE+DfxGUL3xUDOae/8nhM1KVdnudadTAORbuxIC/xAydC5Zr/VLHUDQi1ppuTF5/rjBGzgzrJNA==
 | 
				
			||||||
  dependencies:
 | 
					  dependencies:
 | 
				
			||||||
    "@vue/devtools-api" "^6.0.0-beta.18"
 | 
					    "@vue/devtools-api" "^6.0.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
vue@^3.2.30:
 | 
					vue@^3.2.37:
 | 
				
			||||||
  version "3.2.33"
 | 
					  version "3.2.37"
 | 
				
			||||||
  resolved "https://registry.npmmirror.com/vue/-/vue-3.2.33.tgz#7867eb16a3293a28c4d190a837bc447878bd64c2"
 | 
					  resolved "https://registry.npmmirror.com/vue/-/vue-3.2.37.tgz#da220ccb618d78579d25b06c7c21498ca4e5452e"
 | 
				
			||||||
  integrity sha512-si1ExAlDUrLSIg/V7D/GgA4twJwfsfgG+t9w10z38HhL/HA07132pUQ2KuwAo8qbCyMJ9e6OqrmWrOCr+jW7ZQ==
 | 
					  integrity sha512-bOKEZxrm8Eh+fveCqS1/NkG/n6aMidsI6hahas7pa0w/l7jkbssJVsRhVDs07IdDq7h9KHswZOgItnwJAgtVtQ==
 | 
				
			||||||
  dependencies:
 | 
					  dependencies:
 | 
				
			||||||
    "@vue/compiler-dom" "3.2.33"
 | 
					    "@vue/compiler-dom" "3.2.37"
 | 
				
			||||||
    "@vue/compiler-sfc" "3.2.33"
 | 
					    "@vue/compiler-sfc" "3.2.37"
 | 
				
			||||||
    "@vue/runtime-dom" "3.2.33"
 | 
					    "@vue/runtime-dom" "3.2.37"
 | 
				
			||||||
    "@vue/server-renderer" "3.2.33"
 | 
					    "@vue/server-renderer" "3.2.37"
 | 
				
			||||||
    "@vue/shared" "3.2.33"
 | 
					    "@vue/shared" "3.2.37"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
vuex@^4.0.2:
 | 
					vuex@^4.0.2:
 | 
				
			||||||
  version "4.0.2"
 | 
					  version "4.0.2"
 | 
				
			||||||
@@ -1711,19 +1773,19 @@ xterm-addon-fit@^0.5.0:
 | 
				
			|||||||
  resolved "https://registry.npmmirror.com/xterm-addon-fit/download/xterm-addon-fit-0.5.0.tgz#2d51b983b786a97dcd6cde805e700c7f913bc596"
 | 
					  resolved "https://registry.npmmirror.com/xterm-addon-fit/download/xterm-addon-fit-0.5.0.tgz#2d51b983b786a97dcd6cde805e700c7f913bc596"
 | 
				
			||||||
  integrity sha1-LVG5g7eGqX3NbN6AXnAMf5E7xZY=
 | 
					  integrity sha1-LVG5g7eGqX3NbN6AXnAMf5E7xZY=
 | 
				
			||||||
 | 
					
 | 
				
			||||||
xterm@^4.18.0:
 | 
					xterm@^4.19.0:
 | 
				
			||||||
  version "4.18.0"
 | 
					  version "4.19.0"
 | 
				
			||||||
  resolved "https://registry.npmmirror.com/xterm/-/xterm-4.18.0.tgz#a1f6ab2c330c3918fb094ae5f4c2562987398ea1"
 | 
					  resolved "https://registry.npmmirror.com/xterm/-/xterm-4.19.0.tgz#c0f9d09cd61de1d658f43ca75f992197add9ef6d"
 | 
				
			||||||
  integrity sha512-JQoc1S0dti6SQfI0bK1AZvGnAxH4MVw45ZPFSO6FHTInAiau3Ix77fSxNx3mX4eh9OL4AYa8+4C8f5UvnSfppQ==
 | 
					  integrity sha512-c3Cp4eOVsYY5Q839dR5IejghRPpxciGmLWWaP9g+ppfMeBChMeLa1DCA+pmX/jyDZ+zxFOmlJL/82qVdayVoGQ==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
yallist@^4.0.0:
 | 
					yallist@^4.0.0:
 | 
				
			||||||
  version "4.0.0"
 | 
					  version "4.0.0"
 | 
				
			||||||
  resolved "https://registry.nlark.com/yallist/download/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
 | 
					  resolved "https://registry.nlark.com/yallist/download/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
 | 
				
			||||||
  integrity sha1-m7knkNnA7/7GO+c1GeEaNQGaOnI=
 | 
					  integrity sha1-m7knkNnA7/7GO+c1GeEaNQGaOnI=
 | 
				
			||||||
 | 
					
 | 
				
			||||||
zrender@5.3.1:
 | 
					zrender@5.3.2:
 | 
				
			||||||
  version "5.3.1"
 | 
					  version "5.3.2"
 | 
				
			||||||
  resolved "https://registry.npmmirror.com/zrender/-/zrender-5.3.1.tgz#fa8e63ac7e719cfd563831fe8c42a9756c5af384"
 | 
					  resolved "https://registry.npmmirror.com/zrender/-/zrender-5.3.2.tgz#f67b11d36d3d020d62411d3bb123eb1c93cccd69"
 | 
				
			||||||
  integrity sha512-7olqIjy0gWfznKr6vgfnGBk7y4UtdMvdwFmK92vVQsQeDPyzkHW1OlrLEKg6GHz1W5ePf0FeN1q2vkl/HFqhXw==
 | 
					  integrity sha512-8IiYdfwHj2rx0UeIGZGGU4WEVSDEdeVCaIg/fomejg1Xu6OifAL1GVzIPHg2D+MyUkbNgPWji90t0a8IDk+39w==
 | 
				
			||||||
  dependencies:
 | 
					  dependencies:
 | 
				
			||||||
    tslib "2.3.0"
 | 
					    tslib "2.3.0"
 | 
				
			||||||
 
 | 
				
			|||||||
										
											Binary file not shown.
										
									
								
							@@ -1,27 +0,0 @@
 | 
				
			|||||||
-----BEGIN RSA PRIVATE KEY-----
 | 
					 | 
				
			||||||
MIIEpgIBAAKCAQEA0CsawvEZl42Vf+0BlTuZ3Dp10yW8Oty1tjimxUj3s0WPeKil
 | 
					 | 
				
			||||||
6+TehnQELS8vGJfek+yT99nyrt+bkRmg1kxZ57FtQFEuthG4OQZoaMDUz6Ab+8P1
 | 
					 | 
				
			||||||
PQ9VH0XimnnYabxztJiQjl8HdJt6N4WP35kGlcul7qQ+Qc7iwjhSadfAhXVycqVI
 | 
					 | 
				
			||||||
cGQyHiPPfbmYRjueAIC4czmMUxwFKCwjepGYkwzWuGkpMD0hg/SIXpFJE2dcqYPR
 | 
					 | 
				
			||||||
2nCah1gxZZG00lHU1X2pehNmmgeHRkB5S7mrsCdyyV/33SAYk6T6PT7dOqY54bfn
 | 
					 | 
				
			||||||
h3C0k+T7IzvKTXKG76eG63STmxVa6luVoKMvxwIDAQABAoIBAQCI2Y2CUpYMd9us
 | 
					 | 
				
			||||||
edbskH4ZtaT35nrUB3y+Cog4cjvE8xnarKRHa/KOWX7VZYuEk3KTtJeh/Pn51K6k
 | 
					 | 
				
			||||||
uUBvIUqJcq7r9XLL5uJBOuEw3HQK+qrq3GxAc+/12y+Zdji7alR2iUWfEwIHup6i
 | 
					 | 
				
			||||||
GX/38tXNbE/tjrQO9z9Dh1tGkbvS/66tPn/T/oMxsRvZB6mCjB7yuOlEIwYTomYB
 | 
					 | 
				
			||||||
pUFemELt8T5RtfxRa8T1VoITbfuj7zvecqlThW0H8UizsFxvrOCUaga7jtsJOCHo
 | 
					 | 
				
			||||||
bcW5WvWwazoOfQ2BGpksKkBDf1N6pj85e4kOoYcVG9UN03ZwDvAGfQPWUlHB4YzW
 | 
					 | 
				
			||||||
PybMwIQBAoGBAPfuOQ+ukVmkiEKj6wCBe3Z0pYeNqBGec9aj62bKFh79BCE3ZopS
 | 
					 | 
				
			||||||
7JtGs8VfBKkBAaOy+MDuvJ2fvRNRtHT4BYe1U6ZRsmVFqHScACOaO/7TR0tz0ihL
 | 
					 | 
				
			||||||
0QLCkbSwsXExG6bYbwP4jMHkhHArT7Hy8WXvup8PffjSiEs1A1uGvYSBAoGBANbx
 | 
					 | 
				
			||||||
lHo+39nsc1OO8TUAWZChIQUib2hFIwzQYngSzINdfXQaGFT/omOsudAtfdjvp+qO
 | 
					 | 
				
			||||||
Tr7WpwgFEFveDFsdJfZ2Kc2x9a3ty7IYIWaAjK2ghkAKz3Tt4gClreB6qG2SBycP
 | 
					 | 
				
			||||||
4C2ImbY6hMaFHz3ENtTEzzTMdD1ByxQVMvoem3BHAoGBAJdaTmtMXl8jGivUdXnx
 | 
					 | 
				
			||||||
kbVWsFZ4G8nluUGm/+XYKHjybLr6XxbCWL7SApzSzL1/Z8jPURw2od53za0li8x8
 | 
					 | 
				
			||||||
PKQEBfTamtVIGPZW5Z7WYRnHURa2tezzm7zbmqd71lcLa54HMn5yFTuojVEMn7I6
 | 
					 | 
				
			||||||
ZTOdjYfcpUJpA9slmc8eCkQBAoGBAJEIbxRRaoBEQMkH8Y++zbB+WKZ7RssHo4/Y
 | 
					 | 
				
			||||||
6Ch3HtIg+i6mEPcBitRQzww+NeV0SExHe7Dfa9NIf3JNkO7F60CzGJ/3zXtvsftY
 | 
					 | 
				
			||||||
tujQIpxhbVS3NqaCgPXI1VtbyFwupW7hEnYG7xj7wW2mk578z7afmeTZdDGFPH8v
 | 
					 | 
				
			||||||
krccgeuvAoGBAPAwiqbZlXNx+ueI1B3T8VpXnG0ozKxG+l5B71kssZWa7xcv9yRd
 | 
					 | 
				
			||||||
c15l2PSXNtnoT/mBID7+dqQOmfYxsDHAkUdd/BrxhXtdi9FR3AfHSEQz+VKsogAD
 | 
					 | 
				
			||||||
uLyRd7jWTYqqGa2UToF/CBV+c6QyMB+6pzFNk5DmUEm4Gd6jcHDITYeI
 | 
					 | 
				
			||||||
-----END RSA PRIVATE KEY-----
 | 
					 | 
				
			||||||
@@ -1,21 +0,0 @@
 | 
				
			|||||||
-----BEGIN CERTIFICATE-----
 | 
					 | 
				
			||||||
MIIDejCCAmICCQDQU4ZRt2G46TANBgkqhkiG9w0BAQsFADB/MQswCQYDVQQGEwJ6
 | 
					 | 
				
			||||||
aDEPMA0GA1UECAwGbWF5Zmx5MQswCQYDVQQHDAJ4bTEPMA0GA1UECgwGbWF5Zmx5
 | 
					 | 
				
			||||||
MQ8wDQYDVQQLDAZtYXlmbHkxDzANBgNVBAMMBm1heWZseTEfMB0GCSqGSIb3DQEJ
 | 
					 | 
				
			||||||
ARYQOTU0NTM3NDczQHFxLmNvbTAeFw0yMTA2MjQwMzI2MzBaFw0zMTA2MjIwMzI2
 | 
					 | 
				
			||||||
MzBaMH8xCzAJBgNVBAYTAnpoMQ8wDQYDVQQIDAZtYXlmbHkxCzAJBgNVBAcMAnht
 | 
					 | 
				
			||||||
MQ8wDQYDVQQKDAZtYXlmbHkxDzANBgNVBAsMBm1heWZseTEPMA0GA1UEAwwGbWF5
 | 
					 | 
				
			||||||
Zmx5MR8wHQYJKoZIhvcNAQkBFhA5NTQ1Mzc0NzNAcXEuY29tMIIBIjANBgkqhkiG
 | 
					 | 
				
			||||||
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0CsawvEZl42Vf+0BlTuZ3Dp10yW8Oty1tjim
 | 
					 | 
				
			||||||
xUj3s0WPeKil6+TehnQELS8vGJfek+yT99nyrt+bkRmg1kxZ57FtQFEuthG4OQZo
 | 
					 | 
				
			||||||
aMDUz6Ab+8P1PQ9VH0XimnnYabxztJiQjl8HdJt6N4WP35kGlcul7qQ+Qc7iwjhS
 | 
					 | 
				
			||||||
adfAhXVycqVIcGQyHiPPfbmYRjueAIC4czmMUxwFKCwjepGYkwzWuGkpMD0hg/SI
 | 
					 | 
				
			||||||
XpFJE2dcqYPR2nCah1gxZZG00lHU1X2pehNmmgeHRkB5S7mrsCdyyV/33SAYk6T6
 | 
					 | 
				
			||||||
PT7dOqY54bfnh3C0k+T7IzvKTXKG76eG63STmxVa6luVoKMvxwIDAQABMA0GCSqG
 | 
					 | 
				
			||||||
SIb3DQEBCwUAA4IBAQB/e8EO2XEtkYBxebR1w6i50vaegLsxQJR3l5qm7rsHu3Cr
 | 
					 | 
				
			||||||
smJXGsc56axKCAqJ4XvSI65BT51FghAoGn62QNyiQgc0YoS99nwCCGFtnhZ2lmSe
 | 
					 | 
				
			||||||
pfhUHegN/Qo4I8FemEMD+o9kGeAzwrnaIVIT/cNOEQgm+RzrgHHJh5QBn2XgJalU
 | 
					 | 
				
			||||||
NeFTWaimyefwSezSa/vPbyMoAl9HkT6kdvnms/yOth4AOle6+5pM2StWjmMi4yx4
 | 
					 | 
				
			||||||
16y3NvLTku6nAUazaHTOOu/MCqLWL2/qYTk3r7OCop2jr9Rp+HLbg5AfKLUIVXjG
 | 
					 | 
				
			||||||
/1fnXJIuD+2u9qgDLN5PZNgz4MlU86ugtmYPFkVt
 | 
					 | 
				
			||||||
-----END CERTIFICATE-----
 | 
					 | 
				
			||||||
@@ -1,25 +1,23 @@
 | 
				
			|||||||
module mayfly-go
 | 
					module mayfly-go
 | 
				
			||||||
 | 
					
 | 
				
			||||||
go 1.17
 | 
					go 1.18
 | 
				
			||||||
 | 
					
 | 
				
			||||||
require (
 | 
					require (
 | 
				
			||||||
	// jwt
 | 
						github.com/dgrijalva/jwt-go v3.2.0+incompatible // jwt
 | 
				
			||||||
	github.com/dgrijalva/jwt-go v3.2.0+incompatible
 | 
						github.com/gin-gonic/gin v1.8.1
 | 
				
			||||||
	github.com/gin-gonic/gin v1.7.7
 | 
					 | 
				
			||||||
	github.com/go-redis/redis v6.15.9+incompatible
 | 
						github.com/go-redis/redis v6.15.9+incompatible
 | 
				
			||||||
	github.com/gorilla/websocket v1.5.0
 | 
						github.com/gorilla/websocket v1.5.0
 | 
				
			||||||
	// 验证码
 | 
						github.com/mojocn/base64Captcha v1.3.5 // 验证码
 | 
				
			||||||
	github.com/mojocn/base64Captcha v1.3.5
 | 
					 | 
				
			||||||
	github.com/pkg/sftp v1.13.4
 | 
						github.com/pkg/sftp v1.13.4
 | 
				
			||||||
	// 定时任务
 | 
						github.com/robfig/cron/v3 v3.0.1 // 定时任务
 | 
				
			||||||
	github.com/robfig/cron/v3 v3.0.1
 | 
					 | 
				
			||||||
	github.com/sirupsen/logrus v1.8.1
 | 
						github.com/sirupsen/logrus v1.8.1
 | 
				
			||||||
	// ssh
 | 
						github.com/xwb1989/sqlparser v0.0.0-20180606152119-120387863bf2
 | 
				
			||||||
	golang.org/x/crypto v0.0.0-20220314234724-5d542ad81a58
 | 
						go.mongodb.org/mongo-driver v1.9.1 // mongo
 | 
				
			||||||
 | 
						golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e // ssh
 | 
				
			||||||
	gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
 | 
						gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
 | 
				
			||||||
	// gorm
 | 
						// gorm
 | 
				
			||||||
	gorm.io/driver/mysql v1.3.2
 | 
						gorm.io/driver/mysql v1.3.4
 | 
				
			||||||
	gorm.io/gorm v1.23.2
 | 
						gorm.io/gorm v1.23.5
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
require (
 | 
					require (
 | 
				
			||||||
@@ -28,11 +26,14 @@ require (
 | 
				
			|||||||
	github.com/go-playground/universal-translator v0.18.0 // indirect
 | 
						github.com/go-playground/universal-translator v0.18.0 // indirect
 | 
				
			||||||
	github.com/go-playground/validator/v10 v10.10.1 // indirect
 | 
						github.com/go-playground/validator/v10 v10.10.1 // indirect
 | 
				
			||||||
	github.com/go-sql-driver/mysql v1.6.0 // indirect
 | 
						github.com/go-sql-driver/mysql v1.6.0 // indirect
 | 
				
			||||||
 | 
						github.com/go-stack/stack v1.8.0 // indirect
 | 
				
			||||||
 | 
						github.com/goccy/go-json v0.9.7 // indirect
 | 
				
			||||||
	github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
 | 
						github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
 | 
				
			||||||
	github.com/golang/protobuf v1.5.2 // indirect
 | 
						github.com/golang/snappy v0.0.1 // indirect
 | 
				
			||||||
	github.com/jinzhu/inflection v1.0.0 // indirect
 | 
						github.com/jinzhu/inflection v1.0.0 // indirect
 | 
				
			||||||
	github.com/jinzhu/now v1.1.4 // indirect
 | 
						github.com/jinzhu/now v1.1.4 // indirect
 | 
				
			||||||
	github.com/json-iterator/go v1.1.12 // indirect
 | 
						github.com/json-iterator/go v1.1.12 // indirect
 | 
				
			||||||
 | 
						github.com/klauspost/compress v1.13.6 // indirect
 | 
				
			||||||
	github.com/kr/fs v0.1.0 // indirect
 | 
						github.com/kr/fs v0.1.0 // indirect
 | 
				
			||||||
	github.com/leodido/go-urn v1.2.1 // indirect
 | 
						github.com/leodido/go-urn v1.2.1 // indirect
 | 
				
			||||||
	github.com/mattn/go-isatty v0.0.14 // indirect
 | 
						github.com/mattn/go-isatty v0.0.14 // indirect
 | 
				
			||||||
@@ -40,10 +41,18 @@ require (
 | 
				
			|||||||
	github.com/modern-go/reflect2 v1.0.2 // indirect
 | 
						github.com/modern-go/reflect2 v1.0.2 // indirect
 | 
				
			||||||
	github.com/onsi/ginkgo v1.16.5 // indirect
 | 
						github.com/onsi/ginkgo v1.16.5 // indirect
 | 
				
			||||||
	github.com/onsi/gomega v1.18.1 // indirect
 | 
						github.com/onsi/gomega v1.18.1 // indirect
 | 
				
			||||||
 | 
						github.com/pelletier/go-toml/v2 v2.0.1 // indirect
 | 
				
			||||||
 | 
						github.com/pkg/errors v0.9.1 // indirect
 | 
				
			||||||
	github.com/ugorji/go/codec v1.2.7 // indirect
 | 
						github.com/ugorji/go/codec v1.2.7 // indirect
 | 
				
			||||||
 | 
						github.com/xdg-go/pbkdf2 v1.0.0 // indirect
 | 
				
			||||||
 | 
						github.com/xdg-go/scram v1.0.2 // indirect
 | 
				
			||||||
 | 
						github.com/xdg-go/stringprep v1.0.2 // indirect
 | 
				
			||||||
 | 
						github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
 | 
				
			||||||
	golang.org/x/image v0.0.0-20220302094943-723b81ca9867 // indirect
 | 
						golang.org/x/image v0.0.0-20220302094943-723b81ca9867 // indirect
 | 
				
			||||||
 | 
						golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 // indirect
 | 
				
			||||||
 | 
						golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 // indirect
 | 
				
			||||||
	golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5 // indirect
 | 
						golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5 // indirect
 | 
				
			||||||
	golang.org/x/text v0.3.7 // indirect
 | 
						golang.org/x/text v0.3.7 // indirect
 | 
				
			||||||
	google.golang.org/protobuf v1.27.1 // indirect
 | 
						google.golang.org/protobuf v1.28.0 // indirect
 | 
				
			||||||
	gopkg.in/yaml.v2 v2.4.0 // indirect
 | 
						gopkg.in/yaml.v2 v2.4.0 // indirect
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -2,11 +2,11 @@ package initialize
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"mayfly-go/base/config"
 | 
						common_index_router "mayfly-go/internal/common/router"
 | 
				
			||||||
	"mayfly-go/base/middleware"
 | 
						devops_router "mayfly-go/internal/devops/router"
 | 
				
			||||||
	common_index_router "mayfly-go/server/common/router"
 | 
						sys_router "mayfly-go/internal/sys/router"
 | 
				
			||||||
	devops_router "mayfly-go/server/devops/router"
 | 
						"mayfly-go/pkg/config"
 | 
				
			||||||
	sys_router "mayfly-go/server/sys/router"
 | 
						"mayfly-go/pkg/middleware"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/gin-gonic/gin"
 | 
						"github.com/gin-gonic/gin"
 | 
				
			||||||
@@ -56,10 +56,12 @@ func InitRouter() *gin.Engine {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		devops_router.InitProjectRouter(api)
 | 
							devops_router.InitProjectRouter(api)
 | 
				
			||||||
		devops_router.InitDbRouter(api)
 | 
							devops_router.InitDbRouter(api)
 | 
				
			||||||
 | 
							devops_router.InitDbSqlExecRouter(api)
 | 
				
			||||||
		devops_router.InitRedisRouter(api)
 | 
							devops_router.InitRedisRouter(api)
 | 
				
			||||||
		devops_router.InitMachineRouter(api)
 | 
							devops_router.InitMachineRouter(api)
 | 
				
			||||||
		devops_router.InitMachineScriptRouter(api)
 | 
							devops_router.InitMachineScriptRouter(api)
 | 
				
			||||||
		devops_router.InitMachineFileRouter(api)
 | 
							devops_router.InitMachineFileRouter(api)
 | 
				
			||||||
 | 
							devops_router.InitMongoRouter(api)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return router
 | 
						return router
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,9 @@
 | 
				
			|||||||
package api
 | 
					package api
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"mayfly-go/base/ctx"
 | 
						"mayfly-go/internal/devops/application"
 | 
				
			||||||
	"mayfly-go/server/devops/application"
 | 
						"mayfly-go/internal/devops/domain/entity"
 | 
				
			||||||
	"mayfly-go/server/devops/domain/entity"
 | 
						"mayfly-go/pkg/ctx"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Index struct {
 | 
					type Index struct {
 | 
				
			||||||
@@ -1,9 +1,9 @@
 | 
				
			|||||||
package router
 | 
					package router
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"mayfly-go/base/ctx"
 | 
						"mayfly-go/internal/common/api"
 | 
				
			||||||
	"mayfly-go/server/common/api"
 | 
						devops_app "mayfly-go/internal/devops/application"
 | 
				
			||||||
	devops_app "mayfly-go/server/devops/application"
 | 
						"mayfly-go/pkg/ctx"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/gin-gonic/gin"
 | 
						"github.com/gin-gonic/gin"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -2,30 +2,35 @@ package api
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"io/ioutil"
 | 
						"io"
 | 
				
			||||||
	"mayfly-go/base/biz"
 | 
						"mayfly-go/internal/devops/api/form"
 | 
				
			||||||
	"mayfly-go/base/ctx"
 | 
						"mayfly-go/internal/devops/api/vo"
 | 
				
			||||||
	"mayfly-go/base/ginx"
 | 
						"mayfly-go/internal/devops/application"
 | 
				
			||||||
	"mayfly-go/base/model"
 | 
						"mayfly-go/internal/devops/domain/entity"
 | 
				
			||||||
	"mayfly-go/base/utils"
 | 
						sysApplication "mayfly-go/internal/sys/application"
 | 
				
			||||||
	"mayfly-go/base/ws"
 | 
						"mayfly-go/pkg/biz"
 | 
				
			||||||
	"mayfly-go/server/devops/api/form"
 | 
						"mayfly-go/pkg/ctx"
 | 
				
			||||||
	"mayfly-go/server/devops/api/vo"
 | 
						"mayfly-go/pkg/ginx"
 | 
				
			||||||
	"mayfly-go/server/devops/application"
 | 
						"mayfly-go/pkg/model"
 | 
				
			||||||
	"mayfly-go/server/devops/domain/entity"
 | 
						"mayfly-go/pkg/utils"
 | 
				
			||||||
	sysApplication "mayfly-go/server/sys/application"
 | 
						"mayfly-go/pkg/ws"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/gin-gonic/gin"
 | 
						"github.com/gin-gonic/gin"
 | 
				
			||||||
 | 
						"github.com/xwb1989/sqlparser"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Db struct {
 | 
					type Db struct {
 | 
				
			||||||
	DbApp      application.Db
 | 
						DbApp        application.Db
 | 
				
			||||||
	MsgApp     sysApplication.Msg
 | 
						DbSqlExecApp application.DbSqlExec
 | 
				
			||||||
	ProjectApp application.Project
 | 
						MsgApp       sysApplication.Msg
 | 
				
			||||||
 | 
						ProjectApp   application.Project
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const DEFAULT_COLUMN_SIZE = 500
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// @router /api/dbs [get]
 | 
					// @router /api/dbs [get]
 | 
				
			||||||
func (d *Db) Dbs(rc *ctx.ReqCtx) {
 | 
					func (d *Db) Dbs(rc *ctx.ReqCtx) {
 | 
				
			||||||
	g := rc.GinCtx
 | 
						g := rc.GinCtx
 | 
				
			||||||
@@ -49,7 +54,10 @@ func (d *Db) Save(rc *ctx.ReqCtx) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (d *Db) DeleteDb(rc *ctx.ReqCtx) {
 | 
					func (d *Db) DeleteDb(rc *ctx.ReqCtx) {
 | 
				
			||||||
	d.DbApp.Delete(GetDbId(rc.GinCtx))
 | 
						dbId := GetDbId(rc.GinCtx)
 | 
				
			||||||
 | 
						d.DbApp.Delete(dbId)
 | 
				
			||||||
 | 
						// 删除该库的sql执行记录
 | 
				
			||||||
 | 
						d.DbSqlExecApp.DeleteBy(&entity.DbSqlExec{DbId: dbId})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (d *Db) TableInfos(rc *ctx.ReqCtx) {
 | 
					func (d *Db) TableInfos(rc *ctx.ReqCtx) {
 | 
				
			||||||
@@ -68,23 +76,26 @@ func (d *Db) GetCreateTableDdl(rc *ctx.ReqCtx) {
 | 
				
			|||||||
	rc.ResData = d.DbApp.GetDbInstance(GetIdAndDb(rc.GinCtx)).GetCreateTableDdl(tn)
 | 
						rc.ResData = d.DbApp.GetDbInstance(GetIdAndDb(rc.GinCtx)).GetCreateTableDdl(tn)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// @router /api/db/:dbId/exec-sql [get]
 | 
					 | 
				
			||||||
func (d *Db) ExecSql(rc *ctx.ReqCtx) {
 | 
					func (d *Db) ExecSql(rc *ctx.ReqCtx) {
 | 
				
			||||||
	g := rc.GinCtx
 | 
						g := rc.GinCtx
 | 
				
			||||||
 | 
						form := &form.DbSqlExecForm{}
 | 
				
			||||||
 | 
						ginx.BindJsonAndValid(g, form)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	id, db := GetIdAndDb(g)
 | 
						id := GetDbId(g)
 | 
				
			||||||
 | 
						db := form.Db
 | 
				
			||||||
	dbInstance := d.DbApp.GetDbInstance(id, db)
 | 
						dbInstance := d.DbApp.GetDbInstance(id, db)
 | 
				
			||||||
	biz.ErrIsNilAppendErr(d.ProjectApp.CanAccess(rc.LoginAccount.Id, dbInstance.ProjectId), "%s")
 | 
						biz.ErrIsNilAppendErr(d.ProjectApp.CanAccess(rc.LoginAccount.Id, dbInstance.ProjectId), "%s")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 去除前后空格及换行符
 | 
						// 去除前后空格及换行符
 | 
				
			||||||
	sql := strings.TrimFunc(g.Query("sql"), func(r rune) bool {
 | 
						sql := strings.TrimFunc(form.Sql, func(r rune) bool {
 | 
				
			||||||
		s := string(r)
 | 
							s := string(r)
 | 
				
			||||||
		return s == " " || s == "\n"
 | 
							return s == " " || s == "\n"
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rc.ReqParam = fmt.Sprintf("db: %d:%s | sql: %s", id, db, sql)
 | 
						rc.ReqParam = fmt.Sprintf("db: %d:%s | sql: %s", id, db, sql)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	biz.NotEmpty(sql, "sql不能为空")
 | 
						biz.NotEmpty(sql, "sql不能为空")
 | 
				
			||||||
	if strings.HasPrefix(sql, "SELECT") || strings.HasPrefix(sql, "select") || strings.HasPrefix(sql, "show") {
 | 
						if strings.HasPrefix(sql, "SELECT") || strings.HasPrefix(sql, "select") || strings.HasPrefix(sql, "show") || strings.HasPrefix(sql, "explain") {
 | 
				
			||||||
		colNames, res, err := dbInstance.SelectData(sql)
 | 
							colNames, res, err := dbInstance.SelectData(sql)
 | 
				
			||||||
		biz.ErrIsNilAppendErr(err, "查询失败: %s")
 | 
							biz.ErrIsNilAppendErr(err, "查询失败: %s")
 | 
				
			||||||
		colAndRes := make(map[string]interface{})
 | 
							colAndRes := make(map[string]interface{})
 | 
				
			||||||
@@ -92,6 +103,9 @@ func (d *Db) ExecSql(rc *ctx.ReqCtx) {
 | 
				
			|||||||
		colAndRes["res"] = res
 | 
							colAndRes["res"] = res
 | 
				
			||||||
		rc.ResData = colAndRes
 | 
							rc.ResData = colAndRes
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
 | 
							// 根据执行sql,生成执行记录
 | 
				
			||||||
 | 
							execRecord := d.DbSqlExecApp.GenExecLog(rc.LoginAccount, id, db, sql, dbInstance)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		rowsAffected, err := dbInstance.Exec(sql)
 | 
							rowsAffected, err := dbInstance.Exec(sql)
 | 
				
			||||||
		biz.ErrIsNilAppendErr(err, "执行失败: %s")
 | 
							biz.ErrIsNilAppendErr(err, "执行失败: %s")
 | 
				
			||||||
		res := make([]map[string]string, 0)
 | 
							res := make([]map[string]string, 0)
 | 
				
			||||||
@@ -104,6 +118,11 @@ func (d *Db) ExecSql(rc *ctx.ReqCtx) {
 | 
				
			|||||||
		colAndRes["res"] = res
 | 
							colAndRes["res"] = res
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		rc.ResData = colAndRes
 | 
							rc.ResData = colAndRes
 | 
				
			||||||
 | 
							// 保存sql执行记录
 | 
				
			||||||
 | 
							if res[0]["影响条数"] > "0" {
 | 
				
			||||||
 | 
								execRecord.Remark = form.Remark
 | 
				
			||||||
 | 
								d.DbSqlExecApp.Save(execRecord)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -113,12 +132,8 @@ func (d *Db) ExecSqlFile(rc *ctx.ReqCtx) {
 | 
				
			|||||||
	fileheader, err := g.FormFile("file")
 | 
						fileheader, err := g.FormFile("file")
 | 
				
			||||||
	biz.ErrIsNilAppendErr(err, "读取sql文件失败: %s")
 | 
						biz.ErrIsNilAppendErr(err, "读取sql文件失败: %s")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 读取sql文件并根据;切割sql语句
 | 
					 | 
				
			||||||
	file, _ := fileheader.Open()
 | 
						file, _ := fileheader.Open()
 | 
				
			||||||
	filename := fileheader.Filename
 | 
						filename := fileheader.Filename
 | 
				
			||||||
	bytes, _ := ioutil.ReadAll(file)
 | 
					 | 
				
			||||||
	sqlContent := string(bytes)
 | 
					 | 
				
			||||||
	sqls := strings.Split(sqlContent, ";")
 | 
					 | 
				
			||||||
	dbId, db := GetIdAndDb(g)
 | 
						dbId, db := GetIdAndDb(g)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	go func() {
 | 
						go func() {
 | 
				
			||||||
@@ -138,12 +153,14 @@ func (d *Db) ExecSqlFile(rc *ctx.ReqCtx) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		biz.ErrIsNilAppendErr(d.ProjectApp.CanAccess(rc.LoginAccount.Id, db.ProjectId), "%s")
 | 
							biz.ErrIsNilAppendErr(d.ProjectApp.CanAccess(rc.LoginAccount.Id, db.ProjectId), "%s")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for _, sql := range sqls {
 | 
							tokens := sqlparser.NewTokenizer(file)
 | 
				
			||||||
			sql = strings.Trim(sql, " ")
 | 
							for {
 | 
				
			||||||
			if sql == "" || sql == "\n" {
 | 
								stmt, err := sqlparser.ParseNext(tokens)
 | 
				
			||||||
				continue
 | 
								if err == io.EOF {
 | 
				
			||||||
 | 
									break
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			_, err := db.Exec(sql)
 | 
								sql := sqlparser.String(stmt)
 | 
				
			||||||
 | 
								_, err = db.Exec(sql)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				d.MsgApp.CreateAndSend(rc.LoginAccount, ws.ErrMsg("sql脚本执行失败", fmt.Sprintf("[%s]%s执行失败: [%s]", filename, dbInfo, err.Error())))
 | 
									d.MsgApp.CreateAndSend(rc.LoginAccount, ws.ErrMsg("sql脚本执行失败", fmt.Sprintf("[%s]%s执行失败: [%s]", filename, dbInfo, err.Error())))
 | 
				
			||||||
				return
 | 
									return
 | 
				
			||||||
@@ -153,6 +170,88 @@ func (d *Db) ExecSqlFile(rc *ctx.ReqCtx) {
 | 
				
			|||||||
	}()
 | 
						}()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 数据库dump
 | 
				
			||||||
 | 
					func (d *Db) DumpSql(rc *ctx.ReqCtx) {
 | 
				
			||||||
 | 
						g := rc.GinCtx
 | 
				
			||||||
 | 
						dbId, db := GetIdAndDb(g)
 | 
				
			||||||
 | 
						dumpType := g.Query("type")
 | 
				
			||||||
 | 
						tablesStr := g.Query("tables")
 | 
				
			||||||
 | 
						biz.NotEmpty(tablesStr, "请选择要导出的表")
 | 
				
			||||||
 | 
						tables := strings.Split(tablesStr, ",")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 是否需要导出表结构
 | 
				
			||||||
 | 
						needStruct := dumpType == "1" || dumpType == "3"
 | 
				
			||||||
 | 
						// 是否需要导出数据
 | 
				
			||||||
 | 
						needData := dumpType == "2" || dumpType == "3"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						now := time.Now()
 | 
				
			||||||
 | 
						filename := fmt.Sprintf("%s.%s.sql", db, now.Format("200601021504"))
 | 
				
			||||||
 | 
						g.Header("Content-Type", "application/octet-stream")
 | 
				
			||||||
 | 
						g.Header("Content-Disposition", "attachment; filename="+filename)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc.ReqParam = fmt.Sprintf("数据库id: %d -- %s", dbId, db)
 | 
				
			||||||
 | 
						dbInstance := d.DbApp.GetDbInstance(dbId, db)
 | 
				
			||||||
 | 
						writer := g.Writer
 | 
				
			||||||
 | 
						writer.WriteString("-- ----------------------------")
 | 
				
			||||||
 | 
						writer.WriteString("\n-- 导出平台: mayfly-go")
 | 
				
			||||||
 | 
						writer.WriteString(fmt.Sprintf("\n-- 导出时间: %s ", now.Format("2006-01-02 15:04:05")))
 | 
				
			||||||
 | 
						writer.WriteString(fmt.Sprintf("\n-- 导出数据库: %s ", db))
 | 
				
			||||||
 | 
						writer.WriteString("\n-- ----------------------------\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, table := range tables {
 | 
				
			||||||
 | 
							if needStruct {
 | 
				
			||||||
 | 
								writer.WriteString(fmt.Sprintf("\n-- ----------------------------\n-- 表结构: %s \n-- ----------------------------\n", table))
 | 
				
			||||||
 | 
								writer.WriteString(fmt.Sprintf("DROP TABLE IF EXISTS `%s`;\n", table))
 | 
				
			||||||
 | 
								writer.WriteString(dbInstance.GetCreateTableDdl(table)[0]["Create Table"].(string) + ";\n")
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if !needData {
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							writer.WriteString(fmt.Sprintf("\n-- ----------------------------\n-- 表记录: %s \n-- ----------------------------\n", table))
 | 
				
			||||||
 | 
							writer.WriteString("BEGIN;\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							countSql := fmt.Sprintf("SELECT COUNT(*) count FROM %s", table)
 | 
				
			||||||
 | 
							_, countRes, _ := dbInstance.SelectData(countSql)
 | 
				
			||||||
 | 
							// 查询出所有列信息总数,手动分页获取所有数据
 | 
				
			||||||
 | 
							maCount := int(countRes[0]["count"].(int64))
 | 
				
			||||||
 | 
							// 计算需要查询的页数
 | 
				
			||||||
 | 
							pageNum := maCount / DEFAULT_COLUMN_SIZE
 | 
				
			||||||
 | 
							if maCount%DEFAULT_COLUMN_SIZE > 0 {
 | 
				
			||||||
 | 
								pageNum++
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							sqlTmp := "SELECT * FROM %s LIMIT %d, %d"
 | 
				
			||||||
 | 
							for index := 0; index < pageNum; index++ {
 | 
				
			||||||
 | 
								sql := fmt.Sprintf(sqlTmp, table, index*DEFAULT_COLUMN_SIZE, DEFAULT_COLUMN_SIZE)
 | 
				
			||||||
 | 
								columns, result, _ := dbInstance.SelectData(sql)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								insertSql := "INSERT INTO `%s` VALUES (%s);\n"
 | 
				
			||||||
 | 
								for _, res := range result {
 | 
				
			||||||
 | 
									var values []string
 | 
				
			||||||
 | 
									for _, column := range columns {
 | 
				
			||||||
 | 
										value := res[column]
 | 
				
			||||||
 | 
										if value == nil {
 | 
				
			||||||
 | 
											values = append(values, "NULL")
 | 
				
			||||||
 | 
											continue
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										strValue, ok := value.(string)
 | 
				
			||||||
 | 
										if ok {
 | 
				
			||||||
 | 
											values = append(values, fmt.Sprintf("%#v", strValue))
 | 
				
			||||||
 | 
										} else {
 | 
				
			||||||
 | 
											values = append(values, utils.ToString(value))
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									writer.WriteString(fmt.Sprintf(insertSql, table, strings.Join(values, ", ")))
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							writer.WriteString("COMMIT;\n")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						rc.NoRes = true
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// @router /api/db/:dbId/t-metadata [get]
 | 
					// @router /api/db/:dbId/t-metadata [get]
 | 
				
			||||||
func (d *Db) TableMA(rc *ctx.ReqCtx) {
 | 
					func (d *Db) TableMA(rc *ctx.ReqCtx) {
 | 
				
			||||||
	dbi := d.DbApp.GetDbInstance(GetIdAndDb(rc.GinCtx))
 | 
						dbi := d.DbApp.GetDbInstance(GetIdAndDb(rc.GinCtx))
 | 
				
			||||||
@@ -180,7 +279,7 @@ func (d *Db) HintTables(rc *ctx.ReqCtx) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	tableNames := make([]string, 0)
 | 
						tableNames := make([]string, 0)
 | 
				
			||||||
	for _, v := range tables {
 | 
						for _, v := range tables {
 | 
				
			||||||
		tableNames = append(tableNames, v["tableName"])
 | 
							tableNames = append(tableNames, v["tableName"].(string))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	// key = 表名,value = 列名数组
 | 
						// key = 表名,value = 列名数组
 | 
				
			||||||
	res := make(map[string][]string)
 | 
						res := make(map[string][]string)
 | 
				
			||||||
@@ -194,7 +293,7 @@ func (d *Db) HintTables(rc *ctx.ReqCtx) {
 | 
				
			|||||||
	// 获取所有表下的所有列信息
 | 
						// 获取所有表下的所有列信息
 | 
				
			||||||
	columnMds := dbi.GetColumnMetadatas(tableNames...)
 | 
						columnMds := dbi.GetColumnMetadatas(tableNames...)
 | 
				
			||||||
	for _, v := range columnMds {
 | 
						for _, v := range columnMds {
 | 
				
			||||||
		tName := v["tableName"]
 | 
							tName := v["tableName"].(string)
 | 
				
			||||||
		if res[tName] == nil {
 | 
							if res[tName] == nil {
 | 
				
			||||||
			res[tName] = make([]string, 0)
 | 
								res[tName] = make([]string, 0)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
							
								
								
									
										23
									
								
								server/internal/devops/api/db_sql_exec.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								server/internal/devops/api/db_sql_exec.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
				
			|||||||
 | 
					package api
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"mayfly-go/internal/devops/application"
 | 
				
			||||||
 | 
						"mayfly-go/internal/devops/domain/entity"
 | 
				
			||||||
 | 
						"mayfly-go/pkg/ctx"
 | 
				
			||||||
 | 
						"mayfly-go/pkg/ginx"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type DbSqlExec struct {
 | 
				
			||||||
 | 
						DbSqlExecApp application.DbSqlExec
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (d *DbSqlExec) DbSqlExecs(rc *ctx.ReqCtx) {
 | 
				
			||||||
 | 
						g := rc.GinCtx
 | 
				
			||||||
 | 
						m := &entity.DbSqlExec{DbId: uint64(ginx.QueryInt(g, "dbId", 0)),
 | 
				
			||||||
 | 
							Db:    g.Query("db"),
 | 
				
			||||||
 | 
							Table: g.Query("table"),
 | 
				
			||||||
 | 
							Type:  int8(ginx.QueryInt(g, "type", 0)),
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						m.CreatorId = rc.LoginAccount.Id
 | 
				
			||||||
 | 
						rc.ResData = d.DbSqlExecApp.GetPageList(m, ginx.GetPageParam(rc.GinCtx), new([]entity.DbSqlExec))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -14,3 +14,10 @@ type DbForm struct {
 | 
				
			|||||||
	Env       string `json:"env"`
 | 
						Env       string `json:"env"`
 | 
				
			||||||
	EnvId     uint64 `binding:"required" json:"envId"`
 | 
						EnvId     uint64 `binding:"required" json:"envId"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 数据库SQL执行表单
 | 
				
			||||||
 | 
					type DbSqlExecForm struct {
 | 
				
			||||||
 | 
						Db     string `binding:"required" json:"db"`  //数据库名
 | 
				
			||||||
 | 
						Sql    string `binding:"required" json:"sql"` // 执行sql
 | 
				
			||||||
 | 
						Remark string `json:"remark"`                 // 执行备注
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										40
									
								
								server/internal/devops/api/form/mongo.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								server/internal/devops/api/form/mongo.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,40 @@
 | 
				
			|||||||
 | 
					package form
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Mongo struct {
 | 
				
			||||||
 | 
						Id        uint64
 | 
				
			||||||
 | 
						Uri       string `binding:"required" json:"uri"`
 | 
				
			||||||
 | 
						Name      string `binding:"required" json:"name"`
 | 
				
			||||||
 | 
						ProjectId uint64 `binding:"required" json:"projectId"`
 | 
				
			||||||
 | 
						Project   string `json:"project"`
 | 
				
			||||||
 | 
						Env       string `json:"env"`
 | 
				
			||||||
 | 
						EnvId     uint64 `binding:"required" json:"envId"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type MongoCommand struct {
 | 
				
			||||||
 | 
						Database   string                 `binding:"required" json:"database"`
 | 
				
			||||||
 | 
						Collection string                 `binding:"required" json:"collection"`
 | 
				
			||||||
 | 
						Filter     map[string]interface{} `json:"filter"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type MongoRunCommand struct {
 | 
				
			||||||
 | 
						Database string                 `binding:"required" json:"database"`
 | 
				
			||||||
 | 
						Command  map[string]interface{} `json:"command"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type MongoFindCommand struct {
 | 
				
			||||||
 | 
						MongoCommand
 | 
				
			||||||
 | 
						Sort  map[string]interface{} `json:"sort"`
 | 
				
			||||||
 | 
						Skip  int64
 | 
				
			||||||
 | 
						Limit int64
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type MongoUpdateByIdCommand struct {
 | 
				
			||||||
 | 
						MongoCommand
 | 
				
			||||||
 | 
						DocId  interface{}            `binding:"required" json:"docId"`
 | 
				
			||||||
 | 
						Update map[string]interface{} `json:"update"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type MongoInsertCommand struct {
 | 
				
			||||||
 | 
						MongoCommand
 | 
				
			||||||
 | 
						Doc map[string]interface{} `json:"doc"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -2,16 +2,16 @@ package api
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"mayfly-go/base/biz"
 | 
						"mayfly-go/internal/devops/api/form"
 | 
				
			||||||
	"mayfly-go/base/ctx"
 | 
						"mayfly-go/internal/devops/api/vo"
 | 
				
			||||||
	"mayfly-go/base/ginx"
 | 
						"mayfly-go/internal/devops/application"
 | 
				
			||||||
	"mayfly-go/base/utils"
 | 
						"mayfly-go/internal/devops/domain/entity"
 | 
				
			||||||
	"mayfly-go/base/ws"
 | 
						"mayfly-go/internal/devops/infrastructure/machine"
 | 
				
			||||||
	"mayfly-go/server/devops/api/form"
 | 
						"mayfly-go/pkg/biz"
 | 
				
			||||||
	"mayfly-go/server/devops/api/vo"
 | 
						"mayfly-go/pkg/ctx"
 | 
				
			||||||
	"mayfly-go/server/devops/application"
 | 
						"mayfly-go/pkg/ginx"
 | 
				
			||||||
	"mayfly-go/server/devops/domain/entity"
 | 
						"mayfly-go/pkg/utils"
 | 
				
			||||||
	"mayfly-go/server/devops/infrastructure/machine"
 | 
						"mayfly-go/pkg/ws"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/gin-gonic/gin"
 | 
						"github.com/gin-gonic/gin"
 | 
				
			||||||
@@ -138,7 +138,7 @@ func (m *Machine) WsSSH(g *gin.Context) {
 | 
				
			|||||||
	// 权限校验
 | 
						// 权限校验
 | 
				
			||||||
	rc := ctx.NewReqCtxWithGin(g).WithRequiredPermission(ctx.NewPermission("machine:terminal"))
 | 
						rc := ctx.NewReqCtxWithGin(g).WithRequiredPermission(ctx.NewPermission("machine:terminal"))
 | 
				
			||||||
	if err = ctx.PermissionHandler(rc); err != nil {
 | 
						if err = ctx.PermissionHandler(rc); err != nil {
 | 
				
			||||||
		panic(biz.NewBizErr("没有权限"))
 | 
							panic(biz.NewBizErr("\033[1;31m您没有权限操作该机器终端,请重新登录后再试~\033[0m"))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cols := ginx.QueryInt(g, "cols", 80)
 | 
						cols := ginx.QueryInt(g, "cols", 80)
 | 
				
			||||||
@@ -148,7 +148,7 @@ func (m *Machine) WsSSH(g *gin.Context) {
 | 
				
			|||||||
	biz.ErrIsNilAppendErr(m.ProjectApp.CanAccess(rc.LoginAccount.Id, cli.GetMachine().ProjectId), "%s")
 | 
						biz.ErrIsNilAppendErr(m.ProjectApp.CanAccess(rc.LoginAccount.Id, cli.GetMachine().ProjectId), "%s")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sws, err := machine.NewLogicSshWsSession(cols, rows, cli, wsConn)
 | 
						sws, err := machine.NewLogicSshWsSession(cols, rows, cli, wsConn)
 | 
				
			||||||
	biz.ErrIsNilAppendErr(err, "连接失败:%s")
 | 
						biz.ErrIsNilAppendErr(err, "\033[1;31m连接失败:%s\033[0m")
 | 
				
			||||||
	defer sws.Close()
 | 
						defer sws.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	quitChan := make(chan bool, 3)
 | 
						quitChan := make(chan bool, 3)
 | 
				
			||||||
@@ -4,16 +4,16 @@ import (
 | 
				
			|||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"io/fs"
 | 
						"io/fs"
 | 
				
			||||||
	"io/ioutil"
 | 
						"io/ioutil"
 | 
				
			||||||
	"mayfly-go/base/biz"
 | 
						"mayfly-go/internal/devops/api/form"
 | 
				
			||||||
	"mayfly-go/base/ctx"
 | 
						"mayfly-go/internal/devops/api/vo"
 | 
				
			||||||
	"mayfly-go/base/ginx"
 | 
						"mayfly-go/internal/devops/application"
 | 
				
			||||||
	"mayfly-go/base/utils"
 | 
						"mayfly-go/internal/devops/domain/entity"
 | 
				
			||||||
	"mayfly-go/base/ws"
 | 
						sysApplication "mayfly-go/internal/sys/application"
 | 
				
			||||||
	"mayfly-go/server/devops/api/form"
 | 
						"mayfly-go/pkg/biz"
 | 
				
			||||||
	"mayfly-go/server/devops/api/vo"
 | 
						"mayfly-go/pkg/ctx"
 | 
				
			||||||
	"mayfly-go/server/devops/application"
 | 
						"mayfly-go/pkg/ginx"
 | 
				
			||||||
	"mayfly-go/server/devops/domain/entity"
 | 
						"mayfly-go/pkg/utils"
 | 
				
			||||||
	sysApplication "mayfly-go/server/sys/application"
 | 
						"mayfly-go/pkg/ws"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -2,14 +2,14 @@ package api
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"mayfly-go/base/biz"
 | 
						"mayfly-go/internal/devops/api/form"
 | 
				
			||||||
	"mayfly-go/base/ctx"
 | 
						"mayfly-go/internal/devops/api/vo"
 | 
				
			||||||
	"mayfly-go/base/ginx"
 | 
						"mayfly-go/internal/devops/application"
 | 
				
			||||||
	"mayfly-go/base/utils"
 | 
						"mayfly-go/internal/devops/domain/entity"
 | 
				
			||||||
	"mayfly-go/server/devops/api/form"
 | 
						"mayfly-go/pkg/biz"
 | 
				
			||||||
	"mayfly-go/server/devops/api/vo"
 | 
						"mayfly-go/pkg/ctx"
 | 
				
			||||||
	"mayfly-go/server/devops/application"
 | 
						"mayfly-go/pkg/ginx"
 | 
				
			||||||
	"mayfly-go/server/devops/domain/entity"
 | 
						"mayfly-go/pkg/utils"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/gin-gonic/gin"
 | 
						"github.com/gin-gonic/gin"
 | 
				
			||||||
							
								
								
									
										179
									
								
								server/internal/devops/api/mongo.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										179
									
								
								server/internal/devops/api/mongo.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,179 @@
 | 
				
			|||||||
 | 
					package api
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"context"
 | 
				
			||||||
 | 
						"mayfly-go/internal/devops/api/form"
 | 
				
			||||||
 | 
						"mayfly-go/internal/devops/application"
 | 
				
			||||||
 | 
						"mayfly-go/internal/devops/domain/entity"
 | 
				
			||||||
 | 
						"mayfly-go/pkg/biz"
 | 
				
			||||||
 | 
						"mayfly-go/pkg/ctx"
 | 
				
			||||||
 | 
						"mayfly-go/pkg/ginx"
 | 
				
			||||||
 | 
						"mayfly-go/pkg/utils"
 | 
				
			||||||
 | 
						"strconv"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/gin-gonic/gin"
 | 
				
			||||||
 | 
						"go.mongodb.org/mongo-driver/bson"
 | 
				
			||||||
 | 
						"go.mongodb.org/mongo-driver/bson/primitive"
 | 
				
			||||||
 | 
						"go.mongodb.org/mongo-driver/mongo/options"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Mongo struct {
 | 
				
			||||||
 | 
						MongoApp application.Mongo
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *Mongo) Mongos(rc *ctx.ReqCtx) {
 | 
				
			||||||
 | 
						g := rc.GinCtx
 | 
				
			||||||
 | 
						mc := &entity.Mongo{EnvId: uint64(ginx.QueryInt(g, "envId", 0)),
 | 
				
			||||||
 | 
							ProjectId: uint64(ginx.QueryInt(g, "projectId", 0)),
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						mc.CreatorId = rc.LoginAccount.Id
 | 
				
			||||||
 | 
						rc.ResData = m.MongoApp.GetPageList(mc, ginx.GetPageParam(rc.GinCtx), new([]entity.Mongo))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *Mongo) Save(rc *ctx.ReqCtx) {
 | 
				
			||||||
 | 
						form := &form.Mongo{}
 | 
				
			||||||
 | 
						ginx.BindJsonAndValid(rc.GinCtx, form)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc.ReqParam = form
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mongo := new(entity.Mongo)
 | 
				
			||||||
 | 
						utils.Copy(mongo, form)
 | 
				
			||||||
 | 
						mongo.SetBaseInfo(rc.LoginAccount)
 | 
				
			||||||
 | 
						m.MongoApp.Save(mongo)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *Mongo) DeleteMongo(rc *ctx.ReqCtx) {
 | 
				
			||||||
 | 
						m.MongoApp.Delete(m.GetMongoId(rc.GinCtx))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *Mongo) Databases(rc *ctx.ReqCtx) {
 | 
				
			||||||
 | 
						cli := m.MongoApp.GetMongoCli(m.GetMongoId(rc.GinCtx))
 | 
				
			||||||
 | 
						res, err := cli.ListDatabases(context.TODO(), bson.D{})
 | 
				
			||||||
 | 
						biz.ErrIsNilAppendErr(err, "获取mongo所有库信息失败: %s")
 | 
				
			||||||
 | 
						rc.ResData = res
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *Mongo) Collections(rc *ctx.ReqCtx) {
 | 
				
			||||||
 | 
						cli := m.MongoApp.GetMongoCli(m.GetMongoId(rc.GinCtx))
 | 
				
			||||||
 | 
						db := rc.GinCtx.Query("database")
 | 
				
			||||||
 | 
						biz.NotEmpty(db, "database不能为空")
 | 
				
			||||||
 | 
						ctx := context.TODO()
 | 
				
			||||||
 | 
						res, err := cli.Database(db).ListCollectionNames(ctx, bson.D{})
 | 
				
			||||||
 | 
						biz.ErrIsNilAppendErr(err, "获取库集合信息失败: %s")
 | 
				
			||||||
 | 
						rc.ResData = res
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *Mongo) RunCommand(rc *ctx.ReqCtx) {
 | 
				
			||||||
 | 
						commandForm := new(form.MongoRunCommand)
 | 
				
			||||||
 | 
						ginx.BindJsonAndValid(rc.GinCtx, commandForm)
 | 
				
			||||||
 | 
						cli := m.MongoApp.GetMongoCli(m.GetMongoId(rc.GinCtx))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ctx := context.TODO()
 | 
				
			||||||
 | 
						var bm bson.M
 | 
				
			||||||
 | 
						err := cli.Database(commandForm.Database).RunCommand(
 | 
				
			||||||
 | 
							ctx,
 | 
				
			||||||
 | 
							commandForm.Command,
 | 
				
			||||||
 | 
						).Decode(&bm)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						biz.ErrIsNilAppendErr(err, "执行命令失败: %s")
 | 
				
			||||||
 | 
						rc.ResData = bm
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *Mongo) FindCommand(rc *ctx.ReqCtx) {
 | 
				
			||||||
 | 
						g := rc.GinCtx
 | 
				
			||||||
 | 
						cli := m.MongoApp.GetMongoCli(m.GetMongoId(g))
 | 
				
			||||||
 | 
						commandForm := new(form.MongoFindCommand)
 | 
				
			||||||
 | 
						ginx.BindJsonAndValid(g, commandForm)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						limit := commandForm.Limit
 | 
				
			||||||
 | 
						if limit != 0 {
 | 
				
			||||||
 | 
							biz.IsTrue(limit <= 100, "limit不能超过100")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						opts := options.Find().SetSort(commandForm.Sort).
 | 
				
			||||||
 | 
							SetSkip(commandForm.Skip).
 | 
				
			||||||
 | 
							SetLimit(limit)
 | 
				
			||||||
 | 
						ctx := context.TODO()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						filter := commandForm.Filter
 | 
				
			||||||
 | 
						// 处理_id查询字段,使用ObjectId函数包装
 | 
				
			||||||
 | 
						id, ok := filter["_id"].(string)
 | 
				
			||||||
 | 
						if ok && id != "" {
 | 
				
			||||||
 | 
							objId, err := primitive.ObjectIDFromHex(id)
 | 
				
			||||||
 | 
							if err == nil {
 | 
				
			||||||
 | 
								filter["_id"] = objId
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cur, err := cli.Database(commandForm.Database).Collection(commandForm.Collection).Find(ctx, commandForm.Filter, opts)
 | 
				
			||||||
 | 
						biz.ErrIsNilAppendErr(err, "命令执行失败: %s")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var res []bson.M
 | 
				
			||||||
 | 
						cur.All(ctx, &res)
 | 
				
			||||||
 | 
						rc.ResData = res
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *Mongo) UpdateByIdCommand(rc *ctx.ReqCtx) {
 | 
				
			||||||
 | 
						g := rc.GinCtx
 | 
				
			||||||
 | 
						cli := m.MongoApp.GetMongoCli(m.GetMongoId(g))
 | 
				
			||||||
 | 
						commandForm := new(form.MongoUpdateByIdCommand)
 | 
				
			||||||
 | 
						ginx.BindJsonAndValid(g, commandForm)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 解析docId文档id,如果为string类型则使用ObjectId解析,解析失败则为普通字符串
 | 
				
			||||||
 | 
						docId := commandForm.DocId
 | 
				
			||||||
 | 
						docIdVal, ok := docId.(string)
 | 
				
			||||||
 | 
						if ok {
 | 
				
			||||||
 | 
							objId, err := primitive.ObjectIDFromHex(docIdVal)
 | 
				
			||||||
 | 
							if err == nil {
 | 
				
			||||||
 | 
								docId = objId
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						res, err := cli.Database(commandForm.Database).Collection(commandForm.Collection).UpdateByID(context.TODO(), docId, commandForm.Update)
 | 
				
			||||||
 | 
						biz.ErrIsNilAppendErr(err, "命令执行失败: %s")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc.ReqParam = commandForm
 | 
				
			||||||
 | 
						rc.ResData = res
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *Mongo) DeleteByIdCommand(rc *ctx.ReqCtx) {
 | 
				
			||||||
 | 
						g := rc.GinCtx
 | 
				
			||||||
 | 
						cli := m.MongoApp.GetMongoCli(m.GetMongoId(g))
 | 
				
			||||||
 | 
						commandForm := new(form.MongoUpdateByIdCommand)
 | 
				
			||||||
 | 
						ginx.BindJsonAndValid(g, commandForm)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 解析docId文档id,如果为string类型则使用ObjectId解析,解析失败则为普通字符串
 | 
				
			||||||
 | 
						docId := commandForm.DocId
 | 
				
			||||||
 | 
						docIdVal, ok := docId.(string)
 | 
				
			||||||
 | 
						if ok {
 | 
				
			||||||
 | 
							objId, err := primitive.ObjectIDFromHex(docIdVal)
 | 
				
			||||||
 | 
							if err == nil {
 | 
				
			||||||
 | 
								docId = objId
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						res, err := cli.Database(commandForm.Database).Collection(commandForm.Collection).DeleteOne(context.TODO(), bson.D{{"_id", docId}})
 | 
				
			||||||
 | 
						biz.ErrIsNilAppendErr(err, "命令执行失败: %s")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc.ReqParam = commandForm
 | 
				
			||||||
 | 
						rc.ResData = res
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *Mongo) InsertOneCommand(rc *ctx.ReqCtx) {
 | 
				
			||||||
 | 
						g := rc.GinCtx
 | 
				
			||||||
 | 
						cli := m.MongoApp.GetMongoCli(m.GetMongoId(g))
 | 
				
			||||||
 | 
						commandForm := new(form.MongoInsertCommand)
 | 
				
			||||||
 | 
						ginx.BindJsonAndValid(g, commandForm)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						res, err := cli.Database(commandForm.Database).Collection(commandForm.Collection).InsertOne(context.TODO(), commandForm.Doc)
 | 
				
			||||||
 | 
						biz.ErrIsNilAppendErr(err, "命令执行失败: %s")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc.ReqParam = commandForm
 | 
				
			||||||
 | 
						rc.ResData = res
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 获取请求路径上的mongo id
 | 
				
			||||||
 | 
					func (m *Mongo) GetMongoId(g *gin.Context) uint64 {
 | 
				
			||||||
 | 
						dbId, _ := strconv.Atoi(g.Param("id"))
 | 
				
			||||||
 | 
						biz.IsTrue(dbId > 0, "mongoId错误")
 | 
				
			||||||
 | 
						return uint64(dbId)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -2,14 +2,14 @@ package api
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"mayfly-go/base/biz"
 | 
						"mayfly-go/internal/devops/api/vo"
 | 
				
			||||||
	"mayfly-go/base/ctx"
 | 
						"mayfly-go/internal/devops/application"
 | 
				
			||||||
	"mayfly-go/base/ginx"
 | 
						"mayfly-go/internal/devops/domain/entity"
 | 
				
			||||||
	"mayfly-go/server/devops/api/vo"
 | 
						sys_applicaiton "mayfly-go/internal/sys/application"
 | 
				
			||||||
	"mayfly-go/server/devops/application"
 | 
						sys_entity "mayfly-go/internal/sys/domain/entity"
 | 
				
			||||||
	"mayfly-go/server/devops/domain/entity"
 | 
						"mayfly-go/pkg/biz"
 | 
				
			||||||
	sys_applicaiton "mayfly-go/server/sys/application"
 | 
						"mayfly-go/pkg/ctx"
 | 
				
			||||||
	sys_entity "mayfly-go/server/sys/domain/entity"
 | 
						"mayfly-go/pkg/ginx"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Project struct {
 | 
					type Project struct {
 | 
				
			||||||
@@ -1,14 +1,14 @@
 | 
				
			|||||||
package api
 | 
					package api
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"mayfly-go/base/biz"
 | 
						"mayfly-go/internal/devops/api/form"
 | 
				
			||||||
	"mayfly-go/base/ctx"
 | 
						"mayfly-go/internal/devops/api/vo"
 | 
				
			||||||
	"mayfly-go/base/ginx"
 | 
						"mayfly-go/internal/devops/application"
 | 
				
			||||||
	"mayfly-go/base/utils"
 | 
						"mayfly-go/internal/devops/domain/entity"
 | 
				
			||||||
	"mayfly-go/server/devops/api/form"
 | 
						"mayfly-go/pkg/biz"
 | 
				
			||||||
	"mayfly-go/server/devops/api/vo"
 | 
						"mayfly-go/pkg/ctx"
 | 
				
			||||||
	"mayfly-go/server/devops/application"
 | 
						"mayfly-go/pkg/ginx"
 | 
				
			||||||
	"mayfly-go/server/devops/domain/entity"
 | 
						"mayfly-go/pkg/utils"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
@@ -4,14 +4,15 @@ import (
 | 
				
			|||||||
	"database/sql"
 | 
						"database/sql"
 | 
				
			||||||
	"errors"
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"mayfly-go/base/biz"
 | 
						"mayfly-go/internal/devops/domain/entity"
 | 
				
			||||||
	"mayfly-go/base/cache"
 | 
						"mayfly-go/internal/devops/domain/repository"
 | 
				
			||||||
	"mayfly-go/base/global"
 | 
						"mayfly-go/internal/devops/infrastructure/persistence"
 | 
				
			||||||
	"mayfly-go/base/model"
 | 
						"mayfly-go/pkg/biz"
 | 
				
			||||||
	"mayfly-go/base/utils"
 | 
						"mayfly-go/pkg/cache"
 | 
				
			||||||
	"mayfly-go/server/devops/domain/entity"
 | 
						"mayfly-go/pkg/global"
 | 
				
			||||||
	"mayfly-go/server/devops/domain/repository"
 | 
						"mayfly-go/pkg/model"
 | 
				
			||||||
	"mayfly-go/server/devops/infrastructure/persistence"
 | 
						"mayfly-go/pkg/utils"
 | 
				
			||||||
 | 
						"reflect"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"sync"
 | 
						"sync"
 | 
				
			||||||
@@ -19,7 +20,7 @@ import (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Db interface {
 | 
					type Db interface {
 | 
				
			||||||
	// 分页获取机器脚本信息列表
 | 
						// 分页获取
 | 
				
			||||||
	GetPageList(condition *entity.Db, pageParam *model.PageParam, toEntity interface{}, orderBy ...string) *model.PageResult
 | 
						GetPageList(condition *entity.Db, pageParam *model.PageParam, toEntity interface{}, orderBy ...string) *model.PageResult
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Count(condition *entity.Db) int64
 | 
						Count(condition *entity.Db) int64
 | 
				
			||||||
@@ -158,6 +159,7 @@ func (da *dbAppImpl) GetDbInstance(id uint64, db string) *DbInstance {
 | 
				
			|||||||
	biz.ErrIsNil(err, fmt.Sprintf("Open %s failed, err:%v\n", d.Type, err))
 | 
						biz.ErrIsNil(err, fmt.Sprintf("Open %s failed, err:%v\n", d.Type, err))
 | 
				
			||||||
	perr := DB.Ping()
 | 
						perr := DB.Ping()
 | 
				
			||||||
	if perr != nil {
 | 
						if perr != nil {
 | 
				
			||||||
 | 
							global.Log.Errorf("连接db失败: %s:%d/%s", d.Host, d.Port, db)
 | 
				
			||||||
		panic(biz.NewBizErr(fmt.Sprintf("数据库连接失败: %s", perr.Error())))
 | 
							panic(biz.NewBizErr(fmt.Sprintf("数据库连接失败: %s", perr.Error())))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -217,20 +219,21 @@ type DbInstance struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// 执行查询语句
 | 
					// 执行查询语句
 | 
				
			||||||
// 依次返回 列名数组,结果map,错误
 | 
					// 依次返回 列名数组,结果map,错误
 | 
				
			||||||
func (d *DbInstance) SelectData(sql string) ([]string, []map[string]string, error) {
 | 
					func (d *DbInstance) SelectData(execSql string) ([]string, []map[string]interface{}, error) {
 | 
				
			||||||
	sql = strings.Trim(sql, " ")
 | 
						execSql = strings.Trim(execSql, " ")
 | 
				
			||||||
	isSelect := strings.HasPrefix(sql, "SELECT") || strings.HasPrefix(sql, "select")
 | 
						isSelect := strings.HasPrefix(execSql, "SELECT") || strings.HasPrefix(execSql, "select")
 | 
				
			||||||
	isShow := strings.HasPrefix(sql, "show")
 | 
						isShow := strings.HasPrefix(execSql, "show")
 | 
				
			||||||
 | 
						isExplain := strings.HasPrefix(execSql, "explain")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if !isSelect && !isShow {
 | 
						if !isSelect && !isShow && !isExplain {
 | 
				
			||||||
		return nil, nil, errors.New("该sql非查询语句")
 | 
							return nil, nil, errors.New("该sql非查询语句")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	// 没加limit,则默认限制50条
 | 
						// 没加limit,则默认限制50条
 | 
				
			||||||
	if isSelect && !strings.Contains(sql, "limit") && !strings.Contains(sql, "LIMIT") {
 | 
						if isSelect && !strings.Contains(execSql, "limit") && !strings.Contains(execSql, "LIMIT") {
 | 
				
			||||||
		sql = sql + " LIMIT 50"
 | 
							execSql = execSql + " LIMIT 50"
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rows, err := d.db.Query(sql)
 | 
						rows, err := d.db.Query(execSql)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, nil, err
 | 
							return nil, nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -241,18 +244,18 @@ func (d *DbInstance) SelectData(sql string) ([]string, []map[string]string, erro
 | 
				
			|||||||
			rows.Close()
 | 
								rows.Close()
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}()
 | 
						}()
 | 
				
			||||||
	cols, _ := rows.Columns()
 | 
						colTypes, _ := rows.ColumnTypes()
 | 
				
			||||||
	// 这里表示一行填充数据
 | 
						// 这里表示一行填充数据
 | 
				
			||||||
	scans := make([]interface{}, len(cols))
 | 
						scans := make([]interface{}, len(colTypes))
 | 
				
			||||||
	// 这里表示一行所有列的值,用[]byte表示
 | 
						// 这里表示一行所有列的值,用[]byte表示
 | 
				
			||||||
	vals := make([][]byte, len(cols))
 | 
						vals := make([][]byte, len(colTypes))
 | 
				
			||||||
	// 这里scans引用vals,把数据填充到[]byte里
 | 
						// 这里scans引用vals,把数据填充到[]byte里
 | 
				
			||||||
	for k := range vals {
 | 
						for k := range vals {
 | 
				
			||||||
		scans[k] = &vals[k]
 | 
							scans[k] = &vals[k]
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	result := make([]map[string]string, 0)
 | 
						result := make([]map[string]interface{}, 0)
 | 
				
			||||||
	// 列名
 | 
						// 列名用于前端表头名称按照数据库与查询字段顺序显示
 | 
				
			||||||
	colNames := make([]string, 0)
 | 
						colNames := make([]string, 0)
 | 
				
			||||||
	// 是否第一次遍历,列名数组只需第一次遍历时加入
 | 
						// 是否第一次遍历,列名数组只需第一次遍历时加入
 | 
				
			||||||
	isFirst := true
 | 
						isFirst := true
 | 
				
			||||||
@@ -263,21 +266,52 @@ func (d *DbInstance) SelectData(sql string) ([]string, []map[string]string, erro
 | 
				
			|||||||
			return nil, nil, err
 | 
								return nil, nil, err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		// 每行数据
 | 
							// 每行数据
 | 
				
			||||||
		rowData := make(map[string]string)
 | 
							rowData := make(map[string]interface{})
 | 
				
			||||||
		// 把vals中的数据复制到row中
 | 
							// 把vals中的数据复制到row中
 | 
				
			||||||
		for k, v := range vals {
 | 
							for i, v := range vals {
 | 
				
			||||||
			key := cols[k]
 | 
								colType := colTypes[i]
 | 
				
			||||||
			// 如果是密码字段,则脱敏显示
 | 
								colName := colType.Name()
 | 
				
			||||||
			if key == "password" {
 | 
								// 字段类型名
 | 
				
			||||||
				v = []byte("******")
 | 
								colScanType := colType.ScanType().Name()
 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			if isFirst {
 | 
								if isFirst {
 | 
				
			||||||
				colNames = append(colNames, key)
 | 
									colNames = append(colNames, colName)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if v == nil {
 | 
				
			||||||
 | 
									rowData[colName] = nil
 | 
				
			||||||
 | 
									continue
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			// 这里把[]byte数据转成string
 | 
								// 这里把[]byte数据转成string
 | 
				
			||||||
			rowData[key] = string(v)
 | 
								stringV := string(v)
 | 
				
			||||||
 | 
								if stringV == "" {
 | 
				
			||||||
 | 
									rowData[colName] = stringV
 | 
				
			||||||
 | 
									continue
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if strings.Contains(colScanType, "int") || strings.Contains(colScanType, "Int") {
 | 
				
			||||||
 | 
									intV, _ := strconv.Atoi(stringV)
 | 
				
			||||||
 | 
									switch colType.ScanType().Kind() {
 | 
				
			||||||
 | 
									case reflect.Int8:
 | 
				
			||||||
 | 
										rowData[colName] = int8(intV)
 | 
				
			||||||
 | 
									case reflect.Uint8:
 | 
				
			||||||
 | 
										rowData[colName] = uint8(intV)
 | 
				
			||||||
 | 
									case reflect.Int64:
 | 
				
			||||||
 | 
										rowData[colName] = int64(intV)
 | 
				
			||||||
 | 
									case reflect.Uint64:
 | 
				
			||||||
 | 
										rowData[colName] = uint64(intV)
 | 
				
			||||||
 | 
									case reflect.Uint:
 | 
				
			||||||
 | 
										rowData[colName] = uint(intV)
 | 
				
			||||||
 | 
									default:
 | 
				
			||||||
 | 
										rowData[colName] = intV
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									continue
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if strings.Contains(colScanType, "float") || strings.Contains(colScanType, "Float") {
 | 
				
			||||||
 | 
									floatV, _ := strconv.ParseFloat(stringV, 64)
 | 
				
			||||||
 | 
									rowData[colName] = floatV
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									rowData[colName] = stringV
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		//放入结果集
 | 
							// 放入结果集
 | 
				
			||||||
		result = append(result, rowData)
 | 
							result = append(result, rowData)
 | 
				
			||||||
		isFirst = false
 | 
							isFirst = false
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -302,7 +336,7 @@ func (d *DbInstance) Close() {
 | 
				
			|||||||
// 获取dataSourceName
 | 
					// 获取dataSourceName
 | 
				
			||||||
func getDsn(d *entity.Db) string {
 | 
					func getDsn(d *entity.Db) string {
 | 
				
			||||||
	if d.Type == "mysql" {
 | 
						if d.Type == "mysql" {
 | 
				
			||||||
		return fmt.Sprintf("%s:%s@%s(%s:%d)/%s", d.Username, d.Password, d.Network, d.Host, d.Port, d.Database)
 | 
							return fmt.Sprintf("%s:%s@%s(%s:%d)/%s?timeout=8s", d.Username, d.Password, d.Network, d.Host, d.Port, d.Database)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return ""
 | 
						return ""
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -318,19 +352,19 @@ const (
 | 
				
			|||||||
	// mysql 表信息元数据
 | 
						// mysql 表信息元数据
 | 
				
			||||||
	MYSQL_TABLE_MA = `SELECT table_name tableName, engine, table_comment tableComment, 
 | 
						MYSQL_TABLE_MA = `SELECT table_name tableName, engine, table_comment tableComment, 
 | 
				
			||||||
	create_time createTime from information_schema.tables
 | 
						create_time createTime from information_schema.tables
 | 
				
			||||||
	WHERE table_schema = (SELECT database())`
 | 
						WHERE table_schema = (SELECT database()) LIMIT 2000`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// mysql 表信息
 | 
						// mysql 表信息
 | 
				
			||||||
	MYSQL_TABLE_INFO = `SELECT table_name tableName, table_comment tableComment, table_rows tableRows,
 | 
						MYSQL_TABLE_INFO = `SELECT table_name tableName, table_comment tableComment, table_rows tableRows,
 | 
				
			||||||
	data_length dataLength, index_length indexLength, create_time createTime 
 | 
						data_length dataLength, index_length indexLength, create_time createTime 
 | 
				
			||||||
	FROM information_schema.tables 
 | 
						FROM information_schema.tables 
 | 
				
			||||||
    WHERE table_schema = (SELECT database())`
 | 
					    WHERE table_schema = (SELECT database()) LIMIT 2000`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// mysql 索引信息
 | 
						// mysql 索引信息
 | 
				
			||||||
	MYSQL_INDEX_INFO = `SELECT index_name indexName, column_name columnName, index_type indexType,
 | 
						MYSQL_INDEX_INFO = `SELECT index_name indexName, column_name columnName, index_type indexType,
 | 
				
			||||||
	SEQ_IN_INDEX seqInIndex, INDEX_COMMENT indexComment
 | 
						SEQ_IN_INDEX seqInIndex, INDEX_COMMENT indexComment
 | 
				
			||||||
	FROM information_schema.STATISTICS 
 | 
						FROM information_schema.STATISTICS 
 | 
				
			||||||
    WHERE table_schema = (SELECT database()) AND table_name = '%s'`
 | 
					    WHERE table_schema = (SELECT database()) AND table_name = '%s' LIMIT 500`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 默认每次查询列元信息数量
 | 
						// 默认每次查询列元信息数量
 | 
				
			||||||
	DEFAULT_COLUMN_SIZE = 2000
 | 
						DEFAULT_COLUMN_SIZE = 2000
 | 
				
			||||||
@@ -338,14 +372,14 @@ const (
 | 
				
			|||||||
	// mysql 列信息元数据
 | 
						// mysql 列信息元数据
 | 
				
			||||||
	MYSQL_COLOUMN_MA = `SELECT table_name tableName, column_name columnName, column_type columnType,
 | 
						MYSQL_COLOUMN_MA = `SELECT table_name tableName, column_name columnName, column_type columnType,
 | 
				
			||||||
	column_comment columnComment, column_key columnKey, extra, is_nullable nullable from information_schema.columns
 | 
						column_comment columnComment, column_key columnKey, extra, is_nullable nullable from information_schema.columns
 | 
				
			||||||
	WHERE table_name in (%s) AND table_schema = (SELECT database()) ORDER BY tableName, ordinal_position limit %d, %d`
 | 
						WHERE table_name in (%s) AND table_schema = (SELECT database()) ORDER BY tableName, ordinal_position LIMIT %d, %d`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// mysql 列信息元数据总数
 | 
						// mysql 列信息元数据总数
 | 
				
			||||||
	MYSQL_COLOUMN_MA_COUNT = `SELECT COUNT(*) maNum from information_schema.columns
 | 
						MYSQL_COLOUMN_MA_COUNT = `SELECT COUNT(*) maNum from information_schema.columns
 | 
				
			||||||
	WHERE table_name in (%s) AND table_schema = (SELECT database())`
 | 
						WHERE table_name in (%s) AND table_schema = (SELECT database())`
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (d *DbInstance) GetTableMetedatas() []map[string]string {
 | 
					func (d *DbInstance) GetTableMetedatas() []map[string]interface{} {
 | 
				
			||||||
	var sql string
 | 
						var sql string
 | 
				
			||||||
	if d.Type == "mysql" {
 | 
						if d.Type == "mysql" {
 | 
				
			||||||
		sql = MYSQL_TABLE_MA
 | 
							sql = MYSQL_TABLE_MA
 | 
				
			||||||
@@ -354,7 +388,7 @@ func (d *DbInstance) GetTableMetedatas() []map[string]string {
 | 
				
			|||||||
	return res
 | 
						return res
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (d *DbInstance) GetColumnMetadatas(tableNames ...string) []map[string]string {
 | 
					func (d *DbInstance) GetColumnMetadatas(tableNames ...string) []map[string]interface{} {
 | 
				
			||||||
	var sql, tableName string
 | 
						var sql, tableName string
 | 
				
			||||||
	for i := 0; i < len(tableNames); i++ {
 | 
						for i := 0; i < len(tableNames); i++ {
 | 
				
			||||||
		if i != 0 {
 | 
							if i != 0 {
 | 
				
			||||||
@@ -373,14 +407,14 @@ func (d *DbInstance) GetColumnMetadatas(tableNames ...string) []map[string]strin
 | 
				
			|||||||
	countSql := fmt.Sprintf(countSqlTmp, tableName)
 | 
						countSql := fmt.Sprintf(countSqlTmp, tableName)
 | 
				
			||||||
	_, countRes, _ := d.SelectData(countSql)
 | 
						_, countRes, _ := d.SelectData(countSql)
 | 
				
			||||||
	// 查询出所有列信息总数,手动分页获取所有数据
 | 
						// 查询出所有列信息总数,手动分页获取所有数据
 | 
				
			||||||
	maCount, _ := strconv.Atoi(countRes[0]["maNum"])
 | 
						maCount := int(countRes[0]["maNum"].(int64))
 | 
				
			||||||
	// 计算需要查询的页数
 | 
						// 计算需要查询的页数
 | 
				
			||||||
	pageNum := maCount / DEFAULT_COLUMN_SIZE
 | 
						pageNum := maCount / DEFAULT_COLUMN_SIZE
 | 
				
			||||||
	if maCount%DEFAULT_COLUMN_SIZE > 0 {
 | 
						if maCount%DEFAULT_COLUMN_SIZE > 0 {
 | 
				
			||||||
		pageNum++
 | 
							pageNum++
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	res := make([]map[string]string, 0)
 | 
						res := make([]map[string]interface{}, 0)
 | 
				
			||||||
	for index := 0; index < pageNum; index++ {
 | 
						for index := 0; index < pageNum; index++ {
 | 
				
			||||||
		sql = fmt.Sprintf(sqlTmp, tableName, index*DEFAULT_COLUMN_SIZE, DEFAULT_COLUMN_SIZE)
 | 
							sql = fmt.Sprintf(sqlTmp, tableName, index*DEFAULT_COLUMN_SIZE, DEFAULT_COLUMN_SIZE)
 | 
				
			||||||
		_, result, err := d.SelectData(sql)
 | 
							_, result, err := d.SelectData(sql)
 | 
				
			||||||
@@ -390,7 +424,12 @@ func (d *DbInstance) GetColumnMetadatas(tableNames ...string) []map[string]strin
 | 
				
			|||||||
	return res
 | 
						return res
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (d *DbInstance) GetTableInfos() []map[string]string {
 | 
					// 获取表的主键,目前默认第一列为主键
 | 
				
			||||||
 | 
					func (d *DbInstance) GetPrimaryKey(tablename string) string {
 | 
				
			||||||
 | 
						return d.GetColumnMetadatas(tablename)[0]["columnName"].(string)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (d *DbInstance) GetTableInfos() []map[string]interface{} {
 | 
				
			||||||
	var sql string
 | 
						var sql string
 | 
				
			||||||
	if d.Type == "mysql" {
 | 
						if d.Type == "mysql" {
 | 
				
			||||||
		sql = MYSQL_TABLE_INFO
 | 
							sql = MYSQL_TABLE_INFO
 | 
				
			||||||
@@ -399,7 +438,7 @@ func (d *DbInstance) GetTableInfos() []map[string]string {
 | 
				
			|||||||
	return res
 | 
						return res
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (d *DbInstance) GetTableIndex(tableName string) []map[string]string {
 | 
					func (d *DbInstance) GetTableIndex(tableName string) []map[string]interface{} {
 | 
				
			||||||
	var sql string
 | 
						var sql string
 | 
				
			||||||
	if d.Type == "mysql" {
 | 
						if d.Type == "mysql" {
 | 
				
			||||||
		sql = fmt.Sprintf(MYSQL_INDEX_INFO, tableName)
 | 
							sql = fmt.Sprintf(MYSQL_INDEX_INFO, tableName)
 | 
				
			||||||
@@ -408,7 +447,7 @@ func (d *DbInstance) GetTableIndex(tableName string) []map[string]string {
 | 
				
			|||||||
	return res
 | 
						return res
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (d *DbInstance) GetCreateTableDdl(tableName string) []map[string]string {
 | 
					func (d *DbInstance) GetCreateTableDdl(tableName string) []map[string]interface{} {
 | 
				
			||||||
	var sql string
 | 
						var sql string
 | 
				
			||||||
	if d.Type == "mysql" {
 | 
						if d.Type == "mysql" {
 | 
				
			||||||
		sql = fmt.Sprintf("show create table %s ", tableName)
 | 
							sql = fmt.Sprintf("show create table %s ", tableName)
 | 
				
			||||||
							
								
								
									
										127
									
								
								server/internal/devops/application/db_sql_exec_app.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										127
									
								
								server/internal/devops/application/db_sql_exec_app.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,127 @@
 | 
				
			|||||||
 | 
					package application
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"encoding/json"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"mayfly-go/internal/devops/domain/entity"
 | 
				
			||||||
 | 
						"mayfly-go/internal/devops/domain/repository"
 | 
				
			||||||
 | 
						"mayfly-go/internal/devops/infrastructure/persistence"
 | 
				
			||||||
 | 
						"mayfly-go/pkg/global"
 | 
				
			||||||
 | 
						"mayfly-go/pkg/model"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/xwb1989/sqlparser"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type DbSqlExec interface {
 | 
				
			||||||
 | 
						// 生成sql执行记录
 | 
				
			||||||
 | 
						GenExecLog(loginAccount *model.LoginAccount, dbId uint64, db string, sql string, dbInstance *DbInstance) *entity.DbSqlExec
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 保存sql执行记录
 | 
				
			||||||
 | 
						Save(*entity.DbSqlExec)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 根据条件删除sql执行记录
 | 
				
			||||||
 | 
						DeleteBy(condition *entity.DbSqlExec)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 分页获取
 | 
				
			||||||
 | 
						GetPageList(condition *entity.DbSqlExec, pageParam *model.PageParam, toEntity interface{}, orderBy ...string) *model.PageResult
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type dbSqlExecAppImpl struct {
 | 
				
			||||||
 | 
						dbSqlExecRepo repository.DbSqlExec
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var DbSqlExecApp DbSqlExec = &dbSqlExecAppImpl{
 | 
				
			||||||
 | 
						dbSqlExecRepo: persistence.DbSqlExecDao,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (d *dbSqlExecAppImpl) GenExecLog(loginAccount *model.LoginAccount, dbId uint64, db string, sql string, dbInstance *DbInstance) *entity.DbSqlExec {
 | 
				
			||||||
 | 
						defer func() {
 | 
				
			||||||
 | 
							if err := recover(); err != nil {
 | 
				
			||||||
 | 
								global.Log.Error("生成sql执行记录失败", err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}()
 | 
				
			||||||
 | 
						stmt, err := sqlparser.Parse(sql)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							global.Log.Error("记录数据库sql执行记录失败", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dbSqlExecRecord := new(entity.DbSqlExec)
 | 
				
			||||||
 | 
						dbSqlExecRecord.DbId = dbId
 | 
				
			||||||
 | 
						dbSqlExecRecord.Db = db
 | 
				
			||||||
 | 
						dbSqlExecRecord.Sql = sql
 | 
				
			||||||
 | 
						dbSqlExecRecord.SetBaseInfo(loginAccount)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch stmt := stmt.(type) {
 | 
				
			||||||
 | 
						case *sqlparser.Update:
 | 
				
			||||||
 | 
							doUpdate(stmt, dbInstance, dbSqlExecRecord)
 | 
				
			||||||
 | 
						case *sqlparser.Delete:
 | 
				
			||||||
 | 
							doDelete(stmt, dbInstance, dbSqlExecRecord)
 | 
				
			||||||
 | 
						case *sqlparser.Insert:
 | 
				
			||||||
 | 
							doInsert(stmt, dbSqlExecRecord)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return dbSqlExecRecord
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (d *dbSqlExecAppImpl) Save(dse *entity.DbSqlExec) {
 | 
				
			||||||
 | 
						d.dbSqlExecRepo.Insert(dse)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (d *dbSqlExecAppImpl) DeleteBy(condition *entity.DbSqlExec) {
 | 
				
			||||||
 | 
						d.dbSqlExecRepo.DeleteBy(condition)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (d *dbSqlExecAppImpl) GetPageList(condition *entity.DbSqlExec, pageParam *model.PageParam, toEntity interface{}, orderBy ...string) *model.PageResult {
 | 
				
			||||||
 | 
						return d.dbSqlExecRepo.GetPageList(condition, pageParam, toEntity, orderBy...)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func doUpdate(update *sqlparser.Update, dbInstance *DbInstance, dbSqlExec *entity.DbSqlExec) {
 | 
				
			||||||
 | 
						tableStr := sqlparser.String(update.TableExprs)
 | 
				
			||||||
 | 
						// 可能使用别名,故空格切割
 | 
				
			||||||
 | 
						tableName := strings.Split(tableStr, " ")[0]
 | 
				
			||||||
 | 
						where := sqlparser.String(update.Where)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						updateExprs := update.Exprs
 | 
				
			||||||
 | 
						updateColumns := make([]string, 0)
 | 
				
			||||||
 | 
						for _, v := range updateExprs {
 | 
				
			||||||
 | 
							updateColumns = append(updateColumns, v.Name.Name.String())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 获取表主键列名,排除使用别名
 | 
				
			||||||
 | 
						primaryKey := dbInstance.GetPrimaryKey(tableName)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						updateColumnsAndPrimaryKey := strings.Join(updateColumns, ",") + "," + primaryKey
 | 
				
			||||||
 | 
						// 查询要更新字段数据的旧值,以及主键值
 | 
				
			||||||
 | 
						selectSql := fmt.Sprintf("SELECT %s FROM %s %s LIMIT 200", updateColumnsAndPrimaryKey, tableStr, where)
 | 
				
			||||||
 | 
						_, res, _ := dbInstance.SelectData(selectSql)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bytes, _ := json.Marshal(res)
 | 
				
			||||||
 | 
						dbSqlExec.OldValue = string(bytes)
 | 
				
			||||||
 | 
						dbSqlExec.Table = tableName
 | 
				
			||||||
 | 
						dbSqlExec.Type = entity.DbSqlExecTypeUpdate
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func doDelete(delete *sqlparser.Delete, dbInstance *DbInstance, dbSqlExec *entity.DbSqlExec) {
 | 
				
			||||||
 | 
						tableStr := sqlparser.String(delete.TableExprs)
 | 
				
			||||||
 | 
						// 可能使用别名,故空格切割
 | 
				
			||||||
 | 
						table := strings.Split(tableStr, " ")[0]
 | 
				
			||||||
 | 
						where := sqlparser.String(delete.Where)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 查询删除数据
 | 
				
			||||||
 | 
						selectSql := fmt.Sprintf("SELECT * FROM %s %s LIMIT 200", tableStr, where)
 | 
				
			||||||
 | 
						_, res, _ := dbInstance.SelectData(selectSql)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bytes, _ := json.Marshal(res)
 | 
				
			||||||
 | 
						dbSqlExec.OldValue = string(bytes)
 | 
				
			||||||
 | 
						dbSqlExec.Table = table
 | 
				
			||||||
 | 
						dbSqlExec.Type = entity.DbSqlExecTypeDelete
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func doInsert(insert *sqlparser.Insert, dbSqlExec *entity.DbSqlExec) {
 | 
				
			||||||
 | 
						tableStr := sqlparser.String(insert.Table)
 | 
				
			||||||
 | 
						// 可能使用别名,故空格切割
 | 
				
			||||||
 | 
						table := strings.Split(tableStr, " ")[0]
 | 
				
			||||||
 | 
						dbSqlExec.Table = table
 | 
				
			||||||
 | 
						dbSqlExec.Type = entity.DbSqlExecTypeInsert
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,12 +1,12 @@
 | 
				
			|||||||
package application
 | 
					package application
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"mayfly-go/base/biz"
 | 
						"mayfly-go/internal/devops/domain/entity"
 | 
				
			||||||
	"mayfly-go/base/model"
 | 
						"mayfly-go/internal/devops/domain/repository"
 | 
				
			||||||
	"mayfly-go/server/devops/domain/entity"
 | 
						"mayfly-go/internal/devops/infrastructure/machine"
 | 
				
			||||||
	"mayfly-go/server/devops/domain/repository"
 | 
						"mayfly-go/internal/devops/infrastructure/persistence"
 | 
				
			||||||
	"mayfly-go/server/devops/infrastructure/machine"
 | 
						"mayfly-go/pkg/biz"
 | 
				
			||||||
	"mayfly-go/server/devops/infrastructure/persistence"
 | 
						"mayfly-go/pkg/model"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"gorm.io/gorm"
 | 
						"gorm.io/gorm"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -3,11 +3,11 @@ package application
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
	"io/fs"
 | 
						"io/fs"
 | 
				
			||||||
	"mayfly-go/base/biz"
 | 
						"mayfly-go/internal/devops/domain/entity"
 | 
				
			||||||
	"mayfly-go/base/model"
 | 
						"mayfly-go/internal/devops/domain/repository"
 | 
				
			||||||
	"mayfly-go/server/devops/domain/entity"
 | 
						"mayfly-go/internal/devops/infrastructure/persistence"
 | 
				
			||||||
	"mayfly-go/server/devops/domain/repository"
 | 
						"mayfly-go/pkg/biz"
 | 
				
			||||||
	"mayfly-go/server/devops/infrastructure/persistence"
 | 
						"mayfly-go/pkg/model"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1,11 +1,11 @@
 | 
				
			|||||||
package application
 | 
					package application
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"mayfly-go/base/biz"
 | 
						"mayfly-go/internal/devops/domain/entity"
 | 
				
			||||||
	"mayfly-go/base/model"
 | 
						"mayfly-go/internal/devops/domain/repository"
 | 
				
			||||||
	"mayfly-go/server/devops/domain/entity"
 | 
						"mayfly-go/internal/devops/infrastructure/persistence"
 | 
				
			||||||
	"mayfly-go/server/devops/domain/repository"
 | 
						"mayfly-go/pkg/biz"
 | 
				
			||||||
	"mayfly-go/server/devops/infrastructure/persistence"
 | 
						"mayfly-go/pkg/model"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type MachineScript interface {
 | 
					type MachineScript interface {
 | 
				
			||||||
							
								
								
									
										133
									
								
								server/internal/devops/application/mongo_app.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										133
									
								
								server/internal/devops/application/mongo_app.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,133 @@
 | 
				
			|||||||
 | 
					package application
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"context"
 | 
				
			||||||
 | 
						"mayfly-go/internal/devops/domain/entity"
 | 
				
			||||||
 | 
						"mayfly-go/internal/devops/domain/repository"
 | 
				
			||||||
 | 
						"mayfly-go/internal/devops/infrastructure/persistence"
 | 
				
			||||||
 | 
						"mayfly-go/pkg/biz"
 | 
				
			||||||
 | 
						"mayfly-go/pkg/cache"
 | 
				
			||||||
 | 
						"mayfly-go/pkg/global"
 | 
				
			||||||
 | 
						"mayfly-go/pkg/model"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"go.mongodb.org/mongo-driver/mongo"
 | 
				
			||||||
 | 
						"go.mongodb.org/mongo-driver/mongo/options"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Mongo interface {
 | 
				
			||||||
 | 
						// 分页获取机器脚本信息列表
 | 
				
			||||||
 | 
						GetPageList(condition *entity.Mongo, pageParam *model.PageParam, toEntity interface{}, orderBy ...string) *model.PageResult
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Count(condition *entity.Mongo) int64
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 根据条件获取
 | 
				
			||||||
 | 
						GetBy(condition *entity.Mongo, cols ...string) error
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 根据id获取
 | 
				
			||||||
 | 
						GetById(id uint64, cols ...string) *entity.Mongo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Save(entity *entity.Mongo)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 删除数据库信息
 | 
				
			||||||
 | 
						Delete(id uint64)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 获取mongo连接client
 | 
				
			||||||
 | 
						// @param id mongo id
 | 
				
			||||||
 | 
						GetMongoCli(id uint64) *mongo.Client
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type mongoAppImpl struct {
 | 
				
			||||||
 | 
						mongoRepo repository.Mongo
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var MongoApp Mongo = &mongoAppImpl{
 | 
				
			||||||
 | 
						mongoRepo: persistence.MongoDao,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 分页获取数据库信息列表
 | 
				
			||||||
 | 
					func (d *mongoAppImpl) GetPageList(condition *entity.Mongo, pageParam *model.PageParam, toEntity interface{}, orderBy ...string) *model.PageResult {
 | 
				
			||||||
 | 
						return d.mongoRepo.GetList(condition, pageParam, toEntity, orderBy...)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (d *mongoAppImpl) Count(condition *entity.Mongo) int64 {
 | 
				
			||||||
 | 
						return d.mongoRepo.Count(condition)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 根据条件获取
 | 
				
			||||||
 | 
					func (d *mongoAppImpl) GetBy(condition *entity.Mongo, cols ...string) error {
 | 
				
			||||||
 | 
						return d.mongoRepo.Get(condition, cols...)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 根据id获取
 | 
				
			||||||
 | 
					func (d *mongoAppImpl) GetById(id uint64, cols ...string) *entity.Mongo {
 | 
				
			||||||
 | 
						return d.mongoRepo.GetById(id, cols...)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (d *mongoAppImpl) Delete(id uint64) {
 | 
				
			||||||
 | 
						d.mongoRepo.Delete(id)
 | 
				
			||||||
 | 
						DeleteMongoCache(id)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (d *mongoAppImpl) Save(m *entity.Mongo) {
 | 
				
			||||||
 | 
						if m.Id == 0 {
 | 
				
			||||||
 | 
							d.mongoRepo.Insert(m)
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							// 先关闭连接
 | 
				
			||||||
 | 
							DeleteMongoCache(m.Id)
 | 
				
			||||||
 | 
							d.mongoRepo.Update(m)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (d *mongoAppImpl) GetMongoCli(id uint64) *mongo.Client {
 | 
				
			||||||
 | 
						cli, err := GetMongoCli(id, func(u uint64) string {
 | 
				
			||||||
 | 
							mongo := d.GetById(id)
 | 
				
			||||||
 | 
							biz.NotNil(mongo, "mongo信息不存在")
 | 
				
			||||||
 | 
							return mongo.Uri
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						biz.ErrIsNilAppendErr(err, "连接mongo失败: %s")
 | 
				
			||||||
 | 
						return cli
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// -----------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//mongo客户端连接缓存,30分钟内没有访问则会被关闭
 | 
				
			||||||
 | 
					var mongoCliCache = cache.NewTimedCache(30*time.Minute, 5*time.Second).
 | 
				
			||||||
 | 
						WithUpdateAccessTime(true).
 | 
				
			||||||
 | 
						OnEvicted(func(key interface{}, value interface{}) {
 | 
				
			||||||
 | 
							global.Log.Info("关闭mongo连接: id = ", key)
 | 
				
			||||||
 | 
							value.(*mongo.Client).Disconnect(context.TODO())
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func GetMongoCli(mongoId uint64, getMongoUri func(uint64) string) (*mongo.Client, error) {
 | 
				
			||||||
 | 
						cli, err := mongoCliCache.ComputeIfAbsent(mongoId, func(key interface{}) (interface{}, error) {
 | 
				
			||||||
 | 
							c, err := connect(getMongoUri(mongoId))
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return nil, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return c, nil
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if cli != nil {
 | 
				
			||||||
 | 
							return cli.(*mongo.Client), err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil, err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func DeleteMongoCache(mongoId uint64) {
 | 
				
			||||||
 | 
						mongoCliCache.Delete(mongoId)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 连接mongo,并返回client
 | 
				
			||||||
 | 
					func connect(uri string) (*mongo.Client, error) {
 | 
				
			||||||
 | 
						ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
 | 
				
			||||||
 | 
						defer cancel()
 | 
				
			||||||
 | 
						client, err := mongo.Connect(ctx, options.Client().ApplyURI(uri).SetMaxPoolSize(2))
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if err = client.Ping(context.TODO(), nil); err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return client, err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,11 +1,11 @@
 | 
				
			|||||||
package application
 | 
					package application
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"mayfly-go/base/biz"
 | 
						"mayfly-go/internal/devops/domain/entity"
 | 
				
			||||||
	"mayfly-go/base/model"
 | 
						"mayfly-go/internal/devops/domain/repository"
 | 
				
			||||||
	"mayfly-go/server/devops/domain/entity"
 | 
						"mayfly-go/internal/devops/infrastructure/persistence"
 | 
				
			||||||
	"mayfly-go/server/devops/domain/repository"
 | 
						"mayfly-go/pkg/biz"
 | 
				
			||||||
	"mayfly-go/server/devops/infrastructure/persistence"
 | 
						"mayfly-go/pkg/model"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Project interface {
 | 
					type Project interface {
 | 
				
			||||||
@@ -2,13 +2,13 @@ package application
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"mayfly-go/base/biz"
 | 
						"mayfly-go/internal/devops/domain/entity"
 | 
				
			||||||
	"mayfly-go/base/cache"
 | 
						"mayfly-go/internal/devops/domain/repository"
 | 
				
			||||||
	"mayfly-go/base/global"
 | 
						"mayfly-go/internal/devops/infrastructure/persistence"
 | 
				
			||||||
	"mayfly-go/base/model"
 | 
						"mayfly-go/pkg/biz"
 | 
				
			||||||
	"mayfly-go/server/devops/domain/entity"
 | 
						"mayfly-go/pkg/cache"
 | 
				
			||||||
	"mayfly-go/server/devops/domain/repository"
 | 
						"mayfly-go/pkg/global"
 | 
				
			||||||
	"mayfly-go/server/devops/infrastructure/persistence"
 | 
						"mayfly-go/pkg/model"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/go-redis/redis"
 | 
						"github.com/go-redis/redis"
 | 
				
			||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package entity
 | 
					package entity
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"mayfly-go/base/model"
 | 
						"mayfly-go/pkg/model"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Db struct {
 | 
					type Db struct {
 | 
				
			||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package entity
 | 
					package entity
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"mayfly-go/base/model"
 | 
						"mayfly-go/pkg/model"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type DbSql struct {
 | 
					type DbSql struct {
 | 
				
			||||||
							
								
								
									
										22
									
								
								server/internal/devops/domain/entity/db_sql_exec.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								server/internal/devops/domain/entity/db_sql_exec.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
				
			|||||||
 | 
					package entity
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import "mayfly-go/pkg/model"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 数据库sql执行记录
 | 
				
			||||||
 | 
					type DbSqlExec struct {
 | 
				
			||||||
 | 
						model.Model `orm:"-"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						DbId     uint64 `json:"dbId"`
 | 
				
			||||||
 | 
						Db       string `json:"db"`
 | 
				
			||||||
 | 
						Table    string `json:"table"`
 | 
				
			||||||
 | 
						Type     int8   `json:"type"` // 类型
 | 
				
			||||||
 | 
						Sql      string `json:"sql"`  // 执行的sql
 | 
				
			||||||
 | 
						OldValue string `json:"oldValue"`
 | 
				
			||||||
 | 
						Remark   string `json:"remark"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						DbSqlExecTypeUpdate int8 = 1 // 更新类型
 | 
				
			||||||
 | 
						DbSqlExecTypeDelete int8 = 2 // 删除类型
 | 
				
			||||||
 | 
						DbSqlExecTypeInsert int8 = 3 // 插入类型
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package entity
 | 
					package entity
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"mayfly-go/base/model"
 | 
						"mayfly-go/pkg/model"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Machine struct {
 | 
					type Machine struct {
 | 
				
			||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
package entity
 | 
					package entity
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import "mayfly-go/base/model"
 | 
					import "mayfly-go/pkg/model"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type MachineFile struct {
 | 
					type MachineFile struct {
 | 
				
			||||||
	model.Model
 | 
						model.Model
 | 
				
			||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
package entity
 | 
					package entity
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import "mayfly-go/base/model"
 | 
					import "mayfly-go/pkg/model"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type MachineScript struct {
 | 
					type MachineScript struct {
 | 
				
			||||||
	model.Model
 | 
						model.Model
 | 
				
			||||||
							
								
								
									
										14
									
								
								server/internal/devops/domain/entity/mongo.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								server/internal/devops/domain/entity/mongo.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					package entity
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import "mayfly-go/pkg/model"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Mongo struct {
 | 
				
			||||||
 | 
						model.Model
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Name      string `orm:"column(name)" json:"name"`
 | 
				
			||||||
 | 
						Uri       string `orm:"column(uri)" json:"uri"`
 | 
				
			||||||
 | 
						ProjectId uint64 `json:"projectId"`
 | 
				
			||||||
 | 
						Project   string `json:"project"`
 | 
				
			||||||
 | 
						EnvId     uint64 `json:"envId"`
 | 
				
			||||||
 | 
						Env       string `json:"env"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
package entity
 | 
					package entity
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import "mayfly-go/base/model"
 | 
					import "mayfly-go/pkg/model"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 项目
 | 
					// 项目
 | 
				
			||||||
type Project struct {
 | 
					type Project struct {
 | 
				
			||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
package entity
 | 
					package entity
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import "mayfly-go/base/model"
 | 
					import "mayfly-go/pkg/model"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 项目环境
 | 
					// 项目环境
 | 
				
			||||||
type ProjectEnv struct {
 | 
					type ProjectEnv struct {
 | 
				
			||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
package entity
 | 
					package entity
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import "mayfly-go/base/model"
 | 
					import "mayfly-go/pkg/model"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 项目成员,用于对项目下组件的访问控制
 | 
					// 项目成员,用于对项目下组件的访问控制
 | 
				
			||||||
type ProjectMember struct {
 | 
					type ProjectMember struct {
 | 
				
			||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package entity
 | 
					package entity
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"mayfly-go/base/model"
 | 
						"mayfly-go/pkg/model"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Redis struct {
 | 
					type Redis struct {
 | 
				
			||||||
@@ -1,8 +1,8 @@
 | 
				
			|||||||
package repository
 | 
					package repository
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"mayfly-go/base/model"
 | 
						"mayfly-go/internal/devops/domain/entity"
 | 
				
			||||||
	"mayfly-go/server/devops/domain/entity"
 | 
						"mayfly-go/pkg/model"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Db interface {
 | 
					type Db interface {
 | 
				
			||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
package repository
 | 
					package repository
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import "mayfly-go/server/devops/domain/entity"
 | 
					import "mayfly-go/internal/devops/domain/entity"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type DbSql interface {
 | 
					type DbSql interface {
 | 
				
			||||||
	DeleteBy(condition *entity.DbSql)
 | 
						DeleteBy(condition *entity.DbSql)
 | 
				
			||||||
							
								
								
									
										15
									
								
								server/internal/devops/domain/repository/db_sql_exec.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								server/internal/devops/domain/repository/db_sql_exec.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
				
			|||||||
 | 
					package repository
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"mayfly-go/internal/devops/domain/entity"
 | 
				
			||||||
 | 
						"mayfly-go/pkg/model"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type DbSqlExec interface {
 | 
				
			||||||
 | 
						Insert(d *entity.DbSqlExec)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						DeleteBy(condition *entity.DbSqlExec)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 分页获取
 | 
				
			||||||
 | 
						GetPageList(condition *entity.DbSqlExec, pageParam *model.PageParam, toEntity interface{}, orderBy ...string) *model.PageResult
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,8 +1,8 @@
 | 
				
			|||||||
package repository
 | 
					package repository
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"mayfly-go/base/model"
 | 
						"mayfly-go/internal/devops/domain/entity"
 | 
				
			||||||
	"mayfly-go/server/devops/domain/entity"
 | 
						"mayfly-go/pkg/model"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Machine interface {
 | 
					type Machine interface {
 | 
				
			||||||
@@ -1,8 +1,8 @@
 | 
				
			|||||||
package repository
 | 
					package repository
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"mayfly-go/base/model"
 | 
						"mayfly-go/internal/devops/domain/entity"
 | 
				
			||||||
	"mayfly-go/server/devops/domain/entity"
 | 
						"mayfly-go/pkg/model"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type MachineFile interface {
 | 
					type MachineFile interface {
 | 
				
			||||||
@@ -1,8 +1,8 @@
 | 
				
			|||||||
package repository
 | 
					package repository
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"mayfly-go/base/model"
 | 
						"mayfly-go/internal/devops/domain/entity"
 | 
				
			||||||
	"mayfly-go/server/devops/domain/entity"
 | 
						"mayfly-go/pkg/model"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type MachineScript interface {
 | 
					type MachineScript interface {
 | 
				
			||||||
							
								
								
									
										25
									
								
								server/internal/devops/domain/repository/mongo.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								server/internal/devops/domain/repository/mongo.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					package repository
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"mayfly-go/internal/devops/domain/entity"
 | 
				
			||||||
 | 
						"mayfly-go/pkg/model"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Mongo interface {
 | 
				
			||||||
 | 
						// 分页获取列表
 | 
				
			||||||
 | 
						GetList(condition *entity.Mongo, pageParam *model.PageParam, toEntity interface{}, orderBy ...string) *model.PageResult
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Count(condition *entity.Mongo) int64
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 根据条件获取
 | 
				
			||||||
 | 
						Get(condition *entity.Mongo, cols ...string) error
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 根据id获取
 | 
				
			||||||
 | 
						GetById(id uint64, cols ...string) *entity.Mongo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Insert(db *entity.Mongo)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Update(db *entity.Mongo)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Delete(id uint64)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,8 +1,8 @@
 | 
				
			|||||||
package repository
 | 
					package repository
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"mayfly-go/base/model"
 | 
						"mayfly-go/internal/devops/domain/entity"
 | 
				
			||||||
	"mayfly-go/server/devops/domain/entity"
 | 
						"mayfly-go/pkg/model"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Project interface {
 | 
					type Project interface {
 | 
				
			||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
package repository
 | 
					package repository
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import "mayfly-go/server/devops/domain/entity"
 | 
					import "mayfly-go/internal/devops/domain/entity"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type ProjectEnv interface {
 | 
					type ProjectEnv interface {
 | 
				
			||||||
	// 获取项目环境列表
 | 
						// 获取项目环境列表
 | 
				
			||||||
@@ -1,8 +1,8 @@
 | 
				
			|||||||
package repository
 | 
					package repository
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"mayfly-go/base/model"
 | 
						"mayfly-go/internal/devops/domain/entity"
 | 
				
			||||||
	"mayfly-go/server/devops/domain/entity"
 | 
						"mayfly-go/pkg/model"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type ProjectMemeber interface {
 | 
					type ProjectMemeber interface {
 | 
				
			||||||
@@ -1,8 +1,8 @@
 | 
				
			|||||||
package repository
 | 
					package repository
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"mayfly-go/base/model"
 | 
						"mayfly-go/internal/devops/domain/entity"
 | 
				
			||||||
	"mayfly-go/server/devops/domain/entity"
 | 
						"mayfly-go/pkg/model"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Redis interface {
 | 
					type Redis interface {
 | 
				
			||||||
@@ -3,10 +3,10 @@ package machine
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"errors"
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"mayfly-go/base/biz"
 | 
						"mayfly-go/internal/devops/domain/entity"
 | 
				
			||||||
	"mayfly-go/base/cache"
 | 
						"mayfly-go/pkg/biz"
 | 
				
			||||||
	"mayfly-go/base/global"
 | 
						"mayfly-go/pkg/cache"
 | 
				
			||||||
	"mayfly-go/server/devops/domain/entity"
 | 
						"mayfly-go/pkg/global"
 | 
				
			||||||
	"net"
 | 
						"net"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -2,7 +2,7 @@ package machine
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"mayfly-go/base/utils"
 | 
						"mayfly-go/pkg/utils"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -4,7 +4,7 @@ import (
 | 
				
			|||||||
	"bytes"
 | 
						"bytes"
 | 
				
			||||||
	"encoding/json"
 | 
						"encoding/json"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
	"mayfly-go/base/global"
 | 
						"mayfly-go/pkg/global"
 | 
				
			||||||
	"sync"
 | 
						"sync"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -2,10 +2,10 @@ package persistence
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"mayfly-go/base/biz"
 | 
						"mayfly-go/internal/devops/domain/entity"
 | 
				
			||||||
	"mayfly-go/base/model"
 | 
						"mayfly-go/internal/devops/domain/repository"
 | 
				
			||||||
	"mayfly-go/server/devops/domain/entity"
 | 
						"mayfly-go/pkg/biz"
 | 
				
			||||||
	"mayfly-go/server/devops/domain/repository"
 | 
						"mayfly-go/pkg/model"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type dbRepo struct{}
 | 
					type dbRepo struct{}
 | 
				
			||||||
@@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					package persistence
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"mayfly-go/internal/devops/domain/entity"
 | 
				
			||||||
 | 
						"mayfly-go/internal/devops/domain/repository"
 | 
				
			||||||
 | 
						"mayfly-go/pkg/biz"
 | 
				
			||||||
 | 
						"mayfly-go/pkg/model"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type dbSqlExecRepo struct{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var DbSqlExecDao repository.DbSqlExec = &dbSqlExecRepo{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (d *dbSqlExecRepo) Insert(dse *entity.DbSqlExec) {
 | 
				
			||||||
 | 
						model.Insert(dse)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (d *dbSqlExecRepo) DeleteBy(condition *entity.DbSqlExec) {
 | 
				
			||||||
 | 
						biz.ErrIsNil(model.DeleteByCondition(condition), "删除sql执行记录失败")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 分页获取
 | 
				
			||||||
 | 
					func (d *dbSqlExecRepo) GetPageList(condition *entity.DbSqlExec, pageParam *model.PageParam, toEntity interface{}, orderBy ...string) *model.PageResult {
 | 
				
			||||||
 | 
						return model.GetPage(pageParam, condition, toEntity, orderBy...)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,10 +1,10 @@
 | 
				
			|||||||
package persistence
 | 
					package persistence
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"mayfly-go/base/biz"
 | 
						"mayfly-go/internal/devops/domain/entity"
 | 
				
			||||||
	"mayfly-go/base/model"
 | 
						"mayfly-go/internal/devops/domain/repository"
 | 
				
			||||||
	"mayfly-go/server/devops/domain/entity"
 | 
						"mayfly-go/pkg/biz"
 | 
				
			||||||
	"mayfly-go/server/devops/domain/repository"
 | 
						"mayfly-go/pkg/model"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type dbSqlRepo struct{}
 | 
					type dbSqlRepo struct{}
 | 
				
			||||||
@@ -1,10 +1,10 @@
 | 
				
			|||||||
package persistence
 | 
					package persistence
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"mayfly-go/base/biz"
 | 
						"mayfly-go/internal/devops/domain/entity"
 | 
				
			||||||
	"mayfly-go/base/model"
 | 
						"mayfly-go/internal/devops/domain/repository"
 | 
				
			||||||
	"mayfly-go/server/devops/domain/entity"
 | 
						"mayfly-go/pkg/biz"
 | 
				
			||||||
	"mayfly-go/server/devops/domain/repository"
 | 
						"mayfly-go/pkg/model"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type machineFileRepo struct{}
 | 
					type machineFileRepo struct{}
 | 
				
			||||||
@@ -2,9 +2,9 @@ package persistence
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"mayfly-go/base/model"
 | 
						"mayfly-go/internal/devops/domain/entity"
 | 
				
			||||||
	"mayfly-go/server/devops/domain/entity"
 | 
						"mayfly-go/internal/devops/domain/repository"
 | 
				
			||||||
	"mayfly-go/server/devops/domain/repository"
 | 
						"mayfly-go/pkg/model"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type machineRepo struct{}
 | 
					type machineRepo struct{}
 | 
				
			||||||
@@ -1,10 +1,10 @@
 | 
				
			|||||||
package persistence
 | 
					package persistence
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"mayfly-go/base/biz"
 | 
						"mayfly-go/internal/devops/domain/entity"
 | 
				
			||||||
	"mayfly-go/base/model"
 | 
						"mayfly-go/internal/devops/domain/repository"
 | 
				
			||||||
	"mayfly-go/server/devops/domain/entity"
 | 
						"mayfly-go/pkg/biz"
 | 
				
			||||||
	"mayfly-go/server/devops/domain/repository"
 | 
						"mayfly-go/pkg/model"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type machineScriptRepo struct{}
 | 
					type machineScriptRepo struct{}
 | 
				
			||||||
@@ -0,0 +1,61 @@
 | 
				
			|||||||
 | 
					package persistence
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"mayfly-go/internal/devops/domain/entity"
 | 
				
			||||||
 | 
						"mayfly-go/internal/devops/domain/repository"
 | 
				
			||||||
 | 
						"mayfly-go/pkg/biz"
 | 
				
			||||||
 | 
						"mayfly-go/pkg/model"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type mongoRepo struct{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var MongoDao repository.Mongo = &mongoRepo{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 分页获取数据库信息列表
 | 
				
			||||||
 | 
					func (d *mongoRepo) GetList(condition *entity.Mongo, pageParam *model.PageParam, toEntity interface{}, orderBy ...string) *model.PageResult {
 | 
				
			||||||
 | 
						sql := "SELECT d.* FROM t_mongo d JOIN t_project_member pm ON d.project_id = pm.project_id WHERE 1 = 1 "
 | 
				
			||||||
 | 
						if condition.CreatorId != 0 {
 | 
				
			||||||
 | 
							// 使用创建者id模拟项目成员id
 | 
				
			||||||
 | 
							sql = fmt.Sprintf("%s AND pm.account_id = %d", sql, condition.CreatorId)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if condition.ProjectId != 0 {
 | 
				
			||||||
 | 
							sql = fmt.Sprintf("%s AND d.project_id = %d", sql, condition.ProjectId)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if condition.EnvId != 0 {
 | 
				
			||||||
 | 
							sql = fmt.Sprintf("%s AND d.env_id = %d", sql, condition.EnvId)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						sql = sql + " ORDER BY d.create_time DESC"
 | 
				
			||||||
 | 
						return model.GetPageBySql(sql, pageParam, toEntity)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (d *mongoRepo) Count(condition *entity.Mongo) int64 {
 | 
				
			||||||
 | 
						return model.CountBy(condition)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 根据条件获取
 | 
				
			||||||
 | 
					func (d *mongoRepo) Get(condition *entity.Mongo, cols ...string) error {
 | 
				
			||||||
 | 
						return model.GetBy(condition, cols...)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 根据id获取
 | 
				
			||||||
 | 
					func (d *mongoRepo) GetById(id uint64, cols ...string) *entity.Mongo {
 | 
				
			||||||
 | 
						db := new(entity.Mongo)
 | 
				
			||||||
 | 
						if err := model.GetById(db, id, cols...); err != nil {
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return db
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (d *mongoRepo) Insert(db *entity.Mongo) {
 | 
				
			||||||
 | 
						biz.ErrIsNil(model.Insert(db), "新增mongo信息失败")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (d *mongoRepo) Update(db *entity.Mongo) {
 | 
				
			||||||
 | 
						biz.ErrIsNil(model.UpdateById(db), "更新mongo信息失败")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (d *mongoRepo) Delete(id uint64) {
 | 
				
			||||||
 | 
						model.DeleteById(new(entity.Mongo), id)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,10 +1,10 @@
 | 
				
			|||||||
package persistence
 | 
					package persistence
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"mayfly-go/base/biz"
 | 
						"mayfly-go/internal/devops/domain/entity"
 | 
				
			||||||
	"mayfly-go/base/model"
 | 
						"mayfly-go/internal/devops/domain/repository"
 | 
				
			||||||
	"mayfly-go/server/devops/domain/entity"
 | 
						"mayfly-go/pkg/biz"
 | 
				
			||||||
	"mayfly-go/server/devops/domain/repository"
 | 
						"mayfly-go/pkg/model"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type projectEnvRepo struct{}
 | 
					type projectEnvRepo struct{}
 | 
				
			||||||
@@ -1,10 +1,10 @@
 | 
				
			|||||||
package persistence
 | 
					package persistence
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"mayfly-go/base/biz"
 | 
						"mayfly-go/internal/devops/domain/entity"
 | 
				
			||||||
	"mayfly-go/base/model"
 | 
						"mayfly-go/internal/devops/domain/repository"
 | 
				
			||||||
	"mayfly-go/server/devops/domain/entity"
 | 
						"mayfly-go/pkg/biz"
 | 
				
			||||||
	"mayfly-go/server/devops/domain/repository"
 | 
						"mayfly-go/pkg/model"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type projectMemeberRepo struct{}
 | 
					type projectMemeberRepo struct{}
 | 
				
			||||||
@@ -1,10 +1,10 @@
 | 
				
			|||||||
package persistence
 | 
					package persistence
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"mayfly-go/base/biz"
 | 
						"mayfly-go/internal/devops/domain/entity"
 | 
				
			||||||
	"mayfly-go/base/model"
 | 
						"mayfly-go/internal/devops/domain/repository"
 | 
				
			||||||
	"mayfly-go/server/devops/domain/entity"
 | 
						"mayfly-go/pkg/biz"
 | 
				
			||||||
	"mayfly-go/server/devops/domain/repository"
 | 
						"mayfly-go/pkg/model"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type projectRepo struct{}
 | 
					type projectRepo struct{}
 | 
				
			||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user