Merge branch 'main' of github.com:hainatravel/GHHub

release
赵鹏 2 years ago
commit 26e172a78c

@ -23,6 +23,7 @@ import AccountProfile from "@/views/account/Profile";
import FeedbackIndex from "@/views/feedback/Index"; import FeedbackIndex from "@/views/feedback/Index";
import FeedbackDetail from "@/views/feedback/Detail"; import FeedbackDetail from "@/views/feedback/Detail";
import NoticeIndex from "@/views/notice/Index"; import NoticeIndex from "@/views/notice/Index";
import NoticeDetail from "@/views/notice/Detail";
import InvoiceIndex from "@/views/invoice/Index"; import InvoiceIndex from "@/views/invoice/Index";
import InvoiceDetail from "@/views/invoice/Detail"; import InvoiceDetail from "@/views/invoice/Detail";
@ -52,6 +53,7 @@ const router = createBrowserRouter([
{ path: "feedback", element: <FeedbackIndex />}, { path: "feedback", element: <FeedbackIndex />},
{ path: "feedback/:GRI_SN", element: <FeedbackDetail />}, { path: "feedback/:GRI_SN", element: <FeedbackDetail />},
{ path: "notice", element: <NoticeIndex />}, { path: "notice", element: <NoticeIndex />},
{ path: "notice/:CCP_BLID", element: <NoticeDetail />},
{ path: "invoice",element:<InvoiceIndex />}, { path: "invoice",element:<InvoiceIndex />},
{ path: "invoice/detail/:GMDSN/:GSN",element:<InvoiceDetail />}, { path: "invoice/detail/:GMDSN/:GSN",element:<InvoiceDetail />},
] ]

@ -128,7 +128,7 @@ class Feedback {
//提交供应商反馈信息 //提交供应商反馈信息
postFeedbackInfo(VEI_SN, GRI_SN, EOI_SN, info_content) { postFeedbackInfo(VEI_SN, GRI_SN, EOI_SN, info_content) {
let url = `/service-fileServer/FeedbackInfo`; let url = `/service-CooperateSOA/FeedbackInfo`;
let formData = new FormData(); let formData = new FormData();
formData.append("VEI_SN", VEI_SN); formData.append("VEI_SN", VEI_SN);
formData.append("GRI_SN", GRI_SN); formData.append("GRI_SN", GRI_SN);

@ -0,0 +1,71 @@
import { makeAutoObservable, runInAction } from "mobx";
import * as config from "@/config";
class Notice {
constructor(root) {
makeAutoObservable(this, { rootStore: false });
this.root = root;
}
noticeList = []; //公告列表
noticeUnRead = 0; //未读公告数量
noticeInfo = { CCP_BLID: 0, CCP_BLTitle: "", CCP_BLContent: "", CCP_LastEditTime: "" }; //公告详情
/*
LMI_SN 登录用户SN用户sn用来判断是否已读公告
*/
getBulletinList(LMI_SN) {
let url = `/service-Cooperate/Cooperate/GetBulletinList`;
url += `?LMI_SN=${LMI_SN}`;
fetch(config.HT_HOST + url)
.then(response => response.json())
.then(json => {
console.log(json);
runInAction(() => {
this.noticeList = json.Result;
});
})
.catch(error => {
console.log("fetch data failed", error);
});
}
/*
LMI_SN 登录用户sn 用户sn用来设置已读公告请求过一次详情页表示已读
CCP_BLID 公告sn
*/
getNoticeDetail(LMI_SN, CCP_BLID) {
let url = `/service-Cooperate/Cooperate/GetBulletinDetail`;
url += `?LMI_SN=${LMI_SN}&CCP_BLID=${CCP_BLID}`;
fetch(config.HT_HOST + url)
.then(response => response.json())
.then(json => {
console.log(json);
runInAction(() => {
this.noticeInfo = json.Result;
});
})
.catch(error => {
console.log("fetch data failed", error);
});
}
//检查是否有未读公告
getBulletinUnReadCount(LMI_SN) {
let url = `/service-Cooperate/Cooperate/GetBulletinUnReadCount`;
url += `?LMI_SN=${LMI_SN}`;
fetch(config.HT_HOST + url)
.then(response => response.json())
.then(json => {
console.log(json);
runInAction(() => {
this.noticeUnRead = json.Result.CCP_BulletinCount;
});
})
.catch(error => {
console.log("fetch data failed", error);
});
}
}
export default Notice;

@ -10,13 +10,15 @@ class Reservation {
this.root = root; this.root = root;
} }
fetchReservationList(current, referenceNo, fromDate, thruDate) { fetchReservationList(current) {
const fromDate = this.arrivalDateRange.length == 0 ? null : this.arrivalDateRange[0].format('YYYY-MM-DD');
const thruDate = this.arrivalDateRange.length == 0 ? null : this.arrivalDateRange[1].format('YYYY-MM-DD');
this.reservationPage.current = current; this.reservationPage.current = current;
// 设置为 0后端会重新计算总数当跳转第 X 页时可用原来的总数。 // 设置为 0后端会重新计算总数当跳转第 X 页时可用原来的总数。
const totalNum = current == 1 ? 0 : this.reservationPage.total; const totalNum = current == 1 ? 0 : this.reservationPage.total;
const fetchUrl = prepareUrl(HT_HOST + '/service-cusservice/GetPlanSearchList') const fetchUrl = prepareUrl(HT_HOST + '/service-cusservice/GetPlanSearchList')
.append('VEI_SN', this.root.authStore.login.travelAgencyId) .append('VEI_SN', this.root.authStore.login.travelAgencyId)
.append('GroupNo', referenceNo) .append('GroupNo', this.referenceNo)
.append('DateStart', fromDate) .append('DateStart', fromDate)
.append('DateEnd', thruDate) .append('DateEnd', thruDate)
.append('TotalNum', totalNum) .append('TotalNum', totalNum)
@ -186,11 +188,19 @@ class Reservation {
this.selectedConfirmation = confirmation; this.selectedConfirmation = confirmation;
} }
updatePropertyValue(name, value) {
runInAction(() => {
this[name] = value;
});
}
guideList = []; guideList = [];
cityList = []; cityList = [];
selectedReservation = null; selectedReservation = null;
selectedConfirmation = null; selectedConfirmation = null;
arrivalDateRange = [];
referenceNo = '';
reservationList = []; reservationList = [];

@ -1,6 +1,7 @@
import { makeAutoObservable } from "mobx"; import { makeAutoObservable } from "mobx";
import Reservation from "./Reservation"; import Reservation from "./Reservation";
import Feedback from "./Feedback"; import Feedback from "./Feedback";
import Notice from "./Notice";
import Auth from "./Auth"; import Auth from "./Auth";
import Invoice from "./Invoice"; import Invoice from "./Invoice";
@ -8,6 +9,7 @@ class Root {
constructor() { constructor() {
this.reservationStore = new Reservation(this); this.reservationStore = new Reservation(this);
this.feedbackStore = new Feedback(this); this.feedbackStore = new Feedback(this);
this.noticeStore = new Notice(this);
this.authStore = new Auth(this); this.authStore = new Auth(this);
this.invoiceStore = new Invoice(this); this.invoiceStore = new Invoice(this);
makeAutoObservable(this); makeAutoObservable(this);

@ -1,7 +1,7 @@
import { Outlet, Link, useHref, useLocation, NavLink } from "react-router-dom"; import { Outlet, Link, useHref, useLocation, NavLink } from "react-router-dom";
import { useEffect } from "react"; import { useEffect } from "react";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { Layout, Menu, ConfigProvider, theme, Dropdown, Space, Row, Col, Alert, Typography, Divider, App as AntApp } from "antd"; import { Layout, Menu, ConfigProvider, theme, Dropdown, Space, Row, Col, Badge, Typography, Divider, App as AntApp } from "antd";
import { DownOutlined } from "@ant-design/icons"; import { DownOutlined } from "@ant-design/icons";
import "antd/dist/reset.css"; import "antd/dist/reset.css";
import AppLogo from "@/assets/logo-gh.png"; import AppLogo from "@/assets/logo-gh.png";
@ -28,8 +28,8 @@ const items = [
}, },
]; ];
function App() { function App() {
const { authStore } = useStore(); const { authStore, noticeStore } = useStore();
const { noticeUnRead } = noticeStore;
const href = useHref(); const href = useHref();
useEffect(() => { useEffect(() => {
// Check location // Check location
@ -61,7 +61,7 @@ function App() {
minHeight: "100vh", minHeight: "100vh",
}}> }}>
<Header className="header" style={{ position: "sticky", top: 0, zIndex: 1, width: "100%" }}> <Header className="header" style={{ position: "sticky", top: 0, zIndex: 1, width: "100%" }}>
<Row gutter={{ md: 24 }} justify="end" align="middle"> <Row gutter={{ md: 24 }} justify="end" align="middle">
<Col span={16}> <Col span={16}>
<NavLink to="/"> <NavLink to="/">
<img src={AppLogo} className="logo" alt="App logo" /> <img src={AppLogo} className="logo" alt="App logo" />
@ -74,12 +74,22 @@ function App() {
{ key: "reservation", label: <Link to="/reservation/newest">Reservation</Link> }, { key: "reservation", label: <Link to="/reservation/newest">Reservation</Link> },
{ key: "invoice", label: <Link to="/invoice">Invoice</Link> }, { key: "invoice", label: <Link to="/invoice">Invoice</Link> },
{ key: "feedback", label: <Link to="/feedback">Feedback</Link> }, { key: "feedback", label: <Link to="/feedback">Feedback</Link> },
{ key: "notice", label: <Link to="/notice">Notice</Link> }, {
key: "notice",
label: (
<Link to="/notice">
Notice
{noticeUnRead ? <Badge dot /> : ""}
</Link>
),
},
]} ]}
/> />
</Col> </Col>
<Col span={4}> <Col span={4}>
<Title level={3} style={{color: 'white', marginBottom: '0', display: 'flex', justifyContent: 'end'}}>{authStore.login.travelAgencyName}</Title> <Title level={3} style={{ color: "white", marginBottom: "0", display: "flex", justifyContent: "end" }}>
{authStore.login.travelAgencyName}
</Title>
</Col> </Col>
<Col span={4}> <Col span={4}>
<Dropdown <Dropdown
@ -97,8 +107,6 @@ function App() {
</Row> </Row>
</Header> </Header>
<Alert message={<NavLink to="/notice">公告 查看后不再显示或者一直显示或者放到页面底部</NavLink>} description="" type="info" banner closable />
<Content <Content
style={{ style={{
padding: 24, padding: 24,

@ -5,7 +5,7 @@ import { useStore } from '@/stores/StoreContext.js';
function Login() { function Login() {
const { authStore } = useStore(); const { authStore,noticeStore } = useStore();
const { notification } = App.useApp(); const { notification } = App.useApp();
const navigate = useNavigate(); const navigate = useNavigate();
const [form] = Form.useForm(); const [form] = Form.useForm();
@ -13,6 +13,7 @@ function Login() {
const onFinish = (values) => { const onFinish = (values) => {
authStore.valdateUserPassword(values.username, values.password) authStore.valdateUserPassword(values.username, values.password)
.then((userId) => { .then((userId) => {
noticeStore.getBulletinUnReadCount(userId);
authStore.fetchUserDetail(userId) authStore.fetchUserDetail(userId)
.then((user) => { .then((user) => {
// navigate(-1) is equivalent to hitting the back button. // navigate(-1) is equivalent to hitting the back button.

@ -5,8 +5,6 @@ import { toJS } from "mobx";
import { Row, Col, Space, Button, Table, Input, Typography, DatePicker, Radio } from "antd"; import { Row, Col, Space, Button, Table, Input, Typography, DatePicker, Radio } from "antd";
import { useStore } from "@/stores/StoreContext.js"; import { useStore } from "@/stores/StoreContext.js";
import * as config from "@/config"; import * as config from "@/config";
import * as comm from "@/utils/commons";
import dayjs from "dayjs";
const { Title } = Typography; const { Title } = Typography;
const feedbackListColumns = [ const feedbackListColumns = [
@ -51,10 +49,10 @@ function Index() {
const { feedbackStore, authStore } = useStore(); const { feedbackStore, authStore } = useStore();
const { feedbackList, search_date_start, search_date_end } = feedbackStore; const { feedbackList, search_date_start, search_date_end } = feedbackStore;
const [referenceNo, onNumberChange] = useState(""); const [referenceNo, onNumberChange] = useState("");
const showTotal = (total) => `Total ${feedbackList.length} items`; const showTotal = total => `Total ${feedbackList.length} items`;
useEffect(() => { useEffect(() => {
console.info("feedback.useEffect"); feedbackStore.searchFeedbackList(authStore.login.travelAgencyId, referenceNo, search_date_start.format(config.DATE_FORMAT), search_date_end.format(config.DATE_FORMAT) + " 23:59");
}, []); }, []);
return ( return (

@ -0,0 +1,40 @@
import { NavLink, useParams } from "react-router-dom";
import { useEffect, useState } from "react";
import { observer } from "mobx-react";
import { toJS } from "mobx";
import { Row, Col, Space, Button, Table, Input, Typography, Badge, Divider } from "antd";
import { useStore } from "@/stores/StoreContext.js";
import * as config from "@/config";
import * as comm from "@/utils/commons";
import dayjs from "dayjs";
const { Title, Paragraph, Text } = Typography;
function Detail() {
const { noticeStore, authStore } = useStore();
const { noticeInfo } = noticeStore;
const { CCP_BLID } = useParams();
useEffect(() => {
console.info("notice detail .useEffect " + CCP_BLID);
noticeStore.getNoticeDetail(authStore.login.userId, CCP_BLID);
}, []);
return (
<Space direction="vertical" style={{ width: "100%" }}>
<Row gutter={16}>
<Col span={4}></Col>
<Col span={16}>
<Title level={1}>{noticeInfo.CCP_BLTitle}</Title>
<Divider orientation="right">{noticeInfo.CCP_LastEditTime}</Divider>
<Paragraph>{noticeInfo.CCP_BLContent}</Paragraph>
</Col>
<Col span={4}>
<NavLink to="/notice">Back</NavLink>
</Col>
</Row>
</Space>
);
}
export default observer(Detail);

@ -2,7 +2,7 @@ import { NavLink } from "react-router-dom";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { toJS } from "mobx"; import { toJS } from "mobx";
import { Row, Col, Space, Button, Table, Input, Typography, DatePicker, Radio } from "antd"; import { Row, Col, Space, Button, Table, Input, Typography, Badge, List } from "antd";
import { useStore } from "@/stores/StoreContext.js"; import { useStore } from "@/stores/StoreContext.js";
import * as config from "@/config"; import * as config from "@/config";
import * as comm from "@/utils/commons"; import * as comm from "@/utils/commons";
@ -11,44 +11,28 @@ import dayjs from "dayjs";
const { Title, Paragraph, Text } = Typography; const { Title, Paragraph, Text } = Typography;
function Index() { function Index() {
const { feedbackStore } = useStore(); const { noticeStore, authStore } = useStore();
const { noticeList } = noticeStore;
useEffect(() => { useEffect(() => {
console.info("feedback.useEffect"); console.info("notice.useEffect");
noticeStore.getBulletinList(authStore.login.userId);
noticeStore.getBulletinUnReadCount(authStore.login.userId); //
}, []); }, []);
const [ellipsis, setEllipsis] = useState(true);
return ( return (
<Space direction="vertical" style={{ width: "100%" }}> <Space direction="vertical" style={{ width: "100%" }}>
<Row gutter={16}> <Row gutter={16}>
<Col span={4}></Col> <Col span={4}></Col>
<Col span={18}> <Col span={16}>
<Title level={2}>Guidelines and Resources</Title> <List
<Paragraph ellipsis={{ expandable: true, rows: 5 }}> dataSource={toJS(noticeList)}
We supply a series of design principles, practical patterns and high quality design resources (<Text code>Sketch</Text> and <Text code>Axure</Text>), to help people create their product prototypes beautifully and We renderItem={item => (
supply a series of design principles, practical patterns and high quality design resources (<Text code>Sketch</Text> and <Text code>Axure</Text>), to help people create their product prototypes beautifully and We <List.Item>
supply a series of design principles, practical patterns and high quality design resources (<Text code>Sketch</Text> and <Text code>Axure</Text>), to help people create their product prototypes beautifully and We <Typography.Text>[{item.CCP_LastEditTime}]</Typography.Text>
supply a series of design principles, practical patterns and high quality design resources (<Text code>Sketch</Text> and <Text code>Axure</Text>), to help people create their product prototypes beautifully and <NavLink to={`/notice/${item.CCP_BLID}`}> {item.CCP_BLTitle}</NavLink> {item.IsRead ? "" : <Badge dot />}
efficiently. efficiently. We supply a series of design principles, practical patterns and high quality design resources (<Text code>Sketch</Text> and <Text code>Axure</Text>), to help people create their product </List.Item>
prototypes beautifully and We supply a series of design principles, practical patterns and high quality design resources (<Text code>Sketch</Text> and <Text code>Axure</Text>), to help people create their product )}></List>
prototypes beautifully and efficiently. efficiently. We supply a series of design principles, practical patterns and high quality design resources (<Text code>Sketch</Text> and <Text code>Axure</Text>), to help
people create their product prototypes beautifully and We supply a series of design principles, practical patterns and high quality design resources (<Text code>Sketch</Text> and <Text code>Axure</Text>), to help
people create their product prototypes beautifully and efficiently. efficiently. efficiently. efficiently.
</Paragraph>
<Title level={2}>第二个公告</Title>
<Paragraph ellipsis={{ expandable: true, rows: 5 }}>
We supply a series of design principles, practical patterns and high quality design resources (<Text code>Sketch</Text> and <Text code>Axure</Text>), to help people create their product prototypes beautifully and We
supply a series of design principles, practical patterns and high quality design resources (<Text code>Sketch</Text> and <Text code>Axure</Text>), to help people create their product prototypes beautifully and We
supply a series of design principles, practical patterns and high quality design resources (<Text code>Sketch</Text> and <Text code>Axure</Text>), to help people create their product prototypes beautifully and We
supply a series of design principles, practical patterns and high quality design resources (<Text code>Sketch</Text> and <Text code>Axure</Text>), to help people create their product prototypes beautifully and
efficiently. efficiently. We supply a series of design principles, practical patterns and high quality design resources (<Text code>Sketch</Text> and <Text code>Axure</Text>), to help people create their product
prototypes beautifully and We supply a series of design principles, practical patterns and high quality design resources (<Text code>Sketch</Text> and <Text code>Axure</Text>), to help people create their product
prototypes beautifully and efficiently. efficiently. We supply a series of design principles, practical patterns and high quality design resources (<Text code>Sketch</Text> and <Text code>Axure</Text>), to help
people create their product prototypes beautifully and We supply a series of design principles, practical patterns and high quality design resources (<Text code>Sketch</Text> and <Text code>Axure</Text>), to help
people create their product prototypes beautifully and efficiently. efficiently. efficiently. efficiently.
</Paragraph>
</Col> </Col>
<Col span={4}></Col> <Col span={4}></Col>
</Row> </Row>

@ -1,5 +1,5 @@
import { NavLink } from "react-router-dom"; import { NavLink } from "react-router-dom";
import { useState, useEffect } from 'react'; import { useState, useRef, useEffect } from 'react';
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { toJS } from "mobx"; import { toJS } from "mobx";
import { Row, Col, Space, Button, Table, Input, Typography, DatePicker, Radio, Modal, App, Select } from 'antd'; import { Row, Col, Space, Button, Table, Input, Typography, DatePicker, Radio, Modal, App, Select } from 'antd';
@ -87,18 +87,18 @@ function Newest() {
/> />
); );
} }
// const href = useHref();
// const isMountedRef = useRef(false);
const { reservationStore } = useStore(); const { reservationStore } = useStore();
const { reservationList, reservationPage, cityList, guideList } = reservationStore; const { reservationList, reservationPage, referenceNo, arrivalDateRange, cityList, guideList } = reservationStore;
const [isModalOpen, setIsModalOpen] = useState(false); const [isModalOpen, setIsModalOpen] = useState(false);
const arrivalDateFrom = dayjs().startOf("M");
const arrivalDateThru = dayjs().endOf("M");
const [arrivalDateRange, onDateRangeChange] =
useState([arrivalDateFrom.format('YYYY-MM-DD'), arrivalDateThru.format('YYYY-MM-DD')]);
const [referenceNo, onNumberChange] = useState('');
const [dataLoading, setDataLoading] = useState(false); const [dataLoading, setDataLoading] = useState(false);
const { notification } = App.useApp(); const { notification } = App.useApp();
const arrivalDateFrom = arrivalDateRange.length == 0 ? null : arrivalDateRange[0];
const arrivalDateThru = arrivalDateRange.length == 0 ? null : arrivalDateRange[1];
const guideSelectOptions = guideList.map((data, index) => { const guideSelectOptions = guideList.map((data, index) => {
return { return {
value: data.guideId, value: data.guideId,
@ -108,7 +108,8 @@ function Newest() {
useEffect(() => { useEffect(() => {
onSearchClick(); onSearchClick();
}, []); console.info('Newest...');
}, [123]);
const showCityGuideModal = (reservation) => { const showCityGuideModal = (reservation) => {
setDataLoading(true); setDataLoading(true);
@ -139,7 +140,7 @@ function Newest() {
const onSearchClick = (current=1) => { const onSearchClick = (current=1) => {
setDataLoading(true); setDataLoading(true);
reservationStore.fetchReservationList(current, referenceNo, arrivalDateRange[0], arrivalDateRange[1]) reservationStore.fetchReservationList(current)
.catch(ex => { .catch(ex => {
notification.error({ notification.error({
message: `Notification`, message: `Notification`,
@ -188,25 +189,23 @@ function Newest() {
<Space direction="vertical" style={{ width: '100%' }}> <Space direction="vertical" style={{ width: '100%' }}>
<Title level={3}>Newest Reservations</Title> <Title level={3}>Newest Reservations</Title>
<Row gutter={{ md: 24 }}> <Row gutter={{ md: 24 }}>
<Col span={4}>
<Input placeholder="Reference number" onChange={(e) => {onNumberChange(e.target.value)}} />
</Col>
<Col span={6}> <Col span={6}>
<Input placeholder="Reference number" value={referenceNo} onChange={(e) => { reservationStore.updatePropertyValue('referenceNo', e.target.value)} } />
</Col>
<Col span={18}>
<Space direction="horizontal"> <Space direction="horizontal">
Arrival Date Arrival Date
<DatePicker.RangePicker <DatePicker.RangePicker
allowClear={true} allowClear={true}
inputReadOnly={true} inputReadOnly={true}
presets={DATE_PRESETS} presets={DATE_PRESETS}
defaultValue={[arrivalDateFrom, arrivalDateThru]} value={[arrivalDateFrom, arrivalDateThru]}
placeholder={['From', 'Thru']} placeholder={['From', 'Thru']}
onChange={(date, dateRange) => { onDateRangeChange(dateRange)}} onChange={(dateRange) => { reservationStore.updatePropertyValue('arrivalDateRange', dateRange)}}
/> />
<Button type='primary' onClick={() => onSearchClick()} loading={dataLoading}>Search</Button>
</Space> </Space>
</Col> </Col>
<Col span={14}>
<Button type='primary' onClick={() => onSearchClick()} loading={dataLoading}>Search</Button>
</Col>
</Row> </Row>
<Row> <Row>
<Col span={24}> <Col span={24}>

Loading…
Cancel
Save