From 63a32f54122d745872626b42361e7051fd8c04da Mon Sep 17 00:00:00 2001 From: Jimmy Liow Date: Tue, 11 Jun 2024 14:50:53 +0800 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20AuthStore=20=E5=AE=8C=E6=88=90?= =?UTF-8?q?=E6=89=80=E6=9C=89=E6=96=B9=E6=B3=95=E8=BD=AC=E6=8D=A2=E6=88=90?= =?UTF-8?q?=20zustand?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/usingStorage.js | 2 +- src/stores/Auth.js | 183 +++++++++++---------------- src/views/App.jsx | 36 +++--- src/views/Login.jsx | 1 + src/views/account/ChangePassword.jsx | 42 +++--- 5 files changed, 113 insertions(+), 151 deletions(-) diff --git a/src/hooks/usingStorage.js b/src/hooks/usingStorage.js index fd08c70..d30f360 100644 --- a/src/hooks/usingStorage.js +++ b/src/hooks/usingStorage.js @@ -6,7 +6,7 @@ const persistObject = {} * G-JSON:LOGIN_USER -> loginUser = { username: 'test-username' } */ export function usingStorage() { - // TODO: rename storageUse()???webStorage()??? + const getStorage = () => { if (import.meta.env.DEV && window.localStorage) { return window.localStorage diff --git a/src/stores/Auth.js b/src/stores/Auth.js index d19beb7..9314175 100644 --- a/src/stores/Auth.js +++ b/src/stores/Auth.js @@ -1,33 +1,51 @@ -import { makeAutoObservable, runInAction } from "mobx"; import { create } from 'zustand' import { appendRequestParams, fetchJSON, postForm } from '@/utils/request' import { HT_HOST } from "@/config" -import { isNotEmpty, prepareUrl } from '@/utils/commons' import { loadPageSpy } from '@/pageSpy' import { usingStorage } from '@/hooks/usingStorage' - const KEY_LOGIN_TOKEN = 'G-STR:LOGIN_TOKEN' const KEY_TRAVEL_AGENCY_ID = 'G-INT:TRAVEL_AGENCY_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) => ({ tokenInterval: null, + tokenTimeout: false, + loginStatus: 0, loginUser: { token: '', - userId: 0, // LMI_SN - username: '0', - travelAgencyId: 0, // VEI_SN - travelAgencyName: '', telephone: '', emailAddress: '', cityId: 0, - timeout: false, permissionList: [], }, @@ -48,137 +66,81 @@ const useAuthStore = create((set, get) => ({ }, validateUserPassword: async (usr, pwd) => { + const { startTokenInterval } = get() const { setStorage } = usingStorage() - const formData = new FormData() - 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 { token: loginToken } = await fetchLoginToken(usr, pwd) - const fetchUrl = prepareUrl(HT_HOST + '/service-CooperateSOA/GetLinkManInfo').build() + const userDetail = await fetchUserDetail(loginToken) - return fetchJSON(fetchUrl) - .then(json => { - if (json.errcode == 0) { - set(() => ({ - loginUser: { - token: loginToken, - timeout: false, - 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, - }, - loginStatus: 302 - })) - - 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) - } - }) + set(() => ({ + loginUser: { + telephone: userDetail.LkPhone, + emailAddress: userDetail.LMI_listmail, + cityId: userDetail.citysn, + }, + tokenTimeout: false, + loginStatus: 302 + })) + + setStorage(KEY_LOGIN_TOKEN, loginToken) + setStorage(KEY_USER_ID, userDetail.LMI_SN) + setStorage(KEY_TRAVEL_AGENCY_ID, userDetail.LMI_VEI_SN) + setStorage(KEY_USER_DETAIL, {username: userDetail.LoginName, travelAgencyName: userDetail.VName}) + appendRequestParams('token', loginToken) + // loadPageSpy(`${json.Result.VName}-${json.Result.LoginName}`) + startTokenInterval() }, logout: () => { + const { tokenInterval } = get() const { clearStorage } = usingStorage() clearStorage() + clearInterval(tokenInterval) set(() => ({ 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: () => { - const { loginUser } = 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; - } - } + const { loginTimeout } = get() async function checkTokenTimeout() { - const lastRequest = await fetchLastRequet(); - const lastReqDate = new Date(lastRequest); - const now = new Date(); - const diffTime = now.getTime() - lastReqDate.getTime(); - const diffHours = diffTime/1000/60/60; - if (diffHours > 4) { - authStore.logout(); + const { LastReqDate } = await fetchLastRequet() + const lastReqDate = new Date(LastReqDate) + const now = new Date() + const diffTime = now.getTime() - lastReqDate.getTime() + const diffHours = diffTime/1000/60//60 + if (diffHours > 1) { + loginTimeout() } } - const interval = setInterval(() => checkTokenTimeout(), 1000*60*20) + const interval = setInterval(() => checkTokenTimeout(), 1000)//*60)//*20) set(() => ({ tokenInterval: interval })) }, + loginTimeout: () => { + const { tokenInterval } = get() + // TODO: 这里没有清理 token,刷新后可以正常使用系统 + clearInterval(tokenInterval) + set(() => ({ + tokenTimeout: true + })) + }, + changeUserPassword: (password, newPassword) => { - const { loginUser } = get() + const { userId } = usingStorage() const formData = new FormData(); - formData.append('UserID', loginUser.userId); + formData.append('UserID', userId); formData.append('Password', password); formData.append('NewPassword', newPassword); - formData.append('token', loginUser.token); const postUrl = HT_HOST + '/service-CooperateSOA/SetPassword'; return postForm(postUrl, formData) @@ -195,6 +157,7 @@ const useAuthStore = create((set, get) => ({ export default useAuthStore export class Auth { + // TODO: 等待所有获取用户信息修改完后删除 login = { token: '', userId: 0, // LMI_SN diff --git a/src/views/App.jsx b/src/views/App.jsx index f68f480..2556d2b 100644 --- a/src/views/App.jsx +++ b/src/views/App.jsx @@ -23,15 +23,15 @@ const { Title } = Typography; function App() { const { t, i18n } = useTranslation(); - const [password, setPassword] = useState(''); - const { notification } = AntApp.useApp(); + const [password, setPassword] = useState('') - 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 href = useHref(); + const href = useHref() const navigate = useNavigate() const location = useLocation() @@ -53,16 +53,12 @@ function App() { }, [location]); const onSubmit = () => { - validateUserPassword(username, password) + validateUserPassword(userDetail?.username, password) .catch(ex => { - notification.error({ - message: `Notification`, - description: ex.message, - placement: 'top', - duration: 4, - }); - }); - setPassword(''); + console.error(ex) + alert(t('Validation.LoginFailed')) + }) + setPassword('') }; const splitPath = href.split('/'); @@ -95,17 +91,17 @@ function App() { closable={false} maskClosable={false} footer={null} - open={loginUser.timeout} + open={tokenTimeout} > {t('LoginTimeout')}
{t('LoginTimeoutTip')}
setPassword(e.target.value)} - onPressEnter={() => onSubmit()} - addonBefore={loginUser.username} /> + onPressEnter={onSubmit} + addonBefore={userDetail?.username} /> @@ -142,7 +138,7 @@ function App() { - {loginUser.travelAgencyName} + {userDetail?.travelAgencyName} @@ -162,7 +158,7 @@ function App() { > e.preventDefault()}> - {username} + {userDetail?.username} diff --git a/src/views/Login.jsx b/src/views/Login.jsx index 7918d1b..b973b96 100644 --- a/src/views/Login.jsx +++ b/src/views/Login.jsx @@ -24,6 +24,7 @@ function Login() { const onFinish = (values) => { validateUserPassword(values.username, values.password) .catch(ex => { + console.error(ex) notification.error({ message: t('Validation.Title'), description: t('Validation.LoginFailed'), diff --git a/src/views/account/ChangePassword.jsx b/src/views/account/ChangePassword.jsx index 14f3c4b..1cf1eb1 100644 --- a/src/views/account/ChangePassword.jsx +++ b/src/views/account/ChangePassword.jsx @@ -1,25 +1,27 @@ -import { useNavigate } from "react-router-dom"; -import { Button, Space, Form, Input, Row, Typography, App } from 'antd'; -import { useStore } from '@/stores/StoreContext.js'; +import { useNavigate } from "react-router-dom" +import { Button, Space, Form, Input, Row, Typography, App } from 'antd' +import useAuthStore from '@/stores/Auth' -const { Title } = Typography; +const { Title } = Typography function ChangePassword() { - const navigate = useNavigate(); - const { authStore } = useStore(); - const { notification } = App.useApp(); - const [form] = Form.useForm(); + const navigate = useNavigate() + const [changeUserPassword] = useAuthStore( + (state) => [state.changeUserPassword]) + const { notification } = App.useApp() + const [form] = Form.useForm() const onFinish = (values) => { - authStore.changeUserPassword(values.currentPassword, values.newPassword) + changeUserPassword(values.currentPassword, values.newPassword) .then(() => { notification.success({ message: `Notification`, description: 'Your password has been successfully updated.', placement: 'top', duration: 4, - }); + }) + form.resetFields() }) .catch(() => { notification.error({ @@ -27,18 +29,18 @@ function ChangePassword() { description: 'Failed to change password. Please try again.', placement: 'top', duration: 4, - }); - }); - }; - + }) + }) + } + const onFinishFailed = (errorInfo) => { - console.log('Failed:', errorInfo); - // form.resetFields(); - }; + console.log('Failed:', errorInfo) + // form.resetFields() + } return ( <> - +
- ); + ) } -export default ChangePassword; \ No newline at end of file +export default ChangePassword \ No newline at end of file From 8d3649da9deaba8f267d3f16f0cbda40d41d6f30 Mon Sep 17 00:00:00 2001 From: Jimmy Liow Date: Tue, 11 Jun 2024 15:51:09 +0800 Subject: [PATCH 2/2] =?UTF-8?q?feat:=20=E5=9B=BD=E9=99=85=E5=8C=96?= =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=AF=86=E7=A0=81=E7=95=8C=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/locales/en/account.json | 12 +++++++++++ public/locales/zh/account.json | 12 +++++++++++ public/locales/zh/common.json | 4 ---- src/i18n/index.js | 2 +- src/views/account/ChangePassword.jsx | 31 ++++++++++++++-------------- 5 files changed, 41 insertions(+), 20 deletions(-) create mode 100644 public/locales/en/account.json create mode 100644 public/locales/zh/account.json diff --git a/public/locales/en/account.json b/public/locales/en/account.json new file mode 100644 index 0000000..7abb5cf --- /dev/null +++ b/public/locales/en/account.json @@ -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." + } +} \ No newline at end of file diff --git a/public/locales/zh/account.json b/public/locales/zh/account.json new file mode 100644 index 0000000..a7caf37 --- /dev/null +++ b/public/locales/zh/account.json @@ -0,0 +1,12 @@ +{ + "CurrentPassword": "当前密码", + "NewPassword": "新密码", + "ReenterPassword": "重复输入密码", + "Validation": { + "Success": "密码更新成功", + "Fail": "密码更新失败", + "CurrentPassword": "请输入密码。", + "NewPassword": "请输入新密码。", + "ReenterPassword": "请重复输入密码。" + } +} \ No newline at end of file diff --git a/public/locales/zh/common.json b/public/locales/zh/common.json index d1f3789..7511da4 100644 --- a/public/locales/zh/common.json +++ b/public/locales/zh/common.json @@ -51,10 +51,6 @@ "Notice": "通知", "Report": "质量评分" }, - "Notification": { - "Title": "温馨提示", - "LoginFailed": "密码错误,登陆失败。" - }, "Validation": { "Title": "温馨提示", "LoginFailed": "密码错误,登陆失败。", diff --git a/src/i18n/index.js b/src/i18n/index.js index b787ea2..9efd3bd 100644 --- a/src/i18n/index.js +++ b/src/i18n/index.js @@ -17,7 +17,7 @@ i18n backend: { loadPath: '/locales/{{lng}}/{{ns}}.json', }, - ns: ['common', 'group', 'vendor'], + ns: ['common', 'group', 'vendor', 'account'], defaultNS: 'common', detection: { // convertDetectedLanguage: 'Iso15897', diff --git a/src/views/account/ChangePassword.jsx b/src/views/account/ChangePassword.jsx index 1cf1eb1..11e63e5 100644 --- a/src/views/account/ChangePassword.jsx +++ b/src/views/account/ChangePassword.jsx @@ -1,14 +1,15 @@ import { useNavigate } from "react-router-dom" import { Button, Space, Form, Input, Row, Typography, App } from 'antd' +import { useTranslation } from 'react-i18next' import useAuthStore from '@/stores/Auth' const { Title } = Typography function ChangePassword() { + const { t } = useTranslation() const navigate = useNavigate() - const [changeUserPassword] = useAuthStore( - (state) => [state.changeUserPassword]) + const changeUserPassword = useAuthStore((state) => state.changeUserPassword) const { notification } = App.useApp() const [form] = Form.useForm() @@ -16,8 +17,8 @@ function ChangePassword() { changeUserPassword(values.currentPassword, values.newPassword) .then(() => { notification.success({ - message: `Notification`, - description: 'Your password has been successfully updated.', + message: t('Validation.Title'), + description: t('account:Validation.Success'), placement: 'top', duration: 4, }) @@ -25,8 +26,8 @@ function ChangePassword() { }) .catch(() => { notification.error({ - message: `Notification`, - description: 'Failed to change password. Please try again.', + message: t('Validation.Title'), + description: t('account:Validation.Fail'), placement: 'top', duration: 4, }) @@ -53,38 +54,38 @@ function ChangePassword() { onFinishFailed={onFinishFailed} autoComplete="off" > - Change your password + {t('ChangePassword')} @@ -93,10 +94,10 @@ function ChangePassword() {