Browse Source

免密登录 100%

master
wenlele 2 years ago
parent
commit
7629ba2dec
  1. 48
      web/client/src/layout/containers/layout/index.jsx
  2. 10
      web/client/src/sections/auth/actions/auth.js
  3. 186
      web/client/src/sections/auth/containers/login.jsx
  4. 197
      web/client/src/sections/humanAffairs/components/deleteModal.jsx
  5. 8
      web/config.js
  6. 2
      web/package.json

48
web/client/src/layout/containers/layout/index.jsx

@ -13,6 +13,9 @@ import { useLocation } from "react-router";
import { RouteTable } from '$utils';
import { RouteRequest } from '@peace/utils';
import Cookie from 'js-cookie';
import { login, LOGIN_SUCCESS } from '../../../sections/auth/actions/auth';
import { error } from 'webpack-dev-server/lib/utils/colors';
NProgress.configure({
@ -31,8 +34,8 @@ let requestUser = true
// const location111 = useLocation();
const LayoutContainer = props => {
const {
dispatch, msg, user, copyright, children, sections, clientWidth, clientHeight,
location, match, routes, history, socket,
dispatch, actions, msg, user, copyright, children, sections, clientWidth, clientHeight,
location, match, routes, history, socket,apiRoot
} = props
const [collapsed, setCollapsed] = useState(false)
@ -205,32 +208,20 @@ const LayoutContainer = props => {
if (requestUser) {
requestUser = false;
RouteRequest.get(RouteTable.getDomain).then(res => {
console.log(res);
let token = Cookie.get('pepToken', { domain: res.root });
history.push('/humanAffairs/archivesCenter/personnelArchives/personnelFiles')
dispatch(login(values.username, values.password)).then(res => {
const data = res.payload.user
localStorage.setItem('word', JSON.stringify(values.password))
dispatch(actions.layout.initWebSocket({ ioUrl: apiRoot, token: data.token, hrUserId: data.hrUserInfo && hrUserInfo.id }))
})
// dispatch(getUserInfoByTokenUrl(token)).then(userRes => {
// if (userRes.success) {
// sessionStorage.setItem('user', JSON.stringify(userRes.payload.data));
// dispatch({
// type: 'INIT_AUTH',
// payload: {
// user: userRes.payload.data
// }
// })
// // window.location.href = window.location.href;
// } else {
// redirectToLogin(true);
// }
// }, error => {
// redirectToLogin(true);
// })
dispatch(login({ token })).then(res => {
if (res.type == 'LOGIN_SUCCESS') {
const data = res.payload?.user || {}
history.push('/humanAffairs/archivesCenter/personnelArchives/personnelFiles')
localStorage.setItem('poms_open_sider', JSON.stringify(["archivesCenter"]))
localStorage.setItem('poms_selected_sider', JSON.stringify(["humanAffairs"]))
dispatch(actions.layout.initWebSocket({ ioUrl: apiRoot, token: data.token, hrUserId: data.hrUserInfo && hrUserInfo.id }))
} else {
redirectToLogin(true);
}
}, error => {
redirectToLogin(true);
})
}, error => {
message.error('鉴权失败', 5);
redirectToLogin(true);
@ -378,7 +369,8 @@ function mapStateToProps (state) {
clientHeight: global.clientHeight,
msg: ajaxResponse.msg,
user: auth.user,
socket: webSocket.socket
socket: webSocket.socket,
apiRoot: global.apiRoot,
};
}

10
web/client/src/sections/auth/actions/auth.js

@ -4,7 +4,7 @@ import { ApiTable, AxyRequest, EmisRequest } from '$utils'
import { Request } from '@peace/utils';
export const INIT_AUTH = 'INIT_AUTH';
export function initAuth(userData) {
export function initAuth (userData) {
const sessionUser = JSON.parse(sessionStorage.getItem('hrUser'))
const user = userData || sessionUser || {};
if (user.authorized && !sessionUser) {
@ -21,11 +21,11 @@ export function initAuth(userData) {
export const REQUEST_LOGIN = 'REQUEST_LOGIN';
export const LOGIN_SUCCESS = 'LOGIN_SUCCESS';
export const LOGIN_ERROR = 'LOGIN_ERROR';
export function login(username, password) {
export function login ({ username, password, token }) {
return dispatch => {
dispatch({ type: REQUEST_LOGIN });
if (!username || !password) {
if ((!username || !password) && !token) {
dispatch({
type: LOGIN_ERROR,
payload: { error: '请输入账号名和密码' }
@ -43,7 +43,7 @@ export function login(username, password) {
// },
// });
return Request.post(ApiTable.login, { username, password, code: 'HR' })
return Request.post(ApiTable.login, { username, password, token, code: 'HR' })
.then(user => {
sessionStorage.setItem('hrUser', JSON.stringify(user));
return dispatch({
@ -63,7 +63,7 @@ export function login(username, password) {
}
export const LOGOUT = 'LOGOUT';
export function logout() {
export function logout () {
const user = JSON.parse(sessionStorage.getItem('hrUser'))
user && user.token ?
Request.put(ApiTable.logout, {

186
web/client/src/sections/auth/containers/login.jsx

@ -8,110 +8,110 @@ import { IconLock, IconUser } from '@douyinfe/semi-icons';
import '../style.less'
const Login = props => {
const { dispatch, user, error, actions, apiRoot, isRequesting } = props
const form = useRef();
const { dispatch, user, error, actions, apiRoot, isRequesting } = props
const form = useRef();
useEffect(() => {
if (error) {
Toast.error(error);
form.current.setValue('password', '')
}
}, [error])
useEffect(() => {
if (error) {
Toast.error(error);
form.current.setValue('password', '')
}
}, [error])
useEffect(() => {
if (user && user.authorized) {
dispatch(push('/humanAffairs/archivesCenter/personnelArchives/personnelFiles'));
localStorage.setItem('poms_open_sider', JSON.stringify(["archivesCenter"]))
localStorage.setItem('poms_selected_sider', JSON.stringify(["humanAffairs"]))
}
}, [user])
useEffect(() => {
if (user && user.authorized) {
dispatch(push('/humanAffairs/archivesCenter/personnelArchives/personnelFiles'));
localStorage.setItem('poms_open_sider', JSON.stringify(["archivesCenter"]))
localStorage.setItem('poms_selected_sider', JSON.stringify(["humanAffairs"]))
}
}, [user])
return (
<div style={{
width: '100%',
height: '100%',
background: '#F0F4FF',
}}>
<div style={{
width: '57.64%',
height: '100%'
}}>
<div className='zoomImage'>
<img src="/assets/images/background/loginText.png" style={{ width: 587, height: 81, margin: "143px 0 0 69px" }} />
</div>
return (
<div style={{
width: '100%',
height: '100%',
background: '#F0F4FF',
}}>
<div style={{
width: '57.64%',
height: '100%'
}}>
<div className='zoomImage'>
<img src="/assets/images/background/loginText.png" style={{ width: 587, height: 81, margin: "143px 0 0 69px" }} />
</div>
</div>
<div style={{
width: '42.36%',
height: '100%',
padding: '45px 60px',
background: 'rgb(255 255 255 / 50%)',
backdropFilter: "saturate(100%) contrast(100%) blur(17px)",
position: 'absolute',
top: 0,
right: 0,
zIndex: "6",
textAlign: 'center',
display: 'flex',
justifyContent: 'center',
background: '#FFFFFF'
}}>
<div style={{
width: '42.36%',
height: '100%',
padding: '45px 60px',
background: 'rgb(255 255 255 / 50%)',
backdropFilter: "saturate(100%) contrast(100%) blur(17px)",
position: 'absolute',
top: 0,
right: 0,
zIndex: "6",
textAlign: 'center',
display: 'flex',
justifyContent: 'center',
background: '#FFFFFF'
width: 388,
marginTop: "18.33%"
}}>
<div style={{
width: 388,
marginTop: "18.33%"
}}>
<div style={{ fontSize: 31, color: '#000000', marginBottom: 90 }}>
FS-EIMS企业信息管理系统
</div>
<Form
onSubmit={values => {
dispatch(login(values.username, values.password)).then(res => {
const data = res.payload.user
localStorage.setItem('word', JSON.stringify(values.password))
dispatch(actions.layout.initWebSocket({ ioUrl: apiRoot, token: data.token, hrUserId: data.hrUserInfo && hrUserInfo.id }))
})
}}
getFormApi={formApi => form.current = formApi}
>
<Form.Input
className='inputbgc'
field='username'
noLabel={true}
label='用户名'
placeholder='请输入账号'
prefix={<IconUser style={{ color: '#717171', marginRight: 14, marginLeft: 8 }} />}
style={{ background: '#FFFFFF', height: 46, marginBottom: 33, border: '1px solid rgb(185 211 239)', borderRadius: '4px' }}
/>
<Form.Input
field='password'
noLabel={true}
mode="password"
autoComplete=""
placeholder='请输入密码'
label='密码'
prefix={<IconLock style={{ color: '#717171', marginRight: 14, marginLeft: 8 }} />}
style={{ background: '#FFFFFF', height: 46, border: '1px solid rgb(185 211 239)', borderRadius: '4px' }}
/>
<img src="/assets/images/background/xiangqi.png" style={{ width: 112, height: 14, margin: "4px 0 0 278px" }} />
<Button htmlType='submit' block theme="solid" loading={isRequesting} style={{ marginTop: 56, height: 46, backgroundColor: '#0F7EFB', borderRadius: '27px' }}>立即登录</Button>
</Form>
<div style={{ fontSize: 31, color: '#000000', marginBottom: 90 }}>
FS-EIMS企业信息管理系统
</div>
<Form
onSubmit={values => {
dispatch(login({ username: values.username, password: values.password })).then(res => {
const data = res.payload.user
localStorage.setItem('word', JSON.stringify(values.password))
dispatch(actions.layout.initWebSocket({ ioUrl: apiRoot, token: data.token, hrUserId: data.hrUserInfo && hrUserInfo.id }))
})
}}
getFormApi={formApi => form.current = formApi}
>
<Form.Input
className='inputbgc'
field='username'
noLabel={true}
label='用户名'
placeholder='请输入账号'
prefix={<IconUser style={{ color: '#717171', marginRight: 14, marginLeft: 8 }} />}
style={{ background: '#FFFFFF', height: 46, marginBottom: 33, border: '1px solid rgb(185 211 239)', borderRadius: '4px' }}
/>
<Form.Input
field='password'
noLabel={true}
mode="password"
autoComplete=""
placeholder='请输入密码'
label='密码'
prefix={<IconLock style={{ color: '#717171', marginRight: 14, marginLeft: 8 }} />}
style={{ background: '#FFFFFF', height: 46, border: '1px solid rgb(185 211 239)', borderRadius: '4px' }}
/>
<img src="/assets/images/background/xiangqi.png" style={{ width: 112, height: 14, margin: "4px 0 0 278px" }} />
<Button htmlType='submit' block theme="solid" loading={isRequesting} style={{ marginTop: 56, height: 46, backgroundColor: '#0F7EFB', borderRadius: '27px' }}>立即登录</Button>
</div>
</Form>
</div>
</div >
);
</div>
</div >
);
}
function mapStateToProps(state) {
const { auth, global } = state;
return {
user: auth.user,
error: auth.error,
actions: global.actions,
apiRoot: global.apiRoot,
isRequesting: auth.isRequesting
}
function mapStateToProps (state) {
const { auth, global } = state;
return {
user: auth.user,
error: auth.error,
actions: global.actions,
apiRoot: global.apiRoot,
isRequesting: auth.isRequesting
}
}
export default connect(mapStateToProps)(Login);

197
web/client/src/sections/humanAffairs/components/deleteModal.jsx

@ -3,115 +3,116 @@ import { connect } from "react-redux";
import { Modal, Form, Button, Upload, Toast } from "@douyinfe/semi-ui";
import { IconAlertCircle } from '@douyinfe/semi-icons';
import cityData from './city.json';
import { ApiTable, AxyRequest, EmisRequest } from '$utils'
import PerfectScrollbar from "perfect-scrollbar";
import './style.less'
let Scrollbar;
function deleteModal (props) {
const {
close,
cancel,
visible,
dispatch,
actions,
pepUserId
} = props;
const { humanAffairs } = actions;
const form = useRef();//
const {
close,
cancel,
visible,
dispatch,
actions,
pepUserId,
user
} = props;
const { humanAffairs } = actions;
const form = useRef();//
const [idPhoto, setIdPhoto] = useState(); //
const [idPhoto, setIdPhoto] = useState(); //
const [word, setWord] = useState(); //
//
useEffect(() => {
setWord(JSON.parse(localStorage.getItem('word')))
}, []);
useEffect(() => {
const Project = document.getElementById("myForm");
if (Project) {
if (Project && Scrollbar) {
Scrollbar.update();
}
Scrollbar = new PerfectScrollbar("#myForm", {
suppressScrollX: true,
});
}
});
function handleOk () {
//
form.current
.validate()
.then((values) => {
if (word == values.word) {
dispatch(humanAffairs.delMember({ pepUserId: pepUserId, msg: '删除档案' })).then((res) => {//(PEP)
if (res.success) {
close();
}
})
}
else {
Toast.error('密码错误');
form.current.setValue('word', '')
}
const [word, setWord] = useState(); //
//
useEffect(() => {
setWord(JSON.parse(localStorage.getItem('word')))
}, []);
useEffect(() => {
const Project = document.getElementById("myForm");
if (Project) {
if (Project && Scrollbar) {
Scrollbar.update();
}
Scrollbar = new PerfectScrollbar("#myForm", {
suppressScrollX: true,
});
}
});
function handleOk () {
//
form.current
.validate()
.then((values) => {
console.log(values);
let data = EmisRequest?.post(`verify/user/${user?.id}/pswd`, { pswd: values?.word }, { token: user?.token }).then(res => {
dispatch(humanAffairs.delMember({ pepUserId: pepUserId, msg: '删除档案' })).then((res) => {//(PEP)
if (res.success) {
close();
}
})
}, err => {
Toast.error(err?.response?.body?.message || '密码错误')
form.current.setValue('word', '')
})
}
function handleCancel () {
cancel();
//
}
return (
<>
<Modal
title={'警告'}
okText="确认删除"
cancelText="取消"
visible={visible}
onOk={handleOk}
width={500}
onCancel={handleCancel}
})
}
function handleCancel () {
cancel();
//
}
return (
<>
<Modal
title={'警告'}
okText="确认删除"
cancelText="取消"
visible={visible}
onOk={handleOk}
width={500}
onCancel={handleCancel}
>
<div style={{ borderBottom: '1px solid #DCDEE0', margin: '0px -24px' }}></div>
<Form
// allowEmpty
labelPosition="left"
labelAlign="right"
labelWidth="116px"
onValueChange={(values, field) => {
console.log('values', values);
}}
getFormApi={(formApi) => (form.current = formApi)}
>
<div style={{ borderBottom: '1px solid #DCDEE0', margin: '0px -24px' }}></div>
<Form
// allowEmpty
labelPosition="left"
labelAlign="right"
labelWidth="116px"
onValueChange={(values, field) => {
console.log('values', values);
}}
getFormApi={(formApi) => (form.current = formApi)}
>
<div style={{ padding: '20px 0px' }}>
<div style={{ display: 'flex', alignItems: 'center' }}>
<div>
<Form.Input
field="word"
label='我的登录密码:'
style={{ width: 334 }}
initValue={'' || ""}
placeholder="请输入登录密码"
mode="password"
showClear
rules={[{ required: true, message: "请输入登录密码" }]}
/>
</div>
</div>
</div>
</Form>
</Modal >
</>
);
<div style={{ padding: '20px 0px' }}>
<div style={{ display: 'flex', alignItems: 'center' }}>
<div>
<Form.Input
field="word"
label='我的登录密码:'
style={{ width: 334 }}
initValue={'' || ""}
placeholder="请输入登录密码"
mode="password"
showClear
rules={[{ required: true, message: "请输入登录密码" }]}
/>
</div>
</div>
</div>
</Form>
</Modal >
</>
);
}
function mapStateToProps (state) {
const { auth, global, members } = state;
return {
// loading: members.isRequesting,
user: auth.user,
actions: global.actions,
apiRoot: global.apiRoot,
// members: members.data,
};
const { auth, global, members } = state;
return {
// loading: members.isRequesting,
user: auth.user,
actions: global.actions,
apiRoot: global.apiRoot,
// members: members.data,
};
}
export default connect(mapStateToProps)(deleteModal);

8
web/config.js

@ -13,6 +13,7 @@ dev && console.log('\x1B[33m%s\x1b[0m', '请遵循并及时更新 readme.md,
args.option(['p', 'port'], '启动端口');
args.option(['u', 'api-url'], 'webapi的URL');
args.option('apiHrUrl', 'webapi的URL 外网可访问');
args.option('apiEmisUrl', '企业管理 api');
args.option(['d', 'domain'], 'web domain');
@ -32,6 +33,7 @@ const flags = args.parse(process.argv);
const API_URL = process.env.API_URL || flags.apiUrl;
const API_HR_URL = process.env.API_HR_URL || flags.apiHrUrl;
const FS_HR_DOMAIN = process.env.FS_HR_DOMAIN || flags.domain;
const API_EMIS_URL = process.env.API_EMIS_URL || flags.apiEmisUrl;
// 七牛
const ANXINCLOUD_QINIU_AK = process.env.ANXINCLOUD_QINIU_ACCESSKEY || flags.qnak;
@ -88,6 +90,12 @@ const product = {
},
domain: FS_HR_DOMAIN,
}
}, {
entry: require('./middlewares/proxy').entry,
opts: {
host: API_EMIS_URL,
match: /^\/_emis\//,
}
}, {
entry: require('./client').entry,// 静态信息
opts: {}

2
web/package.json

@ -7,7 +7,7 @@
"test": "mocha",
"start-vite": "cross-env NODE_ENV=developmentVite npm run start-params",
"start": "cross-env NODE_ENV=development npm run start-params",
"start-params": "node server -p 5700 -u http://localhost:4700 --apiHrUrl http://localhost:4700 -d localhost --qnak XuDgkao6cL0HidoMAPnA5OB10Mc_Ew08mpIfRJK5 --qnsk yewcieZLzKZuDfig0wLZ9if9jKp2P_1jd3CMJPSa --qnbkt dev-hr --qndmn http://rjkwed13l.hn-bkt.clouddn.com --wkys http://10.8.30.109:14000",
"start-params": "node server -p 5700 -u http://localhost:4700 --apiHrUrl http://localhost:4700 -d localhost --apiEmisUrl http://localhost:4000 --qnak XuDgkao6cL0HidoMAPnA5OB10Mc_Ew08mpIfRJK5 --qnsk yewcieZLzKZuDfig0wLZ9if9jKp2P_1jd3CMJPSa --qnbkt dev-hr --qndmn http://rjkwed13l.hn-bkt.clouddn.com --wkys http://10.8.30.109:14000",
"deploy": "export NODE_ENV=production&& npm run build && node server",
"build-dev": "cross-env NODE_ENV=development&&webpack --config webpack.config.js",
"build": "cross-env NODE_ENV=production&&webpack --config webpack.config.prod.js"

Loading…
Cancel
Save