kra/web/src/pages/init/index.tsx

359 lines
10 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* KRA - Database Init Page
* Database initialization wizard
*/
import React, { useState } from 'react';
import { Form, Input, Select, Button, message, Modal, Spin } from 'antd';
import { history, Helmet } from '@umijs/max';
import { initDB } from '@/services/kratos/initdb';
import { createStyles } from 'antd-style';
type DBType = 'mysql' | 'pgsql' | 'oracle' | 'mssql' | 'sqlite';
interface InitFormData {
adminPassword: string;
dbType: DBType;
host: string;
port: string;
userName: string;
password: string;
dbName: string;
dbPath?: string;
template?: string;
}
const dbDefaults: Record<DBType, Partial<InitFormData>> = {
mysql: {
host: '127.0.0.1',
port: '3306',
userName: 'root',
dbName: 'kra',
},
pgsql: {
host: '127.0.0.1',
port: '5432',
userName: 'postgres',
dbName: 'kra',
template: 'template0',
},
oracle: {
host: '127.0.0.1',
port: '1521',
userName: 'oracle',
dbName: 'kra',
},
mssql: {
host: '127.0.0.1',
port: '1433',
userName: 'mssql',
dbName: 'kra',
},
sqlite: {
host: '',
port: '',
userName: '',
dbName: 'kra',
dbPath: '',
},
};
const useStyles = createStyles(({ token }) => ({
container: {
width: '100%',
height: '100vh',
display: 'flex',
position: 'relative',
overflow: 'hidden',
},
leftSection: {
flex: 1,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
background: '#fff',
position: 'relative',
zIndex: 10,
},
rightSection: {
width: '50%',
height: '100%',
background: '#194bfb',
display: 'none',
'@media (min-width: 768px)': {
display: 'block',
},
},
rightBanner: {
width: '100%',
height: '100%',
objectFit: 'cover',
},
oblique: {
position: 'absolute',
height: '130%',
width: '60%',
background: '#fff',
transform: 'rotate(-12deg)',
marginLeft: '-320px',
zIndex: 5,
},
content: {
zIndex: 999,
maxWidth: '500px',
padding: '24px',
},
readmeSection: {
animation: 'slideInFwdTop 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94) both',
},
formSection: {
width: '384px',
animation: 'slideInLeft 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94) both',
},
title: {
fontSize: '32px',
fontWeight: 700,
textAlign: 'center' as const,
marginBottom: '16px',
color: token.colorText,
},
subtitle: {
fontSize: '16px',
color: token.colorTextSecondary,
marginBottom: '8px',
},
notice: {
fontSize: '14px',
color: token.colorTextSecondary,
marginBottom: '8px',
lineHeight: 1.8,
},
link: {
color: '#1890ff',
fontWeight: 600,
},
highlight: {
color: '#ff4d4f',
fontWeight: 700,
fontSize: '24px',
marginLeft: '8px',
},
buttonGroup: {
display: 'flex',
justifyContent: 'space-between',
marginTop: '32px',
},
formItem: {
marginBottom: '16px',
},
}));
const InitPage: React.FC = () => {
const [form] = Form.useForm();
const [showForm, setShowForm] = useState(false);
const [loading, setLoading] = useState(false);
const { styles } = useStyles();
const handleShowForm = () => {
setShowForm(true);
};
const handleGoDoc = () => {
window.open('https://go-kratos.dev/docs/getting-started/start', '_blank');
};
const handleDBTypeChange = (value: DBType) => {
const defaults = dbDefaults[value];
form.setFieldsValue({
...defaults,
password: '',
adminPassword: form.getFieldValue('adminPassword'),
});
};
const handleSubmit = async (values: InitFormData) => {
if (values.adminPassword.length < 6) {
message.error('密码长度不能小于6位');
return;
}
setLoading(true);
try {
const res = await initDB(values);
if (res.code === 0) {
message.success(res.msg || '初始化成功');
Modal.confirm({
title: '配置完成',
content: '已经完成基础数据库初始化!建议先阅读官方文档,以获得更好的开发体验。',
okText: '查看文档',
cancelText: '稍后查看',
centered: true,
onOk: () => {
window.open('https://go-kratos.dev/docs/', '_blank');
history.push('/user/login');
},
onCancel: () => {
history.push('/user/login');
},
});
} else {
message.error(res.msg || '初始化失败');
}
} catch (error: any) {
message.error(error?.message || '初始化失败');
} finally {
setLoading(false);
}
};
return (
<div className={styles.container}>
<Helmet>
<title> - Kratos Admin</title>
</Helmet>
<Spin spinning={loading} tip="正在初始化数据库,请稍候..." fullscreen />
<div className={styles.leftSection}>
<div className={styles.oblique} />
{!showForm ? (
<div className={`${styles.content} ${styles.readmeSection}`}>
<h1 className={styles.title}>KRATOS-ADMIN</h1>
<p className={styles.subtitle}></p>
<p className={styles.notice}>1. React Golang </p>
<p className={styles.notice}>
2.
<a className={styles.link} href="https://go-kratos.dev/docs/" target="_blank" rel="noopener noreferrer">
</a>
</p>
<p className={styles.notice}>3. </p>
<p className={styles.notice}>
4. 使 MySQL
<span className={styles.highlight}>InnoDB</span>
</p>
<p className={styles.notice}></p>
<div className={styles.buttonGroup}>
<Button type="primary" size="large" onClick={handleGoDoc}>
</Button>
<Button type="primary" size="large" onClick={handleShowForm}>
</Button>
</div>
</div>
) : (
<div className={`${styles.content} ${styles.formSection}`}>
<Form
form={form}
layout="horizontal"
labelCol={{ span: 6 }}
wrapperCol={{ span: 18 }}
initialValues={{
adminPassword: '123456',
dbType: 'mysql',
...dbDefaults.mysql,
password: '',
}}
onFinish={handleSubmit}
size="large"
>
<Form.Item
label="管理员密码"
name="adminPassword"
className={styles.formItem}
rules={[
{ required: true, message: '请输入管理员密码' },
{ min: 6, message: '密码至少6个字符' },
]}
>
<Input.Password placeholder="admin账号的默认密码" />
</Form.Item>
<Form.Item
label="数据库类型"
name="dbType"
className={styles.formItem}
>
<Select onChange={handleDBTypeChange}>
<Select.Option value="mysql">MySQL</Select.Option>
<Select.Option value="pgsql">PostgreSQL</Select.Option>
<Select.Option value="oracle">Oracle</Select.Option>
<Select.Option value="mssql">SQL Server</Select.Option>
<Select.Option value="sqlite">SQLite</Select.Option>
</Select>
</Form.Item>
<Form.Item noStyle shouldUpdate={(prev, cur) => prev.dbType !== cur.dbType}>
{({ getFieldValue }) => {
const dbType = getFieldValue('dbType');
if (dbType === 'sqlite') return null;
return (
<>
<Form.Item label="Host" name="host" className={styles.formItem}>
<Input placeholder="请输入数据库链接" />
</Form.Item>
<Form.Item label="Port" name="port" className={styles.formItem}>
<Input placeholder="请输入数据库端口" />
</Form.Item>
<Form.Item label="用户名" name="userName" className={styles.formItem}>
<Input placeholder="请输入数据库用户名" />
</Form.Item>
<Form.Item label="密码" name="password" className={styles.formItem}>
<Input.Password placeholder="请输入数据库密码(没有则为空)" />
</Form.Item>
</>
);
}}
</Form.Item>
<Form.Item label="数据库名" name="dbName" className={styles.formItem}>
<Input placeholder="请输入数据库名称" />
</Form.Item>
<Form.Item noStyle shouldUpdate={(prev, cur) => prev.dbType !== cur.dbType}>
{({ getFieldValue }) => {
const dbType = getFieldValue('dbType');
if (dbType === 'sqlite') {
return (
<Form.Item label="数据库路径" name="dbPath" className={styles.formItem}>
<Input placeholder="请输入sqlite数据库文件存放路径" />
</Form.Item>
);
}
if (dbType === 'pgsql') {
return (
<Form.Item label="Template" name="template" className={styles.formItem}>
<Input placeholder="请输入postgresql指定template" />
</Form.Item>
);
}
return null;
}}
</Form.Item>
<Form.Item wrapperCol={{ offset: 6, span: 18 }}>
<Button type="primary" htmlType="submit" block>
</Button>
</Form.Item>
</Form>
</div>
)}
</div>
<div className={styles.rightSection}>
<img
src="/login_right_banner.jpg"
alt="banner"
className={styles.rightBanner}
/>
</div>
</div>
);
};
export default InitPage;