Merge remote-tracking branch 'origin/main'

feature/price_manager
Lei OT 1 year ago
commit c7f29f4999

@ -50,5 +50,11 @@
"Feedback": "Feedback",
"Notice": "Notice",
"Report": "Report"
},
"Validation": {
"Title": "Notification",
"LoginFailed": "Incorrect password, Login failed.",
"UsernameIsEmpty": "Please input your username",
"PasswordIsEmpty": "Please input your password"
}
}

@ -20,7 +20,7 @@
"preview": "预览",
"Login": "登录",
"Username": "账户名",
"Username": "账",
"Password": "密码",
"ChangePassword": "修改密码",
@ -50,5 +50,15 @@
"Feedback": "反馈表",
"Notice": "通知",
"Report": "质量评分"
},
"Notification": {
"Title": "温馨提示",
"LoginFailed": "密码错误,登陆失败。"
},
"Validation": {
"Title": "温馨提示",
"LoginFailed": "密码错误,登陆失败。",
"UsernameIsEmpty": "请输入账号",
"PasswordIsEmpty": "请输入密码"
}
}

@ -44,7 +44,7 @@ const useAuthStore = create((set, get) => ({
},
valdateUserPassword: async (usr, pwd) => {
validateUserPassword: async (usr, pwd) => {
const formData = new FormData()
formData.append('username', usr)
formData.append('Password', pwd)
@ -183,124 +183,6 @@ const useAuthStore = create((set, get) => ({
export default useAuthStore
export class Auth {
constructor(root) {
makeAutoObservable(this, { rootStore: false });
this.root = root;
this.login.token = root.getSession(KEY_LOGIN_TOKEN);
this.login.userId = root.getSession(KEY_USER_ID);
this.login.travelAgencyId = root.getSession(KEY_TRAVEL_AGENCY_ID);
if (isNotEmpty(this.login.token)) {
appendRequestParams('token', this.login.token);
this.fetchUserDetail();
}
}
valdateUserPassword(usr, pwd) {
const formData = new FormData();
formData.append('username', usr);
formData.append('Password', pwd);
const postUrl = HT_HOST + '/service-CooperateSOA/Login';
return postForm(postUrl, formData)
.then(json => {
if (json.errcode == 0) {
runInAction(() => {
this.login.token = json.Result.token;
this.login.timeout = false;
});
this.root.putSession(KEY_LOGIN_TOKEN, json.Result.token);
appendRequestParams('token', json.Result.token);
return json.Result.WU_LMI_SN;
} else {
throw new Error(json.errmsg + ': ' + json.errcode);
}
});
}
fetchUserDetail() {
const fetchUrl = prepareUrl(HT_HOST + '/service-CooperateSOA/GetLinkManInfo')
.append('token', this.login.token)
.build();
return fetchJSON(fetchUrl)
.then(json => {
if (json.errcode == 0) {
runInAction(() => {
this.login.userId = json.Result.LMI_SN;
this.login.username = json.Result.LoginName;
this.login.travelAgencyId = json.Result.LMI_VEI_SN;
this.login.travelAgencyName = json.Result.VName;
this.login.telephone = json.Result.LkPhone;
this.login.emailAddress = json.Result.LMI_listmail;
this.login.cityId = json.Result.citysn;
this.root.putSession(KEY_TRAVEL_AGENCY_ID, this.login.travelAgencyId);
this.root.putSession(KEY_USER_ID, this.login.userId);
});
loadPageSpy(`${json.Result.VName}-${json.Result.LoginName}`)
this.startTokenInterval();
return this.login;
} else {
throw new Error(json.errmsg + ': ' + json.errcode);
}
});
}
startTokenInterval() {
const authStore = this;
async function fetchLastRequet() {
const fetchUrl = prepareUrl(HT_HOST + '/service-CooperateSOA/GetLastReqDate')
.append('token', authStore.login.token)
.build();
const json = await fetchJSON(fetchUrl)
if (json.errcode == 0 && isNotEmpty(json.result)) {
return json.result.LastReqDate;
} else {
return 0;
}
}
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();
}
}
this.tokenInterval = setInterval(() => checkTokenTimeout(), 1000*60*20);
}
logout() {
this.root.clearSession();
runInAction(() => {
this.login.timeout = true;
});
}
tokenInterval = null;
changeUserPassword(password, newPassword) {
const formData = new FormData();
formData.append('UserID', this.login.userId);
formData.append('Password', password);
formData.append('NewPassword', newPassword);
formData.append('token', this.login.token);
const postUrl = HT_HOST + '/service-CooperateSOA/SetPassword';
return postForm(postUrl, formData)
.then(json => {
if (json.errcode == 0) {
return json;
} else {
throw new Error(json.errmsg + ': ' + json.errcode);
}
});
}
login = {
token: '',
userId: 0, // LMI_SN
@ -313,5 +195,3 @@ export class Auth {
timeout: false
}
}
// export Auth;

@ -28,7 +28,7 @@ const useReservationStore = create((set, get) => ({
confirmationList: [
],
fetchReservationList: (travelAgencyId, current, status=null) => {
fetchReservationList: (travelAgencyId, formVal, current=1) => {
const fromDate = null //this.arrivalDateRange.length == 0 ? null : this.arrivalDateRange[0].format('YYYY-MM-DD');
const thruDate = null //this.arrivalDateRange.length == 0 ? null : this.arrivalDateRange[1].format('YYYY-MM-DD');
// this.reservationPage.current = current;
@ -36,34 +36,18 @@ const useReservationStore = create((set, get) => ({
const totalNum = 0//current == 1 ? 0 : this.reservationPage.total;
const fetchUrl = prepareUrl(HT_HOST + '/service-cusservice/GetPlanSearchList')
.append('VEI_SN', travelAgencyId)
.append('GroupNo', '')//this.referenceNo)
.append('DateStart', '')//fromDate)
.append('DateEnd', '')//thruDate)
.append('GroupNo', formVal.referenceNo)
.append('DateStart', formVal.fromDate)
.append('DateEnd', formVal.thruDate)
.append('NotConfirm', '')//status)
.append('TotalNum', totalNum)
.append('PageSize', 5)//this.reservationPage.size)
.append('PageIndex', 1)//this.reservationPage.current)
.append('PageIndex', current)
.build();
return fetchJSON(fetchUrl)
.then(json => {
if (json.errcode == 0) {
// runInAction(() => {
// this.reservationList = (json?.Result??[]).map((data, index) => {
// return {
// key: data.vas_gri_sn,
// reservationId: data.vas_gri_sn,
// referenceNumber: data.GriName,
// arrivalDate: data.GetGDate,
// pax: data.PersonNum,
// status: data.GState,
// reservationDate: data.SendDate,
// guide: data.Guide
// }
// });
// this.reservationPage.total = (json?.Result??[{RsTotal: 0}])[0].RsTotal;
// });
const mapReservationList = (json?.Result??[]).map((data, index) => {
return {
key: data.vas_gri_sn,

@ -1,15 +1,11 @@
import { Outlet, Link, useHref, useNavigate, useLocation, NavLink } from "react-router-dom";
import { Outlet, Link, useHref, useNavigate, useLocation, NavLink } from 'react-router-dom';
import { useEffect, useState } from 'react';
import { observer } from "mobx-react";
import { toJS } from "mobx";
import { Layout, Menu, ConfigProvider, theme, Dropdown, Space, Row, Col, Badge, Typography, Modal, Input, Button, App as AntApp } from "antd";
import { DownOutlined } from "@ant-design/icons";
import "antd/dist/reset.css";
import AppLogo from "@/assets/logo-gh.png";
import { isEmpty } from "@/utils/commons";
import { useStore } from "@/stores/StoreContext.js";
import * as config from "@/config";
import Language from "../i18n/LanguageSwitcher";
import { Layout, Menu, ConfigProvider, theme, Dropdown, Space, Row, Col, Badge, Typography, Modal, Input, Button, App as AntApp } from 'antd';
import { DownOutlined } from '@ant-design/icons';
import 'antd/dist/reset.css';
import AppLogo from '@/assets/logo-gh.png';
import { isEmpty } from '@/utils/commons';
import Language from '../i18n/LanguageSwitcher';
import { useTranslation } from 'react-i18next';
import zhLocale from 'antd/locale/zh_CN';
import enLocale from 'antd/locale/en_US';
@ -25,12 +21,10 @@ function App() {
const { t, i18n } = useTranslation();
const [password, setPassword] = useState('');
const { authStore } = useStore();
const { notification } = AntApp.useApp();
const loginUser = useAuthStore((state) => state.loginUser)
// const login = toJS(authStore.login);
const noticeUnRead = useNoticeStore((state) => state.noticeUnRead);
const href = useHref();
const loginToken = loginUser.token;
@ -71,8 +65,8 @@ function App() {
setPassword('');
};
const splitPath = href.split("/");
let defaultPath = "reservation";
const splitPath = href.split('/');
let defaultPath = 'reservation';
if (splitPath.length > 1) {
defaultPath = splitPath[1];
@ -90,7 +84,7 @@ function App() {
<ConfigProvider locale={antdLng}
theme={{
token: {
colorPrimary: "#00b96b",
colorPrimary: '#00b96b',
},
algorithm: theme.defaultAlgorithm,
}}>
@ -104,7 +98,7 @@ function App() {
>
<Title level={3}>{t('LoginTimeout')}</Title>
<div>{t('LoginTimeoutTip')}</div>
<Space direction="horizontal">
<Space direction='horizontal'>
<Input.Password value={password}
onChange={(e) => setPassword(e.target.value)}
onPressEnter={() => onSubmit()}
@ -116,29 +110,29 @@ function App() {
</Modal>
<Layout
style={{
minHeight: "100vh",
minHeight: '100vh',
}}>
<Header className="header" style={{ position: "sticky", top: 0, zIndex: 1, width: "100%" }}>
<Row gutter={{ md: 24 }} justify="end" align="middle">
<Header className='header' style={{ position: 'sticky', top: 0, zIndex: 1, width: '100%' }}>
<Row gutter={{ md: 24 }} justify='end' align='middle'>
<Col span={16}>
<NavLink to="/">
<img src={AppLogo} className="logo" alt="App logo" />
<NavLink to='/'>
<img src={AppLogo} className='logo' alt='App logo' />
</NavLink>
<Menu
theme="dark"
mode="horizontal"
theme='dark'
mode='horizontal'
selectedKeys={[defaultPath]}
items={[
{ key: "reservation", label: <Link to="/reservation/newest">{t('menu.Reservation')}</Link> },
{ key: "invoice", label: <Link to="/invoice">{t('menu.Invoice')}</Link> },
{ key: "feedback", label: <Link to="/feedback">{t('menu.Feedback')}</Link> },
{ key: "report", label: <Link to="/report">{t('menu.Report')}</Link> },
{ key: 'reservation', label: <Link to='/reservation/newest'>{t('menu.Reservation')}</Link> },
{ key: 'invoice', label: <Link to='/invoice'>{t('menu.Invoice')}</Link> },
{ key: 'feedback', label: <Link to='/feedback'>{t('menu.Feedback')}</Link> },
{ key: 'report', label: <Link to='/report'>{t('menu.Report')}</Link> },
{
key: "notice",
key: 'notice',
label: (
<Link to="/notice">
<Link to='/notice'>
{t('menu.Notice')}
{noticeUnRead ? <Badge dot /> : ""}
{noticeUnRead ? <Badge dot /> : ''}
</Link>
),
},
@ -146,7 +140,7 @@ function App() {
/>
</Col>
<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}
</Title>
</Col>
@ -194,4 +188,4 @@ function App() {
);
}
export default observer(App);
export default App

@ -1,125 +1,109 @@
import { useNavigate, useLocation } from "react-router-dom";
import { useNavigate, useLocation } from 'react-router-dom';
import { useEffect } from 'react';
import { Button, Checkbox, Form, Input, Row, App } from 'antd';
import { useStore } from '@/stores/StoreContext.js';
import { useTranslation } from 'react-i18next';
import useAuthStore from '@/stores/Auth'
import useNoticeStore from '@/stores/Notice';
function Login() {
const { t, i18n } = useTranslation();
const [validateUserPassword, loginStatus, logout] =
useAuthStore((state) => [state.validateUserPassword, state.loginStatus])
const getBulletinUnReadCount = useNoticeStore((state) => state.getBulletinUnReadCount)
const { authStore } = useStore();
const [valdateUserPassword, fetchUserDetail, loginStatus] =
useAuthStore((state) => [state.valdateUserPassword, state.fetchUserDetail, state.loginStatus])
const { t, i18n } = useTranslation()
const { notification } = App.useApp();
const navigate = useNavigate()
const location = useLocation()
const [form] = Form.useForm()
const getBulletinUnReadCount = useNoticeStore((state) => state.getBulletinUnReadCount);
useEffect (() => {
if (location.search === '?out') {
authStore.logout();
navigate('/login');
logout();
navigate('/login')
}
return () => {
// unmount...
};
}, []);
}, [])
useEffect (() => {
if (loginStatus === 302) {
navigate("/reservation/newest")
navigate('/reservation/newest')
}
}, [loginStatus]);
}, [loginStatus])
const onFinish = (values) => {
valdateUserPassword(values.username, values.password)
.then((userId) => {
// noticeStore.getBulletinUnReadCount(userId);
console.info('valdateUserPassword')
//
})
validateUserPassword(values.username, values.password)
.catch(ex => {
notification.error({
message: `Notification`,
description: 'Login failed. Incorrect username or password.',
message: t('Validation.Title'),
description: t('Validation.LoginFailed'),
placement: 'top',
duration: 4,
});
});
};
})
})
}
const onFinishFailed = (errorInfo) => {
console.log('Failed:', errorInfo);
}
console.info('loginStatus: ' + loginStatus)
if (loginStatus === 302) {
} else {
return (
<Row justify="center" align="middle" style={{ minHeight: 500 }}>
<Form
name="basic"
// layout="vertical"
form={form}
size="large"
labelCol={{
span: 8,
}}
return (
<Row justify='center' align='middle' style={{ minHeight: 500 }}>
<Form
name='basic'
form={form}
size='large'
labelCol={{
span: 8,
}}
wrapperCol={{
span: 16,
}}
style={{
maxWidth: 600,
}}
initialValues={{
remember: true,
}}
onFinish={onFinish}
onFinishFailed={onFinishFailed}
autoComplete='off'
>
<Form.Item
label={t('Username')}
name='username'
rules={[
{
required: true,
message: t('Validation.UsernameIsEmpty'),
},
]}
>
<Input />
</Form.Item>
<Form.Item
label={t('Password')}
name='password'
rules={[
{
required: true,
message: t('Validation.PasswordIsEmpty'),
},
]}
>
<Input.Password />
</Form.Item>
<Form.Item
wrapperCol={{
offset: 8,
span: 16,
}}
style={{
maxWidth: 600,
}}
initialValues={{
remember: true,
}}
onFinish={onFinish}
onFinishFailed={onFinishFailed}
autoComplete="off"
>
<Form.Item
label={t("Username")}
name="username"
rules={[
{
required: true,
message: 'Please input your username!',
},
]}
>
<Input />
</Form.Item>
<Form.Item
label={t("Password")}
name="password"
rules={[
{
required: true,
message: 'Please input your password!',
},
]}
>
<Input.Password />
</Form.Item>
<Form.Item
wrapperCol={{
offset: 8,
span: 16,
}}
>
<Button type="primary" htmlType="submit" style={{width: "100%"}}>
{t('Login')}
</Button>
</Form.Item>
</Form>
</Row>
);
}
<Button type='primary' htmlType='submit' style={{width: '100%'}}>
{t('Login')}
</Button>
</Form.Item>
</Form>
</Row>
)
}
export default Login;
export default Login

@ -113,10 +113,10 @@ function Newest() {
const { reservationStore } = useStore();
const loginUser = useAuthStore((state) => state.loginUser)
const [fetchAllGuideList, fetchReservationList] =
useReservationStore((state) => [state.fetchAllGuideList, state.fetchReservationList])
const [fetchAllGuideList, fetchReservationList, reservationList] =
useReservationStore((state) => [state.fetchAllGuideList, state.fetchReservationList, state.reservationList])
const { reservationList, reservationPage, referenceNo, arrivalDateRange, cityList } = reservationStore;
const { reservationPage, cityList } = reservationStore;
const { notification } = App.useApp();
useEffect (() => {
@ -170,7 +170,7 @@ function Newest() {
//
const onSearchClick = (current=1, status=null) => {
setDataLoading(true);
setDataLoading(true)
fetchReservationList(loginUser.travelAgencyId, current, status)
.catch(ex => {
notification.error({
@ -181,8 +181,8 @@ function Newest() {
});
})
.finally(() => {
setDataLoading(false);
});
setDataLoading(false)
})
}
return (
@ -231,33 +231,21 @@ function Newest() {
},
}}
onSubmit={(err, formVal, filedsVal) => {
const _ff = objectMapper(formVal, { startdate: 'DateStart', enddate: 'DateEnd', referenceNo: 'GroupNo' })
console.log('from form', formVal, 'mappered for search', _ff);
setDataLoading(true)
fetchReservationList(loginUser.travelAgencyId, formVal)
.catch(ex => {
notification.error({
message: `Notification`,
description: ex.message,
placement: 'top',
duration: 4,
});
})
.finally(() => {
setDataLoading(false)
})
}}
/>
<Row gutter={16}>
<Col md={24} lg={6} xxl={4}>
<Input placeholder={t('group:RefNo')} value={referenceNo} onChange={(e) => { reservationStore.updatePropertyValue('referenceNo', e.target.value)} } />
</Col>
<Col md={24} lg={8} xxl={6}>
<Space direction="horizontal">
{t('group:ArrivalDate')}
<DatePicker.RangePicker
allowClear={true}
inputReadOnly={true}
presets={presets}
defaultValue={toJS(arrivalDateRange)}
placeholder={['From', 'Thru']}
onChange={(dateRange) => {
reservationStore.updatePropertyValue('arrivalDateRange', dateRange == null ? [] : dateRange)
}}
/>
</Space>
</Col>
<Col md={24} lg={4} xxl={4}>
<Button type='primary' onClick={() => onSearchClick()} loading={dataLoading}>{t('Search')}</Button>
</Col>
</Row>
<Title level={3}></Title>
<Row>
<Col span={24}>
@ -272,7 +260,7 @@ function Newest() {
total: reservationPage.total,
simple: true
}}
onChange={(pagination, filters, sorter, extra) => {onSearchClick(pagination.current);}}
onChange={(pagination, filters, sorter, extra) => {onSearchClick(pagination.current)}}
columns={reservationListColumns} dataSource={reservationList}
/>
</Col>

Loading…
Cancel
Save