This commit is contained in:
shanhexi
2023-10-15 18:10:59 +08:00
16 changed files with 229 additions and 61 deletions

View File

@ -2,6 +2,7 @@
display: flex;
align-items: center;
padding: 2px 20px;
height: 42px;
box-sizing: border-box;
border-bottom: 1px solid var(--color-border-secondary);
}

View File

@ -152,6 +152,17 @@ function MonacoEditor(props: IProps, ref: ForwardedRef<IExportRefFunction>) {
}
}, [editorRef.current, isActive]);
useEffect(() => {
// 监听浏览器窗口大小变化,重新渲染编辑器
const resize = () => {
editorRef.current?.layout();
};
window.addEventListener('resize', resize);
return () => {
window.removeEventListener('resize', resize);
};
}, []);
// 监听主题色变化切换编辑器主题色
useEffect(() => {
if (options?.theme) {

View File

@ -8,10 +8,9 @@
}
.ant-spin-container {
height: calc(100% - 48px);
height: calc(100% - 40px);
}
}
}
.consoleEditor {
@ -19,14 +18,17 @@
}
.consoleEditorWithChat {
height: calc(100% - 56px);
height: calc(100% - 42px);
}
.consoleOptionsWrapper {
position: absolute;
bottom: 8px;
bottom: 0px;
left: 0;
right: 0;
height: 40px;
display: flex;
align-items: center;
display: flex;
margin: 0 12px;

View File

@ -4,9 +4,26 @@
url('../../assets/font/iconfont.ttf') format('truetype');
}
.iconBox {
height: var(--icon-box-size);
width: var(--icon-box-size);
display: flex;
align-items: center;
justify-content: center;
border-radius: 4px;
cursor: pointer;
&:hover {
background-color: var(--color-hover-bg);
.iconfont {
size: var(--icon-size);
color: var(--color-primary);
}
}
}
.iconfont {
font-family: 'iconfont' !important;
font-size: 14px;
font-size: var(--icon-size);
font-style: normal;
user-select: none;
-webkit-font-smoothing: antialiased;

View File

@ -20,16 +20,43 @@ if (__ENV__ === 'local') {
style.appendChild(document.createTextNode(container));
}
export default class Iconfont extends PureComponent<
{
interface IProps {
code: string;
} & React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
> {
render() {
return (
<i {...this.props} className={classnames(this.props.className, styles.iconfont)}>
{this.props.code}
box?: boolean;
boxSize?: number;
size?: number;
className?: string;
classNameBox?: string;
}
const Iconfont = (props: IProps) => {
const { box, boxSize = 32, size = 14, className, classNameBox, ...args } = props;
return box ? (
<div
{...args}
style={
{
'--icon-box-size': `${boxSize}px`,
'--icon-size': `${size}px`,
} as any
}
className={classnames(classNameBox, styles.iconBox)}
>
<i className={classnames(className, styles.iconfont)}>{props.code}</i>
</div>
) : (
<i
{...args}
style={
{
'--icon-size': `${size}px`,
} as any
}
className={classnames(className, styles.iconfont)}
>
{props.code}
</i>
);
}
}
};
export default Iconfont;

View File

@ -2,19 +2,15 @@ import React, { memo, useEffect } from 'react';
import styles from './index.less';
import classnames from 'classnames';
import { Table } from 'antd';
import historyService, { IGetHistoryListParams } from '@/service/history';
import { set } from 'lodash';
export interface IGetOutputParams extends IGetHistoryListParams {}
import historyService, { IHistoryRecord } from '@/service/history';
interface IProps {
className?: string;
params: IGetOutputParams;
}
export default memo<IProps>((props) => {
const { className, params } = props;
const [dataSource, setDataSource] = React.useState<any[]>([]);
const { className } = props;
const [dataSource, setDataSource] = React.useState<IHistoryRecord[]>([]);
const columns = [
{
@ -36,21 +32,32 @@ export default memo<IProps>((props) => {
title: '数据库/schema',
dataIndex: 'databaseName',
key: 'databaseName',
render: (value: string, record: IHistoryRecord) => {
return <span>{`${record.dataSourceName}/${record.databaseName}`}</span>;
},
},
{
title: 'ddl',
dataIndex: 'ddl',
key: 'ddl',
},
{
title: '状态',
dataIndex: 'state',
key: 'state',
dataIndex: 'status',
key: 'status',
render: (value: boolean) => {
return <span style={{ color: value ? 'green' : 'red' }}>{value ? '成功' : '失败'}</span>;
},
},
{
title: 'sql',
dataIndex: 'name',
key: 'name',
title: '影响行数',
dataIndex: 'operationRows',
key: 'operationRows',
},
{
title: '执行耗时',
dataIndex: 'executionTime',
key: 'executionTime',
dataIndex: 'useTime',
key: 'useTime',
},
];
@ -59,7 +66,12 @@ export default memo<IProps>((props) => {
}, []);
const getHistoryList = () => {
historyService.getHistoryList(params).then((res) => {
historyService
.getHistoryList({
pageNo: 1,
pageSize: 100,
})
.then((res) => {
setDataSource(res.data);
});
};

View File

@ -26,6 +26,7 @@
display: flex;
overflow: auto;
height: 32px;
flex-shrink: 0;
background-color: var(--color-bg-base);
border-bottom: 1px solid var(--color-border);
&::-webkit-scrollbar {

View File

@ -22,10 +22,10 @@ export const editorDefaultOptions: IEditorOptions = {
scrollbar: { // 滚动条
alwaysConsumeMouseWheel: false, // 总是消耗鼠标滚轮
},
padding: {
top: 2,
bottom: 2,
},
// padding: {
// top: 2,
// bottom: 2,
// },
minimap: { // 缩略图
enabled: false, // 启用
},

View File

@ -115,7 +115,7 @@
display: flex;
align-items: center;
i {
margin-right: 4px;
margin-right: 6px;
}
}

View File

@ -99,7 +99,7 @@ const TableList = dvaModel((props: any) => {
const reader = new FileReader();
reader.onload = function (event) {
const sqlContent = event.target?.result ?? '';
const sqlContent = (event.target?.result ?? '') as string;
addConsole(sqlContent);
};

View File

@ -14,17 +14,30 @@
}
}
.workspaceRightMain {
display: flex;
}
.rightBar {
flex-shrink: 0;
width: 38px;
border-left: 1px solid var(--color-border);
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
padding: 10px 0px;
}
.tabs {
height: 100%;
width: 100%;
}
.tabBox {
position: absolute;
top: 0;
right: 0;
left: 0;
bottom: 0;
flex: 1;
width: 100%;
height: 100%;
}
.activeConsoleBox {

View File

@ -337,6 +337,7 @@ const WorkspaceRight = memo<IProps>((props: IProps) => {
registerIntelliSenseTable(data, databaseType, dataSourceId, databaseName, schemaName);
registerIntelliSenseField(tableList.current, dataSourceId, databaseName, schemaName);
});
console.log('getAllTable Before:', window._BaseURL);
}
}, [curWorkspaceParams.databaseType, curWorkspaceParams.databaseName, curWorkspaceParams.schemaName]);
@ -575,7 +576,7 @@ const WorkspaceRight = memo<IProps>((props: IProps) => {
return (
<div className={classnames(styles.workspaceRight, className)}>
<LoadingContent data={workspaceTabList} handleEmpty empty={renderEmpty()}>
<LoadingContent className={styles.workspaceRightMain} data={workspaceTabList} handleEmpty empty={renderEmpty()}>
<div className={styles.tabBox}>
<TabsNew
className={styles.tabs}
@ -587,6 +588,14 @@ const WorkspaceRight = memo<IProps>((props: IProps) => {
// lastTabCannotClosed
/>
</div>
<div className={styles.rightBar}>
<div className={styles.rightBarFront}>
<Iconfont code="&#xe8ad;" box size={16} />
</div>
<div className={styles.rightBarAfter}>
<Iconfont code="&#xe8ad;" box size={20} />
</div>
</div>
</LoadingContent>
</div>
);

View File

@ -1,6 +1,6 @@
import { extend, ResponseError, type RequestOptionsInit } from 'umi-request';
import { message } from 'antd';
import { navigate } from '@/utils'
import { navigate } from '@/utils';
export type IErrorLevel = 'toast' | 'prompt' | 'critical' | false;
export interface IOptions {
@ -127,11 +127,22 @@ request.interceptors.response.use(async (response) => {
export default function createRequest<P = void, R = {}>(url: string, options?: IOptions) {
// 路由跳转
const { method = 'get', mock = false, errorLevel = 'toast', delayTime, outside, isFullPath, dynamicUrl } = options || {};
const {
method = 'get',
mock = false,
errorLevel = 'toast',
delayTime,
outside,
isFullPath,
dynamicUrl,
} = options || {};
return function (params: P, restParams?: RequestOptionsInit) {
// 是否需要mock
const _baseURL = (mock ? mockUrl : baseURL) || '';
return function (params: P, restParams?: RequestOptionsInit) {
// if (url === '/api/rdb/ddl/list') {
// debugger;
// }
// 在url上按照定义规则拼接params
const paramsInUrl: string[] = [];
@ -171,7 +182,7 @@ export default function createRequest<P = void, R = {}>(url: string, options?: I
eventualUrl = isFullPath ? url : eventualUrl;
// 动态的url
if(dynamicUrl){
if (dynamicUrl) {
eventualUrl = params as string;
}

View File

@ -25,6 +25,61 @@ export interface IUpdateConsoleParams {
id: number;
}
export interface IHistoryRecord {
/**
* 是否可连接
*/
connectable?: boolean | null;
/**
* DB名称
*/
databaseName?: null | string;
/**
* 数据源id
*/
dataSourceId?: number | null;
/**
* 数据源名称
*/
dataSourceName?: null | string;
/**
* ddl内容
*/
ddl?: null | string;
/**
* 扩展信息
*/
extendInfo?: null | string;
/**
* 主键
*/
id?: number | null;
/**
* 文件别名
*/
name?: null | string;
/**
* 操作行数
*/
operationRows?: number | null;
/**
* schema名称
*/
schemaName?: null | string;
/**
* 状态
*/
status?: null | string;
/**
* ddl语言类型
*/
type?: null | string;
/**
* 使用时长
*/
useTime?: number | null;
}
const saveConsole = createRequest<ICreateConsole, number>('/api/operation/saved/create', { method: 'post' });
// orderByDesc true 降序

View File

@ -111,10 +111,19 @@ const updateTableExample = createRequest<{ dbType: DatabaseTypeCode }, string>('
const exportCreateTableSql = createRequest<ITableParams, string>('/api/rdb/ddl/export', { method: 'get' });
const executeTable = createRequest<IExecuteTableParams, string>('/api/rdb/ddl/execute', { method: 'post' });
const getColumnList = createRequest<ITableParams, IColumn[]>('/api/rdb/ddl/column_list', { method: 'get', delayTime: 200 });
const getIndexList = createRequest<ITableParams, IColumn[]>('/api/rdb/ddl/index_list', { method: 'get', delayTime: 200 });
const getColumnList = createRequest<ITableParams, IColumn[]>('/api/rdb/ddl/column_list', {
method: 'get',
delayTime: 200,
});
const getIndexList = createRequest<ITableParams, IColumn[]>('/api/rdb/ddl/index_list', {
method: 'get',
delayTime: 200,
});
const getKeyList = createRequest<ITableParams, IColumn[]>('/api/rdb/ddl/key_list', { method: 'get', delayTime: 200 });
const getSchemaList = createRequest<ISchemaParams, ISchemaResponse[]>('/api/rdb/ddl/schema_list', { method: 'get', delayTime: 200 });
const getSchemaList = createRequest<ISchemaParams, ISchemaResponse[]>('/api/rdb/ddl/schema_list', {
method: 'get',
delayTime: 200,
});
const getDatabaseSchemaList = createRequest<{ dataSourceId: number }, MetaSchemaVO>(
'/api/rdb/ddl/database_schema_list',
@ -239,7 +248,7 @@ const getTableDetails = createRequest<
/** 获取库的所有表 */
const getAllTableList = createRequest<
{ dataSourceId: number; databaseName: string; schemaName?: string | null },
{ dataSourceId: number; databaseName?: string | null; schemaName?: string | null },
Array<{ name: string; comment: string }>
>('/api/rdb/table/table_list', { method: 'get' });

View File

@ -45,7 +45,7 @@ const registerIntelliSenseTable = (
tableList: Array<{ name: string; comment: string }>,
databaseCode?: DatabaseTypeCode,
dataSourceId?: number,
databaseName?: string,
databaseName?: string | null,
schemaName?: string | null,
) => {
monaco.editor.registerCommand('addFieldList', (_: any, ...args: any[]) => {
@ -55,7 +55,7 @@ const registerIntelliSenseTable = (
intelliSenseTable.dispose();
intelliSenseTable = monaco.languages.registerCompletionItemProvider('sql', {
triggerCharacters: [' ', ],
triggerCharacters: [' '],
provideCompletionItems: (model, position) => {
const lineContentUntilPosition = model.getValueInRange({
startLineNumber: position.lineNumber,