登录、用户接口联调

This commit is contained in:
zhaofengchao 2024-01-12 14:53:09 +08:00
parent bb74e26115
commit 55b18fac12
14 changed files with 432 additions and 88 deletions

View file

@ -1,20 +0,0 @@
import { Button, Result } from 'antd';
import React from 'react';
import { history } from 'umi';
const NoFoundPage = () => {
return (
<Result
status= "404"
title = "404"
subTitle = "页面未找到,请输入正确的地址。"
extra = {
< Button type = "primary" onClick = {() => history.push('/')}>
返回主页
< /Button>
}
/>
);
};
export default NoFoundPage;

17
client/src/pages/404.jsx Normal file
View file

@ -0,0 +1,17 @@
import { Button, Result } from 'antd';
import React from 'react';
import { history } from 'umi';
const NoFoundPage = () => {
return (<Result
status="404"
title="404"
subTitle="页面未找到,请输入正确的地址。"
extra={< Button type="primary" onClick={() => history.push('/')}>
返回主页
</Button>}
/>
)
};
export default NoFoundPage;

View file

@ -1,19 +1,14 @@
import { connect } from 'umi';
import { Input, Form, Button, Checkbox } from 'antd';
// import md5 from 'md5';
import styles from './index.less';
import JSEncrypt from 'jsencrypt';
import { Base64 } from 'js-base64';
import Title from 'antd/es/skeleton/Title';
import { rsaPsw } from '@/utils'
import { useState, useEffect } from 'react';
// import Base64 from 'crypto-js/enc-base64';
const View = ({
loginModel,
dispatch,
location,
}) => {
const [title, setTitle] = useState('login')
const pub = "-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArq9XTUSeYr2+N1h3Afl/z8Dse/2yD0ZGrKwx+EEEcdsBLca9Ynmx3nIB5obmLlSfmskLpBo0UACBmB5rEjBp2Q2f3AG3Hjd4B+gNCG6BDaawuDlgANIhGnaTLrIqWrrcm4EMzJOnAOI1fgzJRsOOUEfaS318Eq9OVO3apEyCCt0lOQK6PuksduOjVxtltDav+guVAA068NrPYmRNabVKRNLJpL8w4D44sfth5RvZ3q9t+6RTArpEtc5sh5ChzvqPOzKGMXW83C95TxmXqpbK6olN4RevSfVjEAgCydH6HN6OhtOQEcnrU97r9H0iZOWwbw3pVrZiUkuRD1R56Wzs2wIDAQAB-----END PUBLIC KEY-----"
const changeTitle = () => {
setTitle((title) => title === 'login' ? 'register' : 'login')
}
@ -27,10 +22,8 @@ const View = ({
const onCheck = async () => {
try {
const params = await form.validateFields();
console.log('Success:', params);
const encryptor = new JSEncrypt()
encryptor.setPublicKey(pub)
var rsaPassWord = encryptor.encrypt(Base64.encode(params.password))
var rsaPassWord = rsaPsw(params.password)
if (title === 'login') {
dispatch({
type: 'loginModel/login',
@ -103,6 +96,7 @@ const View = ({
?<a onClick={changeTitle}></a>
</div>)
}</div>
<div><a href="https://github.com/login/oauth/authorize?scope=user:email&client_id=302129228f0d96055bee"></a></div>
<Form.Item {...formTailLayout}>
<Button type="primary" onClick={onCheck}>
Check

View file

@ -19,48 +19,36 @@ const Model = {
effects: {
*login({ payload = {} }, { call, put }) {
console.log(111, payload)
const { retcode, data, retmsg } = yield call(userService.login, payload);
const { data, response } = yield call(userService.login, payload);
const { retcode, data: res, retmsg } = data
console.log()
const Authorization = response.headers.get('Authorization')
if (retcode === 0) {
message.success('登录成功!');
const name = data.name;
const token = data.access_token;
const role = data.role;
const title = data.title;
const token = res.access_token;
const userInfo = {
role: data.avatar,
title: data.title,
name: data.nickname,
avatar: res.avatar,
name: res.nickname,
email: res.email
};
localStorage.setItem('token', token)
localStorage.setItem('userInfo', JSON.stringify(userInfo))
// setTimeout(() => {
// window.location.href = '/file';
// }, 300);
localStorage.setItem('Authorization', Authorization)
setTimeout(() => {
window.location.href = '/file';
}, 300);
}
},
*register({ payload = {} }, { call, put }) {
console.log(111)
const { retcode, data, retmsg } = yield call(userService.register, payload);
// setTimeout(() => {
// window.location.href = '/';
// }, 300);
// if (code === 0) {
// message.success('登录成功!');
// const name = data.name;
// const token = data.token;
// const role = data.role;
// const title = data.title;
// const userInfo = {
// role: data.role,
// title: data.title,
// name: data.name || data.Name,
// };
// store.token = token;
// store.userInfo = userInfo;
// setTimeout(() => {
// window.location.href = '/file';
// }, 300);
// }
const { data, response } = yield call(userService.register, payload);
console.log()
const { retcode, data: res, retmsg } = data
if (retcode === 0) {
message.success('注册成功!');
setTimeout(() => {
window.location.href = '/login';
}, 300);
}
}
},
reducers: {

View file

@ -0,0 +1,88 @@
import { connect } from 'umi';
import i18n from 'i18next';
import { useTranslation, Trans } from 'react-i18next'
import { Input, Modal, Form } from 'antd'
import { rsaPsw } from '@/utils'
import styles from './index.less';
type FieldType = {
newPassword?: string;
password?: string;
};
const Index = ({ settingModel, dispatch }) => {
const { isShowPSwModal } = settingModel
const { t } = useTranslation()
const handleCancel = () => {
dispatch({
type: 'settingModel/updateState',
payload: {
isShowPSwModal: false
}
});
};
const [form] = Form.useForm()
const handleOk = async () => {
try {
const values = await form.validateFields();
var password = rsaPsw(values.password)
var new_password = rsaPsw(values.newPassword)
dispatch({
type: 'settingModel/setting',
payload: {
password,
new_password
},
callback: () => {
dispatch({
type: 'settingModel/updateState',
payload: {
isShowPSwModal: false
}
});
dispatch({
type: 'settingModel/getUserInfo',
payload: {
}
});
}
});
} catch (errorInfo) {
console.log('Failed:', errorInfo);
}
};
return (
<Modal title="Basic Modal" open={isShowPSwModal} onOk={handleOk} onCancel={handleCancel}>
<Form
form={form}
name="validateOnly"
labelCol={{ span: 8 }}
wrapperCol={{ span: 16 }}
style={{ maxWidth: 600 }}
autoComplete="off"
>
<Form.Item<FieldType>
label="旧密码"
name="password"
rules={[{ required: true, message: 'Please input your password!' }]}
>
<Input.Password />
</Form.Item>
<Form.Item<FieldType>
label="新密码"
name="newPassword"
rules={[{ required: true, message: 'Please input your newPassword!' }]}
>
<Input.Password />
</Form.Item>
</Form>
</Modal >
);
}
export default connect(({ settingModel, loading }) => ({ settingModel, loading }))(Index);

View file

@ -0,0 +1,72 @@
import { connect } from 'umi';
import i18n from 'i18next';
import { useTranslation, Trans } from 'react-i18next'
import { Table } from 'antd'
import styles from './index.less';
import type { ColumnsType } from 'antd/es/table';
interface DataType {
key: React.Key;
name: string;
age: number;
address: string;
description: string;
}
const Index = ({ settingModel, dispatch }) => {
const { t } = useTranslation()
const columns: ColumnsType<DataType> = [
{ title: 'Name', dataIndex: 'name', key: 'name' },
{ title: 'Age', dataIndex: 'age', key: 'age' },
{
title: 'Action',
dataIndex: '',
key: 'x',
render: () => <a>Delete</a>,
},
];
const data: DataType[] = [
{
key: 1,
name: 'John Brown',
age: 32,
address: 'New York No. 1 Lake Park',
description: 'My name is John Brown, I am 32 years old, living in New York No. 1 Lake Park.',
},
{
key: 2,
name: 'Jim Green',
age: 42,
address: 'London No. 1 Lake Park',
description: 'My name is Jim Green, I am 42 years old, living in London No. 1 Lake Park.',
},
{
key: 3,
name: 'Not Expandable',
age: 29,
address: 'Jiangsu No. 1 Lake Park',
description: 'This not expandable',
},
{
key: 4,
name: 'Joe Black',
age: 32,
address: 'Sydney No. 1 Lake Park',
description: 'My name is Joe Black, I am 32 years old, living in Sydney No. 1 Lake Park.',
},
];
return (
<Table
columns={columns}
expandable={{
expandedRowRender: (record) => <p style={{ margin: 0 }}>{record.description}</p>,
rowExpandable: (record) => record.name !== 'Not Expandable',
}}
dataSource={data}
/>
);
}
export default connect(({ settingModel, loading }) => ({ settingModel, loading }))(Index);

View file

@ -0,0 +1,48 @@
import { connect } from 'umi';
import i18n from 'i18next';
import { useTranslation, Trans } from 'react-i18next'
import { Modal, Table } from 'antd'
import styles from './index.less';
import type { ColumnsType } from 'antd/es/table';
interface DataType {
key: React.Key;
name: string;
role: string;
time: string;
}
const Index = ({ settingModel, dispatch }) => {
const { isShowTntModal, tenantData, loading } = settingModel
const { t } = useTranslation()
const handleCancel = () => {
dispatch({
type: 'settingModel/updateState',
payload: {
isShowTntModal: false
}
});
};
console.log(tenantData)
const handleOk = async () => {
dispatch({
type: 'settingModel/updateState',
payload: {
isShowTntModal: false
}
});
};
const columns: ColumnsType<DataType> = [
{ title: '姓名', dataIndex: 'name', key: 'name' },
{ title: '角色', dataIndex: 'role', key: 'age' },
{ title: '活动时间', dataIndex: 'time', key: 'time' },
];
return (
<Modal title="Basic Modal" open={isShowTntModal} onOk={handleOk} onCancel={handleCancel}>
<Table rowKey='name' loading={loading} columns={columns} dataSource={tenantData} />
</Modal >
);
}
export default connect(({ settingModel, loading }) => ({ settingModel, loading }))(Index);

View file

@ -0,0 +1,8 @@
.settingPage {
padding: 10px;
}
.avatar {
display: flex;
justify-content: center;
}

View file

@ -1,20 +1,67 @@
import { connect } from 'umi';
import i18n from 'i18next';
import { Button } from 'antd'
import { useTranslation, Trans } from 'react-i18next'
import { Button, Input, Modal, Form, FloatButton, Table } from 'antd'
function Index() {
import styles from './index.less';
import CPwModal from './CPwModal'
import TntModal from './TntModal'
import List from './List'
const Index = ({ settingModel, dispatch }) => {
const { t } = useTranslation()
const userInfo = JSON.parse(localStorage.getItem('userInfo') || '')
const changeLang = (val: string) => { // 改变状态里的 语言 进行切换
i18n.changeLanguage(val);
}
const { t } = useTranslation()
const showCPwModal = () => {
dispatch({
type: 'settingModel/updateState',
payload: {
isShowPSwModal: true
}
});
};
const showTntModal = () => {
dispatch({
type: 'settingModel/updateState',
payload: {
isShowTntModal: true
}
});
dispatch({
type: 'settingModel/getTenantInfo',
payload: {
}
});
};
return (
<div>
<div>
<Button type="primary" onClick={() => i18n.changeLanguage(i18n.language == 'en' ? 'zh' : 'en')}>{t('setting.btn')}</Button>
<div className={styles.settingPage}>
<div className={styles.avatar}>
<img style={{ width: 50, marginRight: 5 }} src="https://os.alipayobjects.com/rmsportal/QBnOOoLaAfKPirc.png" alt="" />
<div>
<div>{userInfo.name}</div>
<div><span>******</span><Button type='link' onClick={showCPwModal}></Button></div>
</div>
</div >
<div>
<Button type="link" onClick={showTntModal}>
</Button>
<Button type="link" >
</Button>
<List />
</div>
</div>
<CPwModal />
<TntModal />
<FloatButton shape='square' description={t('setting.btn')} onClick={() => i18n.changeLanguage(i18n.language == 'en' ? 'zh' : 'en')} type="default" style={{ right: 94, fontSize: 14 }} />
</div >
);
}
export default Index;
export default connect(({ settingModel, loading }) => ({ settingModel, loading }))(Index);

View file

@ -0,0 +1,75 @@
import { message } from 'antd';
import { addParam } from '@/utils';
import userService from '@/services/userService';
const Model = {
namespace: 'settingModel',
state: {
isShowPSwModal: false,
isShowTntModal: false,
loading: false,
tenantData: []
},
subscriptions: {
setup({ dispatch, history }) {
history.listen(location => {
});
}
},
effects: {
*setting({ payload = {}, callback }, { call, put }) {
const { data, response } = yield call(userService.setting, payload);
const { retcode, data: res, retmsg } = data
if (retcode === 0) {
message.success('密码修改成功!');
callback && callback()
}
},
*getUserInfo({ payload = {} }, { call, put }) {
const { data, response } = yield call(userService.user_info, payload);
const { retcode, data: res, retmsg } = data
const userInfo = {
avatar: res.avatar,
name: res.nickname,
email: res.email
};
localStorage.setItem('userInfo', JSON.stringify(userInfo))
if (retcode === 0) {
// localStorage.setItem('userInfo',res.)
}
},
*getTenantInfo({ payload = {} }, { call, put }) {
yield put({
type: 'updateState',
payload: {
loading: true
}
});
const { data, response } = yield call(userService.get_tenant_info, payload);
const { retcode, data: res, retmsg } = data
yield put({
type: 'updateState',
payload: {
loading: false
}
});
if (retcode === 0) {
yield put({
type: 'updateState',
payload: {
tenantData: res
}
});
}
}
},
reducers: {
updateState(state, { payload }) {
return {
...state,
...payload
};
}
}
};
export default Model;

View file

@ -3,7 +3,7 @@ import registerServer from '@/utils/registerServer';
import request from '@/utils/request';
const {
login, register } = api;
login, register, setting, user_info, tenant_info } = api;
interface userServiceType {
login: (params: any) => void
}
@ -11,12 +11,25 @@ const userService = registerServer(
{
login: {
url: login,
method: 'post'
method: 'post',
},
register: {
url: register,
method: 'post'
}
},
setting: {
url: setting,
method: 'post'
},
user_info: {
url: user_info,
method: 'get'
},
get_tenant_info: {
url: tenant_info,
method: 'get'
},
},
request
);

View file

@ -16,6 +16,9 @@ export default {
// 用户
login: `${api_host}/user/login`,
register: `${api_host}/user/register`,
setting: `${api_host}/user/setting`,
user_info: `${api_host}/user/info`,
tenant_info: `${api_host}/user/tenant_info`,
user: `${api_host}/user/validate`,
getUrl: `${api_host}/requestGetUrl`,
getAdPermits: `${api_host}/adServer/getAdPermits`,

View file

@ -5,7 +5,8 @@
*/
// import numeral from 'numeral';
import store from '@/utils/persistStore';
import JSEncrypt from 'jsencrypt';
import { Base64 } from 'js-base64';
export const parseQuery = (url = window.location.search, isNoCaseSensitive: boolean) => {
return window.g_history.location.query;
let arr, part;
@ -150,6 +151,14 @@ export const formatRequestUrlByDomainPrefix = url => {
export const getWidth = () => {
return { width: window.innerWidth };
};
export const rsaPsw = (password: string) => {
const pub = "-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArq9XTUSeYr2+N1h3Afl/z8Dse/2yD0ZGrKwx+EEEcdsBLca9Ynmx3nIB5obmLlSfmskLpBo0UACBmB5rEjBp2Q2f3AG3Hjd4B+gNCG6BDaawuDlgANIhGnaTLrIqWrrcm4EMzJOnAOI1fgzJRsOOUEfaS318Eq9OVO3apEyCCt0lOQK6PuksduOjVxtltDav+guVAA068NrPYmRNabVKRNLJpL8w4D44sfth5RvZ3q9t+6RTArpEtc5sh5ChzvqPOzKGMXW83C95TxmXqpbK6olN4RevSfVjEAgCydH6HN6OhtOQEcnrU97r9H0iZOWwbw3pVrZiUkuRD1R56Wzs2wIDAQAB-----END PUBLIC KEY-----"
const encryptor = new JSEncrypt()
encryptor.setPublicKey(pub)
return encryptor.encrypt(Base64.encode(password))
}
export default {
parseQuery,

View file

@ -48,13 +48,11 @@ const errorHandler = (error: any) => {
notification.error({
message: `请求错误 ${status}: ${url}`,
description: errorText,
top: 65
});
} else if (!response) {
notification.error({
description: '您的网络发生异常,无法连接服务器',
message: '网络异常',
top: 65
});
}
}
@ -67,18 +65,20 @@ const errorHandler = (error: any) => {
const request = extend({
errorHandler, // 默认错误处理
// credentials: 'include', // 默认请求是否带上cookie
timeout: 3000000
timeout: 3000000,
getResponse: true
});
request.interceptors.request.use((url, options) => {
let prefix = '';
console.log(url)
const Authorization = localStorage.getItem('Authorization')
return {
url,
options: {
...options,
headers: {
...(options.skipToken ? undefined : { Authorization: 'Bearer ' + store.token }),
...(options.skipToken ? undefined : { Authorization }),
...options.headers
},
interceptors: true
@ -90,28 +90,30 @@ request.interceptors.request.use((url, options) => {
* response拦截器
* */
request.interceptors.response.use(async (response, request) => {
console.log(response, request)
const data = await response.clone().json();
// response 拦截
if (data.retcode === 401 || data.retcode === 401) {
notification.error({
message: data.errorMessage,
description: data.errorMessage,
message: data.retmsg,
description: data.retmsg,
duration: 3,
});
} else if (data.retcode !== 0) {
if (data.retcode === 100) {
//retcode为100 时账户名或者密码错误, 为了跟之前弹窗一样所以用message
message.error(data.errorMessage);
message.error(data.retmsg);
} else {
notification.error({
message: `提示 : ${data.retcode}`,
description: data.errorMessage,
description: data.retmsg,
duration: 3,
});
}
return response; //这里return response, 是为了避免modal里面报retcode undefined
return response;
} else {
return response;
}
});