Merge remote-tracking branch 'origin/main'

feature/price_manager
Lei OT 1 year ago
commit af2ce43b2a

@ -0,0 +1,12 @@
{
"CurrentPassword": "Current password",
"NewPassword": "New password",
"ReenterPassword": "Reenter password",
"Validation": {
"Success": "Your password has been successfully updated.",
"Fail": "Failed to change password. Please try again.",
"CurrentPassword": "Please input your password.",
"NewPassword": "Please input your new password.",
"ReenterPassword": "Please reenter your password."
}
}

@ -0,0 +1,12 @@
{
"CurrentPassword": "当前密码",
"NewPassword": "新密码",
"ReenterPassword": "重复输入密码",
"Validation": {
"Success": "密码更新成功",
"Fail": "密码更新失败",
"CurrentPassword": "请输入密码。",
"NewPassword": "请输入新密码。",
"ReenterPassword": "请重复输入密码。"
}
}

@ -51,10 +51,6 @@
"Notice": "通知", "Notice": "通知",
"Report": "质量评分" "Report": "质量评分"
}, },
"Notification": {
"Title": "温馨提示",
"LoginFailed": "密码错误,登陆失败。"
},
"Validation": { "Validation": {
"Title": "温馨提示", "Title": "温馨提示",
"LoginFailed": "密码错误,登陆失败。", "LoginFailed": "密码错误,登陆失败。",

@ -6,7 +6,7 @@ const persistObject = {}
* G-JSON:LOGIN_USER -> loginUser = { username: 'test-username' } * G-JSON:LOGIN_USER -> loginUser = { username: 'test-username' }
*/ */
export function usingStorage() { export function usingStorage() {
// TODO: rename storageUse()???webStorage()???
const getStorage = () => { const getStorage = () => {
if (import.meta.env.DEV && window.localStorage) { if (import.meta.env.DEV && window.localStorage) {
return window.localStorage return window.localStorage

@ -17,7 +17,7 @@ i18n
backend: { backend: {
loadPath: '/locales/{{lng}}/{{ns}}.json', loadPath: '/locales/{{lng}}/{{ns}}.json',
}, },
ns: ['common', 'group', 'vendor'], ns: ['common', 'group', 'vendor', 'account'],
defaultNS: 'common', defaultNS: 'common',
detection: { detection: {
// convertDetectedLanguage: 'Iso15897', // convertDetectedLanguage: 'Iso15897',

@ -1,33 +1,51 @@
import { makeAutoObservable, runInAction } from "mobx";
import { create } from 'zustand' import { create } from 'zustand'
import { appendRequestParams, fetchJSON, postForm } from '@/utils/request' import { appendRequestParams, fetchJSON, postForm } from '@/utils/request'
import { HT_HOST } from "@/config" import { HT_HOST } from "@/config"
import { isNotEmpty, prepareUrl } from '@/utils/commons'
import { loadPageSpy } from '@/pageSpy' import { loadPageSpy } from '@/pageSpy'
import { usingStorage } from '@/hooks/usingStorage' import { usingStorage } from '@/hooks/usingStorage'
const KEY_LOGIN_TOKEN = 'G-STR:LOGIN_TOKEN' const KEY_LOGIN_TOKEN = 'G-STR:LOGIN_TOKEN'
const KEY_TRAVEL_AGENCY_ID = 'G-INT:TRAVEL_AGENCY_ID' const KEY_TRAVEL_AGENCY_ID = 'G-INT:TRAVEL_AGENCY_ID'
const KEY_USER_ID = 'G-INT:USER_ID' const KEY_USER_ID = 'G-INT:USER_ID'
const KEY_USER_NAME = 'G-STR:USERNAME' const KEY_USER_DETAIL = 'G-JSON:USER_DETAIL'
export const fetchLoginToken = async (username, password) => {
const formData = new FormData()
formData.append('username', username)
formData.append('Password', password)
const { errcode, Result } = await postForm(
`${HT_HOST}/service-CooperateSOA/Login`,
formData)
return errcode !== 0 ? {} : Result
}
export const fetchUserDetail = async (loginToken) => {
const { errcode, Result } = await fetchJSON(
`${HT_HOST}/service-CooperateSOA/GetLinkManInfo`, { token: loginToken})
return errcode !== 0 ? {} : Result
}
async function fetchLastRequet() {
const { errcode, result } = await fetchJSON(`${HT_HOST}/service-CooperateSOA/GetLastReqDate`)
return errcode !== 0 ? {} : result
}
const useAuthStore = create((set, get) => ({ const useAuthStore = create((set, get) => ({
tokenInterval: null, tokenInterval: null,
tokenTimeout: false,
loginStatus: 0, loginStatus: 0,
loginUser: { loginUser: {
token: '', token: '',
userId: 0, // LMI_SN
username: '0',
travelAgencyId: 0, // VEI_SN
travelAgencyName: '',
telephone: '', telephone: '',
emailAddress: '', emailAddress: '',
cityId: 0, cityId: 0,
timeout: false,
permissionList: [], permissionList: [],
}, },
@ -48,137 +66,81 @@ const useAuthStore = create((set, get) => ({
}, },
validateUserPassword: async (usr, pwd) => { validateUserPassword: async (usr, pwd) => {
const { startTokenInterval } = get()
const { setStorage } = usingStorage() const { setStorage } = usingStorage()
const formData = new FormData() const { token: loginToken } = await fetchLoginToken(usr, pwd)
formData.append('username', usr)
formData.append('Password', pwd)
async function fetchLoginToken() {
const postUrl = HT_HOST + '/service-CooperateSOA/Login'
const json = await postForm(postUrl, formData)
if (json.errcode == 0 && isNotEmpty(json.Result)) {
return json.Result.token;
} else {
return 0;
}
}
const loginToken = await fetchLoginToken()
setStorage(KEY_LOGIN_TOKEN, loginToken)
appendRequestParams('token', loginToken)
const fetchUrl = prepareUrl(HT_HOST + '/service-CooperateSOA/GetLinkManInfo').build() const userDetail = await fetchUserDetail(loginToken)
return fetchJSON(fetchUrl) set(() => ({
.then(json => { loginUser: {
if (json.errcode == 0) { telephone: userDetail.LkPhone,
set(() => ({ emailAddress: userDetail.LMI_listmail,
loginUser: { cityId: userDetail.citysn,
token: loginToken, },
timeout: false, tokenTimeout: false,
userId: json.Result.LMI_SN, loginStatus: 302
username: json.Result.LoginName, }))
travelAgencyId: json.Result.LMI_VEI_SN,
travelAgencyName: json.Result.VName, setStorage(KEY_LOGIN_TOKEN, loginToken)
telephone: json.Result.LkPhone, setStorage(KEY_USER_ID, userDetail.LMI_SN)
emailAddress: json.Result.LMI_listmail, setStorage(KEY_TRAVEL_AGENCY_ID, userDetail.LMI_VEI_SN)
cityId: json.Result.citysn, setStorage(KEY_USER_DETAIL, {username: userDetail.LoginName, travelAgencyName: userDetail.VName})
}, appendRequestParams('token', loginToken)
loginStatus: 302 // loadPageSpy(`${json.Result.VName}-${json.Result.LoginName}`)
})) startTokenInterval()
setStorage(KEY_USER_ID, json.Result.LMI_SN)
setStorage(KEY_TRAVEL_AGENCY_ID, json.Result.LMI_VEI_SN)
setStorage(KEY_USER_NAME, json.Result.LoginName)
// loadPageSpy(`${json.Result.VName}-${json.Result.LoginName}`)
// this.startTokenInterval()
} else {
throw new Error(json.errmsg + ': ' + json.errcode)
}
})
}, },
logout: () => { logout: () => {
const { tokenInterval } = get()
const { clearStorage } = usingStorage() const { clearStorage } = usingStorage()
clearStorage() clearStorage()
clearInterval(tokenInterval)
set(() => ({ set(() => ({
loginUser: { loginUser: {
token: '',
timeout: true
}, },
loginStatus: 0 loginStatus: 0,
tokenInterval: null,
tokenTimeout: true
})) }))
}, },
fetchUserDetail: () => {
const { loginUser } = get()
const fetchUrl = prepareUrl(HT_HOST + '/service-CooperateSOA/GetLinkManInfo')
.append('token', loginUser.token)
.build();
return fetchJSON(fetchUrl)
.then(json => {
if (json.errcode == 0) {
set((state) => ({
loginUser: {
...state.loginUser,
userId: json.Result.LMI_SN,
username: json.Result.LoginName,
travelAgencyId: json.Result.LMI_VEI_SN,
travelAgencyName: json.Result.VName,
telephone: json.Result.LkPhone,
emailAddress: json.Result.LMI_listmail,
cityId: json.Result.citysn,
}
}))
// loadPageSpy(`${json.Result.VName}-${json.Result.LoginName}`)
// this.startTokenInterval()
return loginUser
} else {
throw new Error(json.errmsg + ': ' + json.errcode)
}
});
},
startTokenInterval: () => { startTokenInterval: () => {
const { loginUser } = get() const { loginTimeout } = get()
async function fetchLastRequet() {
const fetchUrl = prepareUrl(HT_HOST + '/service-CooperateSOA/GetLastReqDate')
.append('token', loginUser.token)
.build();
const json = await fetchJSON(fetchUrl)
if (json.errcode == 0 && isNotEmpty(json.result)) {
return json.result.LastReqDate;
} else {
return 0;
}
}
async function checkTokenTimeout() { async function checkTokenTimeout() {
const lastRequest = await fetchLastRequet(); const { LastReqDate } = await fetchLastRequet()
const lastReqDate = new Date(lastRequest); const lastReqDate = new Date(LastReqDate)
const now = new Date(); const now = new Date()
const diffTime = now.getTime() - lastReqDate.getTime(); const diffTime = now.getTime() - lastReqDate.getTime()
const diffHours = diffTime/1000/60/60; const diffHours = diffTime/1000/60//60
if (diffHours > 4) { if (diffHours > 1) {
authStore.logout(); loginTimeout()
} }
} }
const interval = setInterval(() => checkTokenTimeout(), 1000*60*20) const interval = setInterval(() => checkTokenTimeout(), 1000)//*60)//*20)
set(() => ({ set(() => ({
tokenInterval: interval tokenInterval: interval
})) }))
}, },
loginTimeout: () => {
const { tokenInterval } = get()
// TODO: 这里没有清理 token刷新后可以正常使用系统
clearInterval(tokenInterval)
set(() => ({
tokenTimeout: true
}))
},
changeUserPassword: (password, newPassword) => { changeUserPassword: (password, newPassword) => {
const { loginUser } = get() const { userId } = usingStorage()
const formData = new FormData(); const formData = new FormData();
formData.append('UserID', loginUser.userId); formData.append('UserID', userId);
formData.append('Password', password); formData.append('Password', password);
formData.append('NewPassword', newPassword); formData.append('NewPassword', newPassword);
formData.append('token', loginUser.token);
const postUrl = HT_HOST + '/service-CooperateSOA/SetPassword'; const postUrl = HT_HOST + '/service-CooperateSOA/SetPassword';
return postForm(postUrl, formData) return postForm(postUrl, formData)
@ -195,6 +157,7 @@ const useAuthStore = create((set, get) => ({
export default useAuthStore export default useAuthStore
export class Auth { export class Auth {
// TODO: 等待所有获取用户信息修改完后删除
login = { login = {
token: '', token: '',
userId: 0, // LMI_SN userId: 0, // LMI_SN

@ -23,15 +23,15 @@ const { Title } = Typography;
function App() { function App() {
const { t, i18n } = useTranslation(); const { t, i18n } = useTranslation();
const [password, setPassword] = useState(''); const [password, setPassword] = useState('')
const { notification } = AntApp.useApp();
const [loginUser, validateUserPassword] = useAuthStore((state) => [state.loginUser, state.validateUserPassword]) const [validateUserPassword, tokenTimeout] = useAuthStore(
(state) => [state.validateUserPassword, state.tokenTimeout])
const { loginToken, username } = usingStorage() const { loginToken, userDetail } = usingStorage()
const noticeUnRead = useNoticeStore((state) => state.noticeUnRead) const noticeUnRead = useNoticeStore((state) => state.noticeUnRead)
const href = useHref(); const href = useHref()
const navigate = useNavigate() const navigate = useNavigate()
const location = useLocation() const location = useLocation()
@ -53,16 +53,12 @@ function App() {
}, [location]); }, [location]);
const onSubmit = () => { const onSubmit = () => {
validateUserPassword(username, password) validateUserPassword(userDetail?.username, password)
.catch(ex => { .catch(ex => {
notification.error({ console.error(ex)
message: `Notification`, alert(t('Validation.LoginFailed'))
description: ex.message, })
placement: 'top', setPassword('')
duration: 4,
});
});
setPassword('');
}; };
const splitPath = href.split('/'); const splitPath = href.split('/');
@ -95,17 +91,17 @@ function App() {
closable={false} closable={false}
maskClosable={false} maskClosable={false}
footer={null} footer={null}
open={loginUser.timeout} open={tokenTimeout}
> >
<Title level={3}>{t('LoginTimeout')}</Title> <Title level={3}>{t('LoginTimeout')}</Title>
<div>{t('LoginTimeoutTip')}</div> <div>{t('LoginTimeoutTip')}</div>
<Space direction='horizontal'> <Space direction='horizontal'>
<Input.Password value={password} <Input.Password value={password}
onChange={(e) => setPassword(e.target.value)} onChange={(e) => setPassword(e.target.value)}
onPressEnter={() => onSubmit()} onPressEnter={onSubmit}
addonBefore={loginUser.username} /> addonBefore={userDetail?.username} />
<Button <Button
onClick={() => onSubmit()} onClick={onSubmit}
>{t('Submit')}</Button></Space> >{t('Submit')}</Button></Space>
</Modal> </Modal>
@ -142,7 +138,7 @@ function App() {
</Col> </Col>
<Col span={4}> <Col span={4}>
<Title level={3} style={{ color: 'white', marginBottom: '0', display: 'flex', justifyContent: 'end' }}> <Title level={3} style={{ color: 'white', marginBottom: '0', display: 'flex', justifyContent: 'end' }}>
{loginUser.travelAgencyName} {userDetail?.travelAgencyName}
</Title> </Title>
</Col> </Col>
<Col span={2}> <Col span={2}>
@ -162,7 +158,7 @@ function App() {
> >
<a onClick={e => e.preventDefault()}> <a onClick={e => e.preventDefault()}>
<Space> <Space>
{username} {userDetail?.username}
<DownOutlined /> <DownOutlined />
</Space> </Space>
</a> </a>

@ -24,6 +24,7 @@ function Login() {
const onFinish = (values) => { const onFinish = (values) => {
validateUserPassword(values.username, values.password) validateUserPassword(values.username, values.password)
.catch(ex => { .catch(ex => {
console.error(ex)
notification.error({ notification.error({
message: t('Validation.Title'), message: t('Validation.Title'),
description: t('Validation.LoginFailed'), description: t('Validation.LoginFailed'),

@ -1,40 +1,43 @@
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom"
import { Button, Space, Form, Input, Row, Typography, App } from 'antd'; import { Button, Space, Form, Input, Row, Typography, App } from 'antd'
import { useStore } from '@/stores/StoreContext.js'; import { useTranslation } from 'react-i18next'
import useAuthStore from '@/stores/Auth'
const { Title } = Typography; const { Title } = Typography
function ChangePassword() { function ChangePassword() {
const navigate = useNavigate(); const { t } = useTranslation()
const { authStore } = useStore(); const navigate = useNavigate()
const { notification } = App.useApp(); const changeUserPassword = useAuthStore((state) => state.changeUserPassword)
const [form] = Form.useForm(); const { notification } = App.useApp()
const [form] = Form.useForm()
const onFinish = (values) => { const onFinish = (values) => {
authStore.changeUserPassword(values.currentPassword, values.newPassword) changeUserPassword(values.currentPassword, values.newPassword)
.then(() => { .then(() => {
notification.success({ notification.success({
message: `Notification`, message: t('Validation.Title'),
description: 'Your password has been successfully updated.', description: t('account:Validation.Success'),
placement: 'top', placement: 'top',
duration: 4, duration: 4,
}); })
form.resetFields()
}) })
.catch(() => { .catch(() => {
notification.error({ notification.error({
message: `Notification`, message: t('Validation.Title'),
description: 'Failed to change password. Please try again.', description: t('account:Validation.Fail'),
placement: 'top', placement: 'top',
duration: 4, duration: 4,
}); })
}); })
}; }
const onFinishFailed = (errorInfo) => { const onFinishFailed = (errorInfo) => {
console.log('Failed:', errorInfo); console.log('Failed:', errorInfo)
// form.resetFields(); // form.resetFields()
}; }
return ( return (
<> <>
@ -51,38 +54,38 @@ function ChangePassword() {
onFinishFailed={onFinishFailed} onFinishFailed={onFinishFailed}
autoComplete="off" autoComplete="off"
> >
<Form.Item><Title level={2}>Change your password</Title></Form.Item> <Form.Item><Title level={2}>{t('ChangePassword')}</Title></Form.Item>
<Form.Item <Form.Item
label="Current password" label={t('account:CurrentPassword')}
name="currentPassword" name="currentPassword"
rules={[ rules={[
{ {
required: true, required: true,
message: 'Please input your password!', message: t('account:Validation.CurrentPassword'),
}, },
]} ]}
> >
<Input.Password /> <Input.Password />
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label="New password" label={t('account:NewPassword')}
name="newPassword" name="newPassword"
rules={[ rules={[
{ {
required: true, required: true,
message: 'Please input your password!', message: t('account:Validation.NewPassword'),
}, },
]} ]}
> >
<Input.Password /> <Input.Password />
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label="Reenter password" label={t('account:ReenterPassword')}
name="reenterPassword" name="reenterPassword"
rules={[ rules={[
{ {
required: true, required: true,
message: 'Please reenter your password!', message: t('account:Validation.ReenterPassword'),
}, },
]} ]}
> >
@ -91,17 +94,17 @@ function ChangePassword() {
<Form.Item> <Form.Item>
<Space size="middle"> <Space size="middle">
<Button type="primary" htmlType="submit"> <Button type="primary" htmlType="submit">
Save {t('Submit')}
</Button> </Button>
<Button onClick={() => navigate('/reservation/newest')}> <Button onClick={() => navigate('/reservation/newest')}>
Cancel {t('Cancel')}
</Button> </Button>
</Space> </Space>
</Form.Item> </Form.Item>
</Form> </Form>
</Row> </Row>
</> </>
); )
} }
export default ChangePassword; export default ChangePassword
Loading…
Cancel
Save