mirror of
https://gitee.com/dromara/mayfly-go
synced 2025-11-02 15:30:25 +08:00
refactor: 新增达梦图标、调整前端DbDialect接口
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -26,6 +26,13 @@
|
||||
"unicode": "e8b7",
|
||||
"unicode_decimal": 59575
|
||||
},
|
||||
{
|
||||
"icon_id": "12295203",
|
||||
"name": "达梦数据库",
|
||||
"font_class": "db-dm",
|
||||
"unicode": "e6f0",
|
||||
"unicode_decimal": 59120
|
||||
},
|
||||
{
|
||||
"icon_id": "10055634",
|
||||
"name": "云数据库MongoDB",
|
||||
|
||||
@@ -8,10 +8,11 @@
|
||||
<el-input v-model.trim="form.name" placeholder="请输入数据库别名" auto-complete="off"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="type" label="类型" required>
|
||||
<el-select style="width: 100%" v-model="form.type" placeholder="请选择数据库类型">
|
||||
<el-option key="item.id" label="mysql" value="mysql"> </el-option>
|
||||
<el-option key="item.id" label="postgres" value="postgres"> </el-option>
|
||||
<el-option key="item.id" label="达梦(暂不支持ssh)" value="dm"> </el-option>
|
||||
<el-select @change="changeDbType" style="width: 100%" v-model="form.type" placeholder="请选择数据库类型">
|
||||
<el-option v-for="dt in dbTypes" :key="dt.type" :value="dt.type">
|
||||
<SvgIcon :name="getDbDialect(dt.type).getInfo().icon" :size="18" />
|
||||
{{ dt.label }}
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item prop="host" label="host" required>
|
||||
@@ -86,6 +87,8 @@ import { ElMessage } from 'element-plus';
|
||||
import { notBlank } from '@/common/assert';
|
||||
import { RsaEncrypt } from '@/common/rsa';
|
||||
import SshTunnelSelect from '../component/SshTunnelSelect.vue';
|
||||
import { getDbDialect } from './dialect';
|
||||
import SvgIcon from '@/components/svgIcon/index.vue';
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
@@ -121,7 +124,7 @@ const rules = {
|
||||
{
|
||||
required: true,
|
||||
message: '请输入主机ip和port',
|
||||
trigger: ['change', 'blur'],
|
||||
trigger: ['blur'],
|
||||
},
|
||||
],
|
||||
username: [
|
||||
@@ -135,6 +138,21 @@ const rules = {
|
||||
|
||||
const dbForm: any = ref(null);
|
||||
|
||||
const dbTypes = [
|
||||
{
|
||||
type: 'mysql',
|
||||
label: 'mysql',
|
||||
},
|
||||
{
|
||||
type: 'postgres',
|
||||
label: 'postgres',
|
||||
},
|
||||
{
|
||||
type: 'dm',
|
||||
label: '达梦(暂不支持ssh)',
|
||||
},
|
||||
];
|
||||
|
||||
const state = reactive({
|
||||
dialogVisible: false,
|
||||
tabActiveName: 'basic',
|
||||
@@ -143,7 +161,7 @@ const state = reactive({
|
||||
type: null,
|
||||
name: null,
|
||||
host: '',
|
||||
port: 3306,
|
||||
port: null,
|
||||
username: null,
|
||||
password: null,
|
||||
params: null,
|
||||
@@ -170,11 +188,17 @@ watch(props, (newValue: any) => {
|
||||
state.form = { ...newValue.data };
|
||||
state.oldUserName = state.form.username;
|
||||
} else {
|
||||
state.form = { port: 3306 } as any;
|
||||
state.form = { port: null } as any;
|
||||
state.oldUserName = null;
|
||||
}
|
||||
});
|
||||
|
||||
const changeDbType = (val: string) => {
|
||||
if (!state.form.id) {
|
||||
state.form.port = getDbDialect(val).getInfo().defaultPort as any;
|
||||
}
|
||||
};
|
||||
|
||||
const getDbPwd = async () => {
|
||||
state.pwd = await dbApi.getInstancePwd.request({ id: state.form.id });
|
||||
};
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<span v-if="data.type.value == SqlExecNodeType.DbInst">
|
||||
<el-popover :show-after="500" placement="right-start" title="数据库实例信息" trigger="hover" :width="250">
|
||||
<template #reference>
|
||||
<SvgIcon :name="getDbDialect(data.params.type).getIcon()" :size="18" />
|
||||
<SvgIcon :name="getDbDialect(data.params.type).getInfo().icon" :size="18" />
|
||||
</template>
|
||||
<template #default>
|
||||
<el-descriptions :column="1" size="small">
|
||||
@@ -66,7 +66,7 @@
|
||||
<el-descriptions-item label-align="right">
|
||||
<template #label>
|
||||
<div>
|
||||
<SvgIcon :name="getDbDialect(nowDbInst.type).getIcon()" :size="18" />
|
||||
<SvgIcon :name="getDbDialect(nowDbInst.type).getInfo().icon" :size="18" />
|
||||
实例
|
||||
</div>
|
||||
</template>
|
||||
@@ -104,7 +104,7 @@
|
||||
{{ dt.params.name }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="host">
|
||||
<SvgIcon :name="getDbDialect(dt.params.type).getIcon()" :size="18" />
|
||||
<SvgIcon :name="getDbDialect(dt.params.type).getInfo().icon" :size="18" />
|
||||
{{ dt.params.host }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="库名">
|
||||
|
||||
@@ -332,7 +332,7 @@ const selectData = async () => {
|
||||
const table = props.tableName;
|
||||
try {
|
||||
const countRes = await dbInst.runSql(db, dbInst.getDefaultCountSql(table, state.condition));
|
||||
state.count = countRes.res[0].count || countRes.res[0].COUNT;
|
||||
state.count = countRes.res[0].count || countRes.res[0].COUNT || 0;
|
||||
let sql = dbInst.getDefaultSelectSql(table, state.condition, state.orderBy, state.pageNum, state.pageSize);
|
||||
state.sql = sql;
|
||||
if (state.count > 0) {
|
||||
|
||||
@@ -167,7 +167,7 @@ const state = reactive({
|
||||
dialogVisible: false,
|
||||
btnloading: false,
|
||||
activeName: '1',
|
||||
columnTypeList: dbDialect.getColumnTypes(),
|
||||
columnTypeList: dbDialect.getInfo().columnTypes,
|
||||
indexTypeList: ['BTREE'], // mysql索引类型详解 http://c.biancheng.net/view/7897.html
|
||||
tableData: {
|
||||
fields: {
|
||||
@@ -425,7 +425,7 @@ const submit = async () => {
|
||||
sql: sql,
|
||||
dbId: props.dbId as any,
|
||||
db: props.db as any,
|
||||
dbType: dbDialect.getFormatDialect(),
|
||||
dbType: dbDialect.getInfo().formatSqlDialect,
|
||||
runSuccessCallback: () => {
|
||||
emit('submit-sql', { tableName: state.tableData.tableName });
|
||||
// cancel();
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { DbDialect, sqlColumnType } from './index';
|
||||
import { SqlLanguage } from 'sql-formatter/lib/src/sqlFormatter';
|
||||
import { DbDialect, sqlColumnType, DialectInfo } from './index';
|
||||
|
||||
export { DMDialect, GAUSS_TYPE_LIST };
|
||||
|
||||
@@ -83,13 +82,16 @@ const GAUSS_TYPE_LIST: sqlColumnType[] = [
|
||||
{ udtName: 'macaddr', dataType: 'macaddr', desc: 'MAC地址', space: '6字节' },
|
||||
];
|
||||
|
||||
class DMDialect implements DbDialect {
|
||||
getFormatDialect(): SqlLanguage {
|
||||
return 'postgresql';
|
||||
}
|
||||
const dmDialectInfo: DialectInfo = {
|
||||
icon: 'iconfont icon-db-dm',
|
||||
defaultPort: 5236,
|
||||
formatSqlDialect: 'postgresql',
|
||||
columnTypes: GAUSS_TYPE_LIST.sort((a, b) => a.udtName.localeCompare(b.udtName)),
|
||||
};
|
||||
|
||||
getIcon() {
|
||||
return 'iconfont icon-op-postgres';
|
||||
class DMDialect implements DbDialect {
|
||||
getInfo() {
|
||||
return dmDialectInfo;
|
||||
}
|
||||
|
||||
getDefaultSelectSql(table: string, condition: string, orderBy: string, pageNum: number, limit: number) {
|
||||
@@ -102,10 +104,6 @@ class DMDialect implements DbDialect {
|
||||
return name;
|
||||
};
|
||||
|
||||
getColumnTypes(): sqlColumnType[] {
|
||||
return GAUSS_TYPE_LIST.sort((a, b) => a.udtName.localeCompare(b.udtName));
|
||||
}
|
||||
|
||||
matchType(text: string, arr: string[]): boolean {
|
||||
if (!text || !arr || arr.length === 0) {
|
||||
return false;
|
||||
|
||||
@@ -11,6 +11,29 @@ export interface sqlColumnType {
|
||||
range?: string;
|
||||
}
|
||||
|
||||
// 数据库基础信息
|
||||
export interface DialectInfo {
|
||||
/**
|
||||
* 图标
|
||||
*/
|
||||
icon: string;
|
||||
|
||||
/**
|
||||
* 默认端口
|
||||
*/
|
||||
defaultPort: number;
|
||||
|
||||
/**
|
||||
* 格式化sql的方言
|
||||
*/
|
||||
formatSqlDialect: SqlLanguage;
|
||||
|
||||
/**
|
||||
* 列字段类型
|
||||
*/
|
||||
columnTypes: sqlColumnType[];
|
||||
}
|
||||
|
||||
export const DbType = {
|
||||
mysql: 'mysql',
|
||||
postgresql: 'postgres',
|
||||
@@ -19,14 +42,9 @@ export const DbType = {
|
||||
|
||||
export interface DbDialect {
|
||||
/**
|
||||
* 获取格式化sql对应的dialect名称
|
||||
* 获取一些数据库默认信息
|
||||
*/
|
||||
getFormatDialect(): SqlLanguage;
|
||||
|
||||
/**
|
||||
* 获取图标信息
|
||||
*/
|
||||
getIcon(): string;
|
||||
getInfo(): DialectInfo;
|
||||
|
||||
/**
|
||||
* 获取默认查询sql
|
||||
@@ -44,11 +62,6 @@ export interface DbDialect {
|
||||
*/
|
||||
wrapName(name: string): string;
|
||||
|
||||
/**
|
||||
* 生成字段类型列表
|
||||
* */
|
||||
getColumnTypes(): sqlColumnType[];
|
||||
|
||||
/**
|
||||
* 生成创建表sql
|
||||
* @param tableData 建表数据
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { DbDialect, sqlColumnType } from './index';
|
||||
import { SqlLanguage } from 'sql-formatter/lib/src/sqlFormatter';
|
||||
import { DbDialect, DialectInfo } from './index';
|
||||
|
||||
export { MYSQL_TYPE_LIST, MysqlDialect, language };
|
||||
|
||||
@@ -30,13 +29,16 @@ const MYSQL_TYPE_LIST = [
|
||||
'varchar',
|
||||
];
|
||||
|
||||
class MysqlDialect implements DbDialect {
|
||||
getFormatDialect(): SqlLanguage {
|
||||
return 'mysql';
|
||||
}
|
||||
const mysqlDialectInfo: DialectInfo = {
|
||||
icon: 'iconfont icon-op-mysql',
|
||||
defaultPort: 3306,
|
||||
formatSqlDialect: 'mysql',
|
||||
columnTypes: MYSQL_TYPE_LIST.map((a) => ({ udtName: a, dataType: a, desc: '', space: '' })),
|
||||
};
|
||||
|
||||
getIcon() {
|
||||
return 'iconfont icon-op-mysql';
|
||||
class MysqlDialect implements DbDialect {
|
||||
getInfo(): DialectInfo {
|
||||
return mysqlDialectInfo;
|
||||
}
|
||||
|
||||
getDefaultSelectSql(table: string, condition: string, orderBy: string, pageNum: number, limit: number) {
|
||||
@@ -49,10 +51,6 @@ class MysqlDialect implements DbDialect {
|
||||
return `\`${name}\``;
|
||||
};
|
||||
|
||||
getColumnTypes(): sqlColumnType[] {
|
||||
return MYSQL_TYPE_LIST.map((a) => ({ udtName: a, dataType: a, desc: '', space: '' }));
|
||||
}
|
||||
|
||||
genColumnBasicSql(cl: any): string {
|
||||
let val = cl.value ? (cl.value === 'CURRENT_TIMESTAMP' ? cl.value : `'${cl.value}'`) : '';
|
||||
let defVal = val ? `DEFAULT ${val}` : '';
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { DbDialect, sqlColumnType } from './index';
|
||||
import { SqlLanguage } from 'sql-formatter/lib/src/sqlFormatter';
|
||||
import { DbDialect, DialectInfo, sqlColumnType } from './index';
|
||||
|
||||
export { PostgresqlDialect, GAUSS_TYPE_LIST };
|
||||
|
||||
@@ -83,13 +82,16 @@ const GAUSS_TYPE_LIST: sqlColumnType[] = [
|
||||
{ udtName: 'macaddr', dataType: 'macaddr', desc: 'MAC地址', space: '6字节' },
|
||||
];
|
||||
|
||||
class PostgresqlDialect implements DbDialect {
|
||||
getFormatDialect(): SqlLanguage {
|
||||
return 'postgresql';
|
||||
}
|
||||
const postgresDialectInfo: DialectInfo = {
|
||||
icon: 'iconfont icon-op-postgres',
|
||||
defaultPort: 5432,
|
||||
formatSqlDialect: 'postgresql',
|
||||
columnTypes: GAUSS_TYPE_LIST.sort((a, b) => a.udtName.localeCompare(b.udtName)),
|
||||
};
|
||||
|
||||
getIcon() {
|
||||
return 'iconfont icon-op-postgres';
|
||||
class PostgresqlDialect implements DbDialect {
|
||||
getInfo(): DialectInfo {
|
||||
return postgresDialectInfo;
|
||||
}
|
||||
|
||||
getDefaultSelectSql(table: string, condition: string, orderBy: string, pageNum: number, limit: number) {
|
||||
@@ -102,10 +104,6 @@ class PostgresqlDialect implements DbDialect {
|
||||
return name;
|
||||
};
|
||||
|
||||
getColumnTypes(): sqlColumnType[] {
|
||||
return GAUSS_TYPE_LIST.sort((a, b) => a.udtName.localeCompare(b.udtName));
|
||||
}
|
||||
|
||||
matchType(text: string, arr: string[]): boolean {
|
||||
if (!text || !arr || arr.length === 0) {
|
||||
return false;
|
||||
|
||||
@@ -34,8 +34,6 @@ require (
|
||||
gorm.io/gorm v1.25.5
|
||||
)
|
||||
|
||||
require golang.org/x/exp v0.0.0-20230519143937-03e91628a987
|
||||
|
||||
require (
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
|
||||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
|
||||
@@ -79,6 +77,7 @@ require (
|
||||
github.com/xdg-go/stringprep v1.0.4 // indirect
|
||||
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
|
||||
golang.org/x/arch v0.3.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20230519143937-03e91628a987
|
||||
golang.org/x/image v0.0.0-20220302094943-723b81ca9867 // indirect
|
||||
golang.org/x/net v0.18.0 // indirect
|
||||
golang.org/x/sync v0.1.0 // indirect
|
||||
|
||||
@@ -115,7 +115,7 @@ func (d *Db) ExecSql(rc *req.Ctx) {
|
||||
ctx := rc.MetaCtx
|
||||
// 如果存在执行id,则保存取消函数,用于后续可能的取消操作
|
||||
if form.ExecId != "" {
|
||||
cancelCtx, cancel := context.WithCancel(rc.MetaCtx)
|
||||
cancelCtx, cancel := context.WithTimeout(rc.MetaCtx, 55*time.Second)
|
||||
ctx = cancelCtx
|
||||
cancelExecSqlMap.Store(form.ExecId, cancel)
|
||||
defer cancelExecSqlMap.Delete(form.ExecId)
|
||||
|
||||
@@ -33,10 +33,7 @@ func (d *DbConn) QueryContext(ctx context.Context, querySql string) ([]string, [
|
||||
result = append(result, record)
|
||||
})
|
||||
if err != nil {
|
||||
if err == context.Canceled {
|
||||
return nil, nil, errorx.NewBiz("取消执行")
|
||||
}
|
||||
return nil, nil, err
|
||||
return nil, nil, wrapSqlError(err)
|
||||
}
|
||||
return columns, result, nil
|
||||
}
|
||||
@@ -74,10 +71,7 @@ func (d *DbConn) Exec(sql string) (int64, error) {
|
||||
func (d *DbConn) ExecContext(ctx context.Context, sql string) (int64, error) {
|
||||
res, err := d.db.ExecContext(ctx, sql)
|
||||
if err != nil {
|
||||
if err == context.Canceled {
|
||||
return 0, errorx.NewBiz("取消执行")
|
||||
}
|
||||
return 0, err
|
||||
return 0, wrapSqlError(err)
|
||||
}
|
||||
return res.RowsAffected()
|
||||
}
|
||||
@@ -202,3 +196,14 @@ func valueConvert(data []byte, colType *sql.ColumnType) any {
|
||||
|
||||
return stringV
|
||||
}
|
||||
|
||||
// 包装sql执行相关错误
|
||||
func wrapSqlError(err error) error {
|
||||
if err == context.Canceled {
|
||||
return errorx.NewBiz("取消执行")
|
||||
}
|
||||
if err == context.DeadlineExceeded {
|
||||
return errorx.NewBiz("执行超时")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -4,10 +4,11 @@ import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
_ "gitee.com/chunanyong/dm"
|
||||
"mayfly-go/pkg/errorx"
|
||||
"mayfly-go/pkg/utils/anyx"
|
||||
"strings"
|
||||
|
||||
_ "gitee.com/chunanyong/dm"
|
||||
)
|
||||
|
||||
func getDmDB(d *DbInfo) (*sql.DB, error) {
|
||||
|
||||
Reference in New Issue
Block a user