Resolve conflicts.

This commit is contained in:
fanjin.fjy
2023-06-26 21:21:35 +08:00
parent 13250567b1
commit 549aeb8c13
17 changed files with 213 additions and 153 deletions

View File

@ -1,15 +1,17 @@
{ {
"cSpell.words": [ "cSpell.words": [
"Dserver",
"Dspring",
"Sercurity",
"ahooks", "ahooks",
"antd", "antd",
"asar", "asar",
"cascader", "cascader",
"Dserver",
"Dspring",
"echarts", "echarts",
"favicons",
"iconfont",
"nsis", "nsis",
"pgsql", "pgsql",
"Sercurity",
"sortablejs", "sortablejs",
"wireframe" "wireframe"
] ]

View File

@ -9,13 +9,6 @@ const chainWebpack = (config: any, { webpack }: any) => {
languages: ['mysql', 'pgsql', 'sql'], languages: ['mysql', 'pgsql', 'sql'],
}, },
]); ]);
config.plugin('define').use(require('webpack').DefinePlugin, [
{
__BUILD_TIME__: JSON.stringify(formatDate(new Date(), 'yyyyMMddhhmmss')),
__APP_VERSION__: JSON.stringify(process.env.APP_VERSION || '0.0.0'),
},
]);
}; };
export default defineConfig({ export default defineConfig({
@ -24,5 +17,5 @@ export default defineConfig({
headScripts: ['if (window.myAPI) { window.myAPI.startServerForSpawn() }'], headScripts: ['if (window.myAPI) { window.myAPI.startServerForSpawn() }'],
define: { define: {
'process.env.UMI_ENV': process.env.UMI_ENV, 'process.env.UMI_ENV': process.env.UMI_ENV,
} },
}); });

View File

@ -9,13 +9,6 @@ const chainWebpack = (config: any, { webpack }: any) => {
languages: ['mysql', 'pgsql', 'sql'], languages: ['mysql', 'pgsql', 'sql'],
}, },
]); ]);
config.plugin('define').use(require('webpack').DefinePlugin, [
{
__BUILD_TIME__: JSON.stringify(formatDate(new Date(), 'yyyyMMddhhmmss')),
__APP_VERSION__: JSON.stringify(process.env.APP_VERSION || '0.0.0'),
},
]);
}; };
export default defineConfig({ export default defineConfig({
@ -23,5 +16,5 @@ export default defineConfig({
chainWebpack, chainWebpack,
define: { define: {
'process.env.UMI_ENV': process.env.UMI_ENV, 'process.env.UMI_ENV': process.env.UMI_ENV,
} },
}); });

View File

@ -1,7 +1,7 @@
import { formatDate } from './src/utils/date'; import { formatDate } from './src/utils/date';
import { defineConfig } from 'umi'; import { defineConfig } from 'umi';
const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin'); const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin');
console.log(process.env.UMI_ENV) console.log(process.env.UMI_ENV);
const chainWebpack = (config: any, { webpack }: any) => { const chainWebpack = (config: any, { webpack }: any) => {
config.plugin('monaco-editor').use(MonacoWebpackPlugin, [ config.plugin('monaco-editor').use(MonacoWebpackPlugin, [
@ -37,11 +37,11 @@ export default defineConfig({
changeOrigin: true, changeOrigin: true,
}, },
}, },
headScripts: ['if (window.myAPI) { window.myAPI.startServerForSpawn() }'],
favicons: ['logo.ico'],
define: { define: {
__ENV: process.env.UMI_ENV , __ENV: process.env.UMI_ENV,
__BUILD_TIME__: formatDate(new Date(), 'yyyyMMddhhmmss'), __BUILD_TIME__: formatDate(new Date(), 'yyyyMMddhhmmss'),
__APP_VERSION__: process.env.APP_VERSION || '0.0.0', __APP_VERSION__: process.env.APP_VERSION || '0.0.0',
}, },
headScripts: ['if (window.myAPI) { window.myAPI.startServerForSpawn() }'],
favicons: ['logo.ico'],
}); });

View File

@ -14,4 +14,4 @@
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
-webkit-text-stroke-width: 0.2px; -webkit-text-stroke-width: 0.2px;
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
} }

View File

@ -6,7 +6,6 @@ import styles from './index.less';
// 只有本地开发时使用cdn发布线上时要下载iconfont到 /assets/font // 只有本地开发时使用cdn发布线上时要下载iconfont到 /assets/font
if (__ENV === 'local') { if (__ENV === 'local') {
let container = ` let container = `
/* 在线链接服务仅供平台体验和调试使用,平台不承诺服务的稳定性,企业客户需下载字体包自行发布使用并做好备份。 */
@font-face { @font-face {
font-family: 'iconfont'; /* Project id 3633546 */ font-family: 'iconfont'; /* Project id 3633546 */
src: url('//at.alicdn.com/t/a/font_3633546_p80guyu8w2s.woff2?t=1687748230475') format('woff2'), src: url('//at.alicdn.com/t/a/font_3633546_p80guyu8w2s.woff2?t=1687748230475') format('woff2'),
@ -20,11 +19,16 @@ if (__ENV === 'local') {
style.appendChild(document.createTextNode(container)); style.appendChild(document.createTextNode(container));
} }
export default class Iconfont extends PureComponent<
export default class Iconfont extends PureComponent<{ {
code: string; code: string;
} & React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>> { } & React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
> {
render() { render() {
return <i {...this.props} className={classnames(this.props.className, styles.iconfont)}>{this.props.code}</i> return (
<i {...this.props} className={classnames(this.props.className, styles.iconfont)}>
{this.props.code}
</i>
);
} }
} }

View File

@ -17,5 +17,4 @@ export default {
'connection.message.testSshConnection': 'Test the ssh connection', 'connection.message.testSshConnection': 'Test the ssh connection',
'connection.tableHeader.name': 'Name', 'connection.tableHeader.name': 'Name',
'connection.tableHeader.value': 'Value', 'connection.tableHeader.value': 'Value',
'connection.menu.enterToWorkSpace': 'Go to DataSource',
}; };

View File

@ -17,5 +17,4 @@ export default {
'connection.message.testSshConnection': '测试ssh连接', 'connection.message.testSshConnection': '测试ssh连接',
'connection.tableHeader.name': '名称', 'connection.tableHeader.name': '名称',
'connection.tableHeader.value': '值', 'connection.tableHeader.value': '值',
'connection.menu.enterToWorkSpace': '前往数据源',
} }

View File

@ -9,15 +9,10 @@ import antdEnUS from 'antd/locale/en_US';
import antdZhCN from 'antd/locale/zh_CN'; import antdZhCN from 'antd/locale/zh_CN';
import { useTheme } from '@/hooks'; import { useTheme } from '@/hooks';
import { isEn } from '@/utils/check'; import { isEn } from '@/utils/check';
import { ThemeType, PrimaryColorType, LangType } from '@/constants'; import { ThemeType, PrimaryColorType, LangType } from '@/constants/';
import { InjectThemeVar } from '@/theme' import { InjectThemeVar } from '@/theme';
import styles from './index.less'; import styles from './index.less';
import { import { getLang, getPrimaryColor, getTheme, setLang } from '@/utils/localStorage';
getLang,
getPrimaryColor,
getTheme,
setLang,
} from '@/utils/localStorage';
declare global { declare global {
interface Window { interface Window {
@ -59,7 +54,6 @@ export default function Layout() {
); );
} }
function AppContainer() { function AppContainer() {
const { token } = useToken(); const { token } = useToken();
const [initEnd, setInitEnd] = useState(false); const [initEnd, setInitEnd] = useState(false);
@ -67,7 +61,7 @@ function AppContainer() {
useEffect(() => { useEffect(() => {
InjectThemeVar(token as any, appTheme.backgroundColor, appTheme.primaryColor); InjectThemeVar(token as any, appTheme.backgroundColor, appTheme.primaryColor);
}, [token]) }, [token]);
useLayoutEffect(() => { useLayoutEffect(() => {
collectInitApp(); collectInitApp();
@ -102,8 +96,7 @@ function AppContainer() {
let theme = getTheme(); let theme = getTheme();
if (theme === ThemeType.FollowOs) { if (theme === ThemeType.FollowOs) {
theme = theme =
(window.matchMedia && (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches
window.matchMedia('(prefers-color-scheme: dark)').matches
? ThemeType.Dark ? ThemeType.Dark
: ThemeType.Light) || ThemeType.Dark; : ThemeType.Light) || ThemeType.Dark;
} }
@ -119,14 +112,13 @@ function AppContainer() {
} }
} }
return <div className={styles.appContainer}> return (
{ <div className={styles.appContainer}>
initEnd && {initEnd && (
<div className={styles.app}> <div className={styles.app}>
<Outlet /> <Outlet />
</div> </div>
} )}
</div> </div>
);
} }

View File

@ -1,36 +1,63 @@
import { IConnectionDetails } from "@/typings" import { IConnectionDetails } from '@/typings/connection';
import { Effect, Reducer } from 'umi';
import connectionService from '@/service/connection';
import { IPageResponse } from '@/typings/common';
export interface ConnectionState { /**
curConnection: IConnectionDetails * 数据源相关 - 链接池、数据库、schema、表
connectionList: IConnectionDetails[] */
export interface ConnectionModelState {
curConnection?: IConnectionDetails;
connectionList: IConnectionDetails[];
} }
export interface ConnectionModelType {
namespace: 'connection';
state: ConnectionModelState;
reducers: {
// 设置连接池列表
setConnectionList: Reducer<ConnectionModelState>;
setCurConnection: Reducer<ConnectionModelState>;
};
effects: {
// setConnectionList: Effect;
};
}
export default { // const ConnectionModel:ConnectionModelType = {
namespace: 'connection', const ConnectionModel = {
state: { namespace: 'connection',
curConnection: null, state: {
connectionList: [], curConnection: undefined,
connectionList: [],
},
reducers: {
// 设置连接池列表
setConnectionList(state: ConnectionModelState, { payload }: { payload: ConnectionModelState['connectionList'] }) {
return {
...state,
connectionList: payload,
};
}, },
reducers: { // 设置当前选着的Connection
// 获取连接池列表 setCurConnection(state: ConnectionModelState, { payload }: { payload: ConnectionModelState['curConnection'] }) {
setConnectionList(state: ConnectionState, { payload }: { payload: ConnectionState['connectionList'] }) { return { ...state, curConnection: payload };
return { },
...state,
connectionList: payload
}
},
// 设置当前选着的Connection },
setCurConnection(
state: ConnectionState,
{ payload }: { payload: ConnectionState['curConnection'] },
) {
return { ...state, curConnection: payload }
},
effects: {
*fetchConnectionList(_, { call, put }) {
const res = (yield connectionService.getList({ pageNo: 1, pageSize: 999 })) as IPageResponse<IConnectionDetails>;
console.log('fetchConnectionList==>', res.data);
yield put({
type: 'setConnectionList',
payload: res.data,
});
},
},
};
} export default ConnectionModel;
}

View File

@ -0,0 +1,43 @@
import sqlService from '@/service/sql';
interface ISchema {
databaseName: string;
name: string;
}
interface IDatabase {
name: string;
schema: ISchema[];
}
const DatabaseModel = {
namespace: 'database',
state: {
databaseAndSchemaList: [],
},
reducers: {
// 设置 database schema 数据
setDatabaseAndSchemaList(state, { payload }) {
return {
...state,
databaseAndSchemaList: payload,
};
},
},
effects: {
*fetchDatabaseAndSchemaList(p, { call, put }) {
console.log('fetchDatabaseAndSchemaList start', p);
const res = (yield sqlService.getDatabaseSchemaList({ dataSourceId: 2 })) as {
data: { database: IDatabase[]; schema: ISchema[] };
};
console.log('fetchDatabaseAndSchemaList end', res);
yield put({
type: 'setDatabaseAndSchemaList',
payload: res,
});
},
},
};
export default DatabaseModel;

View File

@ -12,7 +12,7 @@ import { Button, Dropdown, Modal } from 'antd';
import { MoreOutlined } from '@ant-design/icons'; import { MoreOutlined } from '@ant-design/icons';
import styles from './index.less'; import styles from './index.less';
import { connect, history } from 'umi'; import { connect, history } from 'umi';
import { ConnectionState } from '@/models/connection'; import { ConnectionModelType } from '@/models/connection';
interface IMenu { interface IMenu {
key: number; key: number;
@ -20,15 +20,22 @@ interface IMenu {
icon: React.ReactNode; icon: React.ReactNode;
meta: IConnectionDetails; meta: IConnectionDetails;
} }
interface IProps {
connectionList: IConnectionDetails[];
curConnection: IConnectionDetails;
dispatch: (p: { type: string, payload: any }) => void
interface IProps {
connectionModel: {
connectionList: IConnectionDetails[];
curConnection: IConnectionDetails;
};
databaseModel: {
databaseAndSchemaList: any;
};
dispatch: (p: { type: `connection/${string}` | `database/${string}`; payload?: any }) => void;
} }
function Connections(props: IProps) { function Connections(props: IProps) {
const { connectionList } = props; console.log('props', props);
const { connectionModel, databaseModel, dispatch } = props;
const { connectionList } = connectionModel;
const volatileRef = useRef<any>(); const volatileRef = useRef<any>();
// const [connectionList, setConnectionList] = useState<IConnectionDetails[]>(); // const [connectionList, setConnectionList] = useState<IConnectionDetails[]>();
const [curConnection, setCurConnection] = useState<Partial<IConnectionDetails>>({}); const [curConnection, setCurConnection] = useState<Partial<IConnectionDetails>>({});
@ -38,18 +45,10 @@ function Connections(props: IProps) {
}, []); }, []);
const getConnectionList = async () => { const getConnectionList = async () => {
let p = { dispatch({
pageNo: 1, type: 'connection/fetchConnectionList',
pageSize: 999, });
}; };
let res = await connectionService.getList(p)
props.dispatch({
type: 'connection/setConnectionList',
payload: res.data,
})
}
function handleCreateConnections(database: IDatabase) { function handleCreateConnections(database: IDatabase) {
setCurConnection({ setCurConnection({
@ -83,9 +82,7 @@ function Connections(props: IProps) {
setCurConnection(menu.meta); setCurConnection(menu.meta);
}} }}
> >
<div <div className={classnames(styles.menuItemsTitle)}>
className={classnames(styles.menuItemsTitle)}
>
{icon} {icon}
<span style={{ marginLeft: '8px' }}>{label}</span> <span style={{ marginLeft: '8px' }}>{label}</span>
</div> </div>
@ -95,13 +92,18 @@ function Connections(props: IProps) {
items: [ items: [
{ {
key: 'EnterWorkSpace', key: 'EnterWorkSpace',
label: i18n('connection.menu.enterToWorkSpace'), label: i18n('connection.button.connect'),
onClick: () => { onClick: () => {
props.dispatch({ dispatch({
type: 'connection/setCurConnection', type: 'connection/setCurConnection',
payload: menu.meta, payload: menu.meta,
}) });
history.push('/workspace')
dispatch({
type: 'database/fetchDatabaseAndSchemaList',
});
history.push('/workspace');
// window.location.replace('/workspace'); // window.location.replace('/workspace');
}, },
}, },
@ -160,35 +162,35 @@ function Connections(props: IProps) {
/> />
</div> </div>
) : ( ) : (
<div className={styles.dataBaseList}> <div className={styles.dataBaseList}>
{databaseTypeList.map((t) => { {databaseTypeList.map((t) => {
return ( return (
<div key={t.code} className={styles.databaseItem} onClick={handleCreateConnections.bind(null, t)}> <div key={t.code} className={styles.databaseItem} onClick={handleCreateConnections.bind(null, t)}>
<div className={styles.databaseItemMain}> <div className={styles.databaseItemMain}>
<div className={styles.databaseItemLeft}> <div className={styles.databaseItemLeft}>
<div className={styles.logoBox}> <div className={styles.logoBox}>
<Iconfont code={t.icon} /> <Iconfont code={t.icon} />
</div>
{t.name}
</div>
<div className={styles.databaseItemRight}>
<Iconfont code="&#xe631;" />
</div> </div>
{t.name}
</div>
<div className={styles.databaseItemRight}>
<Iconfont code="&#xe631;" />
</div> </div>
</div> </div>
); </div>
})} );
{ })}
Array.from({ length: 5 }).map(t => { {Array.from({ length: 20 }).map((t) => {
return <div className={styles.databaseItemSpacer}></div> return <div className={styles.databaseItemSpacer}></div>;
}) })}
} </div>
</div> )}
)}
</div> </div>
</div> </div>
); );
}; }
export default connect(({ connection, database }: { connection: ConnectionModelType; database: any }) => ({
export default connect(({ connection }: { connection: ConnectionState }) => (connection))(Connections); connectionModel: connection,
databaseModel: database,
}))(Connections);

View File

@ -7,7 +7,7 @@ import Setting from '@/blocks/Setting';
import Iconfont from '@/components/Iconfont'; import Iconfont from '@/components/Iconfont';
import BrandLogo from '@/components/BrandLogo'; import BrandLogo from '@/components/BrandLogo';
import DataSource from './connections'; import DataSource from './connection';
import Workspace from './workspace'; import Workspace from './workspace';
import Dashboard from './dashboard'; import Dashboard from './dashboard';
import Chat from './chat'; import Chat from './chat';

View File

@ -1,4 +1,4 @@
import createRequest from "./base"; import createRequest from './base';
import { IPageResponse, ITable, IPageParams } from '@/types'; import { IPageResponse, ITable, IPageParams } from '@/types';
import { DatabaseTypeCode } from '@/constants'; import { DatabaseTypeCode } from '@/constants';
@ -10,10 +10,10 @@ export interface IGetListParams extends IPageParams {
} }
export interface IExecuteSqlParams { export interface IExecuteSqlParams {
sql: string, sql: string;
dataSourceId: number, dataSourceId: number;
databaseName: string, databaseName: string;
consoleId: number, consoleId: number;
} }
export interface IExecuteSqlResponse { export interface IExecuteSqlResponse {
@ -25,9 +25,9 @@ export interface IExecuteSqlResponse {
dataList: any[]; dataList: any[];
} }
export interface IConnectConsoleParams { export interface IConnectConsoleParams {
consoleId: number, consoleId: number;
dataSourceId: number, dataSourceId: number;
databaseName: string, databaseName: string;
} }
const getList = createRequest<IGetListParams, IPageResponse<ITable>>('/api/rdb/ddl/list', {}); const getList = createRequest<IGetListParams, IPageResponse<ITable>>('/api/rdb/ddl/list', {});
@ -83,6 +83,10 @@ const getIndexList = createRequest<ITableParams, IColumn[]>('/api/rdb/ddl/index_
const getKeyList = createRequest<ITableParams, IColumn[]>('/api/rdb/ddl/key_list', { method: 'get' }); const getKeyList = createRequest<ITableParams, IColumn[]>('/api/rdb/ddl/key_list', { method: 'get' });
const getSchemaList = createRequest<ISchemaParams, ISchemaResponse[]>('/api/rdb/ddl/schema_list', { method: 'get' }); const getSchemaList = createRequest<ISchemaParams, ISchemaResponse[]>('/api/rdb/ddl/schema_list', { method: 'get' });
const getDatabaseSchemaList = createRequest<{ dataSourceId: number; databaseName?: string; schemaName?: string }>(
'/api/rdb/ddl/database_schema_list',
{ method: 'get' }
);
export default { export default {
getList, getList,
@ -96,5 +100,6 @@ export default {
getColumnList, getColumnList,
getIndexList, getIndexList,
getKeyList, getKeyList,
getSchemaList getSchemaList,
} getDatabaseSchemaList
};

View File

@ -1,13 +1,13 @@
import antdDarkTheme from './dark'; import antdDarkTheme from './dark';
import antdLightTheme from './light'; import antdLightTheme from './light';
import { ThemeType, PrimaryColorType } from "@/constants"; import { ThemeType, PrimaryColorType } from '@/constants';
import { ITheme } from '@/typings'; import { ITheme } from '@/typings/theme';
import lodash from 'lodash'; import lodash from 'lodash';
const antdThemeConfigs = { const antdThemeConfigs = {
[ThemeType.Dark]: antdDarkTheme, [ThemeType.Dark]: antdDarkTheme,
[ThemeType.Light]: antdLightTheme, [ThemeType.Light]: antdLightTheme,
} };
export function getAntdThemeConfig(theme: ITheme) { export function getAntdThemeConfig(theme: ITheme) {
const antdThemeConfig = lodash.cloneDeep(antdThemeConfigs[theme.backgroundColor]); const antdThemeConfig = lodash.cloneDeep(antdThemeConfigs[theme.backgroundColor]);
@ -15,29 +15,29 @@ export function getAntdThemeConfig(theme: ITheme) {
...antdThemeConfig.token, ...antdThemeConfig.token,
...(antdThemeConfig.antdPrimaryColor[theme.primaryColor as PrimaryColorType] || {}), ...(antdThemeConfig.antdPrimaryColor[theme.primaryColor as PrimaryColorType] || {}),
}; };
return antdThemeConfig return antdThemeConfig;
} }
// TODO: 只插入一次 // TODO: 只插入一次
export function InjectThemeVar(token: { [key in string]: string }, theme: ThemeType, primaryColor: PrimaryColorType) { export function InjectThemeVar(token: { [key in string]: string }, theme: ThemeType, primaryColor: PrimaryColorType) {
let css = ''; let css = '';
Object.keys(token).map(t => { Object.keys(token).map((t) => {
const attributeName = camelToDash(t); const attributeName = camelToDash(t);
let value = token[t]; let value = token[t];
// 将需要px的数字带上px // 将需要px的数字带上px
const joinPxArr = ['fontSize', 'borderRadius'] const joinPxArr = ['fontSize', 'borderRadius', 'borderRadiusLG'];
if (joinPxArr.includes(t)) { if (joinPxArr.includes(t)) {
value = value + 'px' value = value + 'px';
} }
css = css + `--${attributeName}: ${value};\n` css = css + `--${attributeName}: ${value};\n`;
}) });
const container = `html[theme='${theme}'],html[primary-color='${primaryColor}']{ const container = `html[theme='${theme}'],html[primary-color='${primaryColor}']{
${css} ${css}
}` }`;
let style = document.createElement("style"); // 创建style标签 let style = document.createElement('style'); // 创建style标签
style.type = "text/css"; style.type = 'text/css';
style.appendChild(document.createTextNode(container)); style.appendChild(document.createTextNode(container));
document.head.appendChild(style); // 将style标签插入到head标签中 document.head.appendChild(style); // 将style标签插入到head标签中

View File

@ -4,5 +4,6 @@ declare namespace NodeJS {
interface ProcessEnv { interface ProcessEnv {
readonly NODE_ENV: 'development' | 'production' readonly NODE_ENV: 'development' | 'production'
readonly UMI_ENV: string readonly UMI_ENV: string
readonly __ENV: string;
} }
} }