mirror of
https://gitee.com/dromara/mayfly-go
synced 2025-11-03 16:00:25 +08:00
feat: 优化
This commit is contained in:
@@ -111,14 +111,24 @@ function buildDocker() {
|
||||
echo_yellow "-------------------构建docker镜像结束-------------------"
|
||||
}
|
||||
|
||||
function buildxDocker() {
|
||||
echo_yellow "-------------------docker buildx构建镜像开始-------------------"
|
||||
imageVersion=$1
|
||||
cd ${server_folder}
|
||||
imageName="mayflygo/mayfly-go:${imageVersion}"
|
||||
docker buildx build --push --platform linux/amd64,linux/arm64 -t "${imageName}" .
|
||||
echo_green "docker多版本镜像构建完成->[${imageName}]"
|
||||
echo_yellow "-------------------docker buildx构建镜像结束-------------------"
|
||||
}
|
||||
|
||||
function runBuild() {
|
||||
read -p "请选择构建版本[0|其他->全部 1->linux-amd64 2->linux-arm64 3->windows 4->mac 5->docker]: " buildType
|
||||
read -p "请选择构建版本[0|其他->除docker镜像外其他 1->linux-amd64 2->linux-arm64 3->windows 4->mac 5->docker 6->docker buildx]: " buildType
|
||||
|
||||
toPath="."
|
||||
imageVersion="latest"
|
||||
copyDocScript="1"
|
||||
|
||||
if [ "${buildType}" != "5" ] ; then
|
||||
if [[ "${buildType}" != "5" ]] && [[ "${buildType}" != "6" ]] ; then
|
||||
# 构建结果的目的路径
|
||||
read -p "请输入构建产物输出目录[默认当前路径]: " toPath
|
||||
if [ ! -d ${toPath} ] ; then
|
||||
@@ -139,7 +149,7 @@ function runBuild() {
|
||||
toPath=`pwd`
|
||||
fi
|
||||
|
||||
if [[ "${buildType}" == "5" ]] || [[ "${buildType}" == "0" ]] ; then
|
||||
if [[ "${buildType}" == "5" ]] || [[ "${buildType}" == "0" ]] || [[ "${buildType}" == "6" ]] ; then
|
||||
read -p "请输入docker镜像版本号[默认latest]: " imageVersion
|
||||
|
||||
if [ "${imageVersion}" == "" ] ; then
|
||||
@@ -169,12 +179,14 @@ function runBuild() {
|
||||
"5")
|
||||
buildDocker ${imageVersion}
|
||||
;;
|
||||
"6")
|
||||
buildxDocker ${imageVersion}
|
||||
;;
|
||||
*)
|
||||
buildLinuxAmd64 ${toPath} ${copyDocScript}
|
||||
buildLinuxArm64 ${toPath} ${copyDocScript}
|
||||
buildWindows ${toPath} ${copyDocScript}
|
||||
buildMac ${toPath} ${copyDocScript}
|
||||
buildDocker ${imageVersion}
|
||||
;;
|
||||
esac
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ const config = {
|
||||
baseWsUrl: `${(window as any).globalConfig.BaseWsUrl || `${location.protocol == 'https:' ? 'wss:' : 'ws:'}//${getBaseApiUrl()}`}/api`,
|
||||
|
||||
// 系统版本
|
||||
version: 'v1.3.1'
|
||||
version: 'v1.4.0'
|
||||
}
|
||||
|
||||
export default config
|
||||
@@ -1,5 +1,6 @@
|
||||
<template>
|
||||
<div style="display: inline-flex; justify-content: center; align-items: center; cursor: pointer;">
|
||||
<div
|
||||
style="display: inline-flex; justify-content: center; align-items: center; cursor: pointer;vertical-align: middle;">
|
||||
<el-popover @show="showTagInfo" placement="right-end" title="标签信息" :width="300" trigger="hover">
|
||||
<template #reference>
|
||||
<el-icon>
|
||||
|
||||
@@ -1,18 +1,34 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-row type="flex">
|
||||
<el-col :span="24">
|
||||
<el-button type="primary" icon="plus"
|
||||
@click="addQueryTab({ id: state.dbId, type: state.dbType }, state.db)"
|
||||
<el-row>
|
||||
<el-col :span="4">
|
||||
<el-button type="primary" icon="plus" @click="addQueryTab({ id: nowDbInst.id }, state.db)"
|
||||
size="small">新建查询</el-button>
|
||||
</el-col>
|
||||
<el-col :span="20" v-if="state.db">
|
||||
<el-descriptions :column="4" size="small" border style="height: 10px">
|
||||
<el-descriptions-item label-align="right" label="tag">{{ nowDbInst.tagPath }}</el-descriptions-item>
|
||||
|
||||
<el-descriptions-item label="实例" label-align="right">
|
||||
{{ nowDbInst.id }}
|
||||
<el-divider direction="vertical" border-style="dashed" />
|
||||
{{ nowDbInst.type }}
|
||||
<el-divider direction="vertical" border-style="dashed" />
|
||||
{{ nowDbInst.name }}
|
||||
</el-descriptions-item>
|
||||
|
||||
<el-descriptions-item label="库名" label-align="right">{{ state.db }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row type="flex">
|
||||
<el-col :span="4" style="border-left: 1px solid #eee; margin-top: 10px">
|
||||
<InstanceTree ref="instanceTreeRef" @change-instance="changeInstance" @change-schema="changeSchema"
|
||||
@clickSqlName="onClickSqlName" @clickSchemaTable="loadTableData" />
|
||||
</el-col>
|
||||
<el-col :span="20">
|
||||
<el-container id="data-exec" style="border-left: 1px solid #eee; margin-top: 10px">
|
||||
<el-tabs @tab-remove="remoteTab" @tab-click="onDataTabClick" style="width: 100%"
|
||||
<el-tabs @tab-remove="onRemoveTab" @tab-change="onTabChange" style="width: 100%"
|
||||
v-model="state.activeName">
|
||||
|
||||
<el-tab-pane closable v-for="dt in state.tabs.values()" :key="dt.key" :label="dt.key"
|
||||
@@ -37,7 +53,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, reactive, ref, Ref } from 'vue';
|
||||
import { onMounted, reactive, ref, Ref, toRefs } from 'vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
|
||||
import { language as sqlLanguage } from 'monaco-editor/esm/vs/basic-languages/mysql/mysql.js';
|
||||
@@ -53,8 +69,10 @@ const instanceTreeRef = ref(null) as Ref;
|
||||
|
||||
const tabs: Map<string, TabInfo> = new Map();
|
||||
const state = reactive({
|
||||
dbId: null, // 当前选中操作的数据库实例
|
||||
dbType: '',
|
||||
/**
|
||||
* 当前操作的数据库实例
|
||||
*/
|
||||
nowDbInst: {} as DbInst,
|
||||
db: '', // 当前操作的数据库
|
||||
activeName: 'Query',
|
||||
tabs,
|
||||
@@ -66,6 +84,10 @@ const state = reactive({
|
||||
},
|
||||
});
|
||||
|
||||
const {
|
||||
nowDbInst,
|
||||
} = toRefs(state);
|
||||
|
||||
onMounted(() => {
|
||||
self.completionItemProvider?.dispose()
|
||||
setHeight();
|
||||
@@ -85,15 +107,13 @@ const setHeight = () => {
|
||||
|
||||
// 选择数据库实例
|
||||
const changeInstance = (inst: any, fn?: Function) => {
|
||||
state.dbId = inst.id
|
||||
state.dbType = inst.type
|
||||
fn && fn()
|
||||
}
|
||||
|
||||
// 选择数据库
|
||||
const changeSchema = (inst: any, schema: string) => {
|
||||
changeInstance(inst)
|
||||
state.db = schema
|
||||
state.nowDbInst = DbInst.getOrNewInst(inst);
|
||||
state.db = schema;
|
||||
}
|
||||
|
||||
// 加载选中的表数据,即新增表数据操作tab
|
||||
@@ -113,7 +133,6 @@ const loadTableData = async (inst: any, schema: string, tableName: string) => {
|
||||
tab = new TabInfo();
|
||||
tab.key = label;
|
||||
tab.dbId = inst.id;
|
||||
tab.dbType = inst.type;
|
||||
tab.db = schema;
|
||||
tab.type = TabType.TableData;
|
||||
tab.params = {
|
||||
@@ -124,8 +143,8 @@ const loadTableData = async (inst: any, schema: string, tableName: string) => {
|
||||
|
||||
// 新建查询panel
|
||||
const addQueryTab = async (inst: any, db: string, sqlName: string = '') => {
|
||||
if (!db) {
|
||||
ElMessage.warning('请选择schema')
|
||||
if (!db || !inst.id) {
|
||||
ElMessage.warning('请选择数据库实例及对应的schema')
|
||||
return
|
||||
}
|
||||
const dbId = inst.id;
|
||||
@@ -150,7 +169,6 @@ const addQueryTab = async (inst: any, db: string, sqlName: string = '') => {
|
||||
tab = new TabInfo();
|
||||
tab.key = label;
|
||||
tab.dbId = dbId;
|
||||
tab.dbType = inst.type;
|
||||
tab.db = db;
|
||||
tab.type = TabType.Query;
|
||||
tab.params = {
|
||||
@@ -161,7 +179,7 @@ const addQueryTab = async (inst: any, db: string, sqlName: string = '') => {
|
||||
registerSqlCompletionItemProvider();
|
||||
}
|
||||
|
||||
const remoteTab = (targetName: string) => {
|
||||
const onRemoveTab = (targetName: string) => {
|
||||
let activeName = state.activeName;
|
||||
const tabNames = [...state.tabs.keys()]
|
||||
for (let i = 0; i < tabNames.length; i++) {
|
||||
@@ -172,19 +190,22 @@ const remoteTab = (targetName: string) => {
|
||||
const nextTab = tabNames[i + 1] || tabNames[i - 1];
|
||||
if (nextTab) {
|
||||
activeName = nextTab;
|
||||
} else {
|
||||
activeName = '';
|
||||
}
|
||||
state.tabs.delete(targetName);
|
||||
state.activeName = activeName;
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 数据tab点击
|
||||
*/
|
||||
const onDataTabClick = (tab: any) => {
|
||||
state.activeName = tab.props.name;
|
||||
};
|
||||
const onTabChange = () => {
|
||||
if (!state.activeName) {
|
||||
state.nowDbInst = {} as DbInst;
|
||||
state.db = '';
|
||||
return;
|
||||
}
|
||||
state.nowDbInst = DbInst.getInst(state.tabs.get(state.activeName)?.dbId);
|
||||
}
|
||||
|
||||
const onGenerateInsertSql = async (sql: string) => {
|
||||
state.genSqlDialog.sql = sql;
|
||||
@@ -201,7 +222,7 @@ const reloadSqls = (dbId: number, db: string) => {
|
||||
|
||||
const deleteSqlScript = (ti: TabInfo) => {
|
||||
instanceTreeRef.value.reloadSqls({ id: ti.dbId }, ti.db);
|
||||
remoteTab(ti.key);
|
||||
onRemoveTab(ti.key);
|
||||
}
|
||||
|
||||
const registerSqlCompletionItemProvider = () => {
|
||||
@@ -214,8 +235,8 @@ const registerSqlCompletionItemProvider = () => {
|
||||
if (!nowTab) {
|
||||
return;
|
||||
}
|
||||
const { db, dbId, dbType } = nowTab;
|
||||
const dbInst = DbInst.getInst(dbId, dbType);
|
||||
const { db, dbId } = nowTab;
|
||||
const dbInst = DbInst.getInst(dbId);
|
||||
const { lineNumber, column } = position
|
||||
const { startColumn, endColumn } = word
|
||||
|
||||
@@ -267,7 +288,7 @@ const registerSqlCompletionItemProvider = () => {
|
||||
let str = lastToken.substring(0, lastToken.lastIndexOf('.'))
|
||||
// 库.表名联想
|
||||
|
||||
if (dbs.filter((a:any)=>a.name === str)?.length > 0) {
|
||||
if (dbs.filter((a: any) => a.name === str)?.length > 0) {
|
||||
let tables = await dbInst.loadTables(str)
|
||||
let suggestions: languages.CompletionItem[] = []
|
||||
for (let item of tables) {
|
||||
|
||||
@@ -306,7 +306,7 @@ const getNowDb = () => {
|
||||
}
|
||||
|
||||
const getNowDbInst = () => {
|
||||
return DbInst.getInst(state.dbId, state.dbType);
|
||||
return DbInst.getInst(state.dbId);
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
|
||||
@@ -207,7 +207,7 @@ const loadSchemaTables = async (inst: any, schema: string) => {
|
||||
state.loading[key] = true
|
||||
try {
|
||||
let { id } = inst
|
||||
let tables = await DbInst.getInst(id, inst.type).loadTables(schema);
|
||||
let tables = await DbInst.getInst(id).loadTables(schema);
|
||||
tables && tables.forEach((a: any) => a.show = true)
|
||||
state.tables[key] = tables;
|
||||
changeSchema(inst, schema);
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
style="font-size: 12px">取消</span></el-link>
|
||||
</span>
|
||||
</el-row>
|
||||
<db-table ref="dbTableRef" :db-id="state.ti.dbId" :db-type="state.ti.dbType" :db="state.ti.db"
|
||||
<db-table ref="dbTableRef" :db-id="state.ti.dbId" :db="state.ti.db"
|
||||
:data="execRes.data" :table="state.table" :column-names="execRes.tableColumn" :loading="loading"
|
||||
height="250" empty-text="tips: select *开头的单表查询或点击表名默认查询的数据,可双击数据在线修改"
|
||||
@selection-change="onDataSelectionChange" @change-updated-field="changeUpdatedField"></db-table>
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<db-table ref="dbTableRef" :db-id="state.ti.dbId" :db-type="state.ti.dbType" :db="state.ti.db" :data="datas"
|
||||
<db-table ref="dbTableRef" :db-id="state.ti.dbId" :db="state.ti.db" :data="datas"
|
||||
:table="state.table" :column-names="columnNames" :loading="loading" :height="tableHeight"
|
||||
:show-column-tip="true" :sortable="'custom'" @sort-change="(sort: any) => onTableSortChange(sort)"
|
||||
@selection-change="onDataSelectionChange" @change-updated-field="changeUpdatedField"></db-table>
|
||||
|
||||
@@ -5,11 +5,21 @@ import SqlExecBox from './component/SqlExecBox';
|
||||
const dbInstCache: Map<number, DbInst> = new Map();
|
||||
|
||||
export class DbInst {
|
||||
/**
|
||||
* 标签路径
|
||||
*/
|
||||
tagPath: string
|
||||
|
||||
/**
|
||||
* 实例id
|
||||
*/
|
||||
id: number
|
||||
|
||||
/**
|
||||
* 实例名
|
||||
*/
|
||||
name: string
|
||||
|
||||
/**
|
||||
* 数据库类型, mysql postgres
|
||||
*/
|
||||
@@ -183,26 +193,45 @@ export class DbInst {
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取或新建dbInst,如果缓存中不存在则新建,否则直接返回
|
||||
* @param inst 数据库实例,后端返回的列表接口中的信息
|
||||
* @returns DbInst
|
||||
*/
|
||||
static getOrNewInst(inst: any) {
|
||||
if (!inst) {
|
||||
throw new Error('inst不能为空')
|
||||
}
|
||||
let dbInst = dbInstCache.get(inst.id);
|
||||
if (dbInst) {
|
||||
return dbInst;
|
||||
}
|
||||
console.info(`new dbInst: ${inst.id}, tagPath: ${inst.tagPath}`);
|
||||
dbInst = new DbInst();
|
||||
dbInst.tagPath = inst.tagPath;
|
||||
dbInst.id = inst.id;
|
||||
dbInst.name = inst.name;
|
||||
dbInst.type = inst.type;
|
||||
|
||||
dbInstCache.set(dbInst.id, dbInst);
|
||||
return dbInst;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取数据库实例id,若不存在,则新建一个并缓存
|
||||
* @param dbId 数据库实例id
|
||||
* @param dbType 第一次获取时为必传项,即第一次创建时
|
||||
* @returns 数据库实例
|
||||
*/
|
||||
static getInst(dbId: number, dbType?: string): DbInst {
|
||||
static getInst(dbId?: number): DbInst {
|
||||
if (!dbId) {
|
||||
throw new Error('dbId不能为空');
|
||||
}
|
||||
let dbInst = dbInstCache.get(dbId);
|
||||
if (dbInst) {
|
||||
return dbInst;
|
||||
}
|
||||
if (!dbType) {
|
||||
throw new Error('DbInst不存在, dbType为必传项')
|
||||
}
|
||||
console.log(`new dbInst -> dbId: ${dbId}, dbType: ${dbType}`);
|
||||
dbInst = new DbInst();
|
||||
dbInst.id = dbId;
|
||||
dbInst.type = dbType;
|
||||
dbInstCache.set(dbInst.id, dbInst);
|
||||
return dbInst;
|
||||
throw new Error('dbInst不存在! 请在合适调用点使用DbInst.newInst()新建该实例');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -387,11 +416,6 @@ export class TabInfo {
|
||||
*/
|
||||
dbId: number
|
||||
|
||||
/**
|
||||
* 数据库类型
|
||||
*/
|
||||
dbType: string
|
||||
|
||||
/**
|
||||
* 库名
|
||||
*/
|
||||
@@ -408,10 +432,7 @@ export class TabInfo {
|
||||
params: any
|
||||
|
||||
getNowDbInst() {
|
||||
if (!this.dbType) {
|
||||
throw new Error('dbType不能为空')
|
||||
}
|
||||
return DbInst.getInst(this.dbId, this.dbType);
|
||||
return DbInst.getInst(this.dbId);
|
||||
}
|
||||
|
||||
getNowDb() {
|
||||
|
||||
@@ -12,14 +12,16 @@
|
||||
v-model="state.activeName">
|
||||
<el-tab-pane closable v-for="dt in state.dataTabs" :key="dt.key" :label="dt.label"
|
||||
:name="dt.key">
|
||||
<el-row class="mt5 mb5">
|
||||
<el-row>
|
||||
<el-col :span="2">
|
||||
<el-link @click="findCommand(state.activeName)" icon="refresh" :underline="false"
|
||||
class="">
|
||||
<div>
|
||||
<el-link @click="findCommand(state.activeName)" icon="refresh"
|
||||
:underline="false" class="">
|
||||
</el-link>
|
||||
<el-link @click="showInsertDocDialog" class="" type="primary" icon="plus"
|
||||
<el-link @click="showInsertDocDialog" class="ml5" type="primary" icon="plus"
|
||||
:underline="false">
|
||||
</el-link>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="22">
|
||||
<el-input ref="findParamInputRef" v-model="dt.findParamStr" placeholder="点击输入相应查询条件"
|
||||
|
||||
@@ -4,7 +4,7 @@ import "fmt"
|
||||
|
||||
const (
|
||||
AppName = "mayfly-go"
|
||||
Version = "v1.3.1"
|
||||
Version = "v1.4.0"
|
||||
)
|
||||
|
||||
func GetAppInfo() string {
|
||||
|
||||
Reference in New Issue
Block a user