Merge branch 'feature/hotel-cruise'

main
Lei OT 2 months ago
commit 7c08e8bfe6

@ -55,6 +55,8 @@ import CooperationIcon from './components/icons/CooperationIcon';
import OPDashboard from './views/OPDashboard'; import OPDashboard from './views/OPDashboard';
import OPProcess from './views/OPProcess'; import OPProcess from './views/OPProcess';
import OPRisk from './views/OPRisk'; import OPRisk from './views/OPRisk';
import Cruise from './views/Cruise';
import Hotel from './views/Hotel';
const App = () => { const App = () => {
const { Content, Footer, Sider, } = Layout; const { Content, Footer, Sider, } = Layout;
@ -158,6 +160,8 @@ const App = () => {
key: 62, key: 62,
label: <NavLink to="/destination/group/count">目的地接团</NavLink>, label: <NavLink to="/destination/group/count">目的地接团</NavLink>,
}, },
{ key: 'cruise', label: <NavLink to="/cruise">三峡游船</NavLink> },
{ key: 'hotel', label: <NavLink to="/hotel">酒店</NavLink> },
], ],
}, },
{ {
@ -259,7 +263,9 @@ const App = () => {
<Route path="/destination/group/count" element={<DestinationGroupCount />} /> <Route path="/destination/group/count" element={<DestinationGroupCount />} />
<Route path="/agent/:agentId/group/list" element={<AgentGroupList />} /> <Route path="/agent/:agentId/group/list" element={<AgentGroupList />} />
<Route path="/destination/:destinationId/group/list" element={<DestinationGroupList />} /> <Route path="/destination/:destinationId/group/list" element={<DestinationGroupList />} />
</Route> <Route path="/cruise" element={<Cruise />} />
<Route path="/hotel" element={<Hotel />} />
</Route>
<Route element={<ProtectedRoute auth={['admin', 'director_bu', 'financial']} />}> <Route element={<ProtectedRoute auth={['admin', 'director_bu', 'financial']} />}>
<Route path="/credit_card_bill" element={<Credit_card_bill />} /> <Route path="/credit_card_bill" element={<Credit_card_bill />} />
<Route path="/exchange_rate" element={<ExchangeRate />} /> <Route path="/exchange_rate" element={<ExchangeRate />} />

@ -0,0 +1,40 @@
import React from 'react';
import { Select } from 'antd';
import { observer } from 'mobx-react';
import { HotelStars as options } from '../../libs/ht';
const HotelStars = (props) => {
const { mode, value, onChange, show_all, ...extProps } = props;
const _show_all = ['tags', 'multiple'].includes(mode) ? false : show_all;
return (
<div>
<Select
mode={mode || null}
allowClear
style={{ width: '100%' }}
placeholder="星级"
value={value || undefined}
onChange={(value) => {
if (typeof onChange === 'function') {
onChange(value);
}
}}
labelInValue={false}
{...extProps}
options={options}
>
{_show_all ? (
<Select.Option key="-1" value="ALL">
ALL
</Select.Option>
) : (
''
)}
</Select>
</div>
);
};
/**
* 酒店星级
*/
export default observer(HotelStars);

@ -3,7 +3,7 @@ import { toJS } from 'mobx';
import { observer } from 'mobx-react'; import { observer } from 'mobx-react';
import { DATE_FORMAT, SMALL_DATETIME_FORMAT, stores_Context } from './../../config'; import { DATE_FORMAT, SMALL_DATETIME_FORMAT, stores_Context } from './../../config';
import { SearchOutlined } from '@ant-design/icons'; import { SearchOutlined } from '@ant-design/icons';
import { Form, Row, Col, Select, Button, Space, DatePicker } from 'antd'; import { Form, Row, Col, Select, Button, Space, DatePicker, Input, InputNumber } from 'antd';
import moment from 'moment'; import moment from 'moment';
// import locale from 'antd/es/date-picker/locale/zh_CN'; // import locale from 'antd/es/date-picker/locale/zh_CN';
import BusinessSelect from './BusinessSelect'; import BusinessSelect from './BusinessSelect';
@ -18,6 +18,7 @@ import { objectMapper, at, empty, isEmpty } from './../../utils/commons';
import { departureDateTypes } from './../../libs/ht'; import { departureDateTypes } from './../../libs/ht';
import './search.css'; import './search.css';
import HotelStarSelect from './HotelStarSelect';
const EditableContext = createContext(); const EditableContext = createContext();
const Option = Select.Option; const Option = Select.Option;
@ -180,6 +181,26 @@ export default observer((props) => {
transform: (value) => value?.value || value?.key || '', transform: (value) => value?.value || value?.key || '',
default: '', default: '',
}, },
'cruiseDirection': {
key: 'cruiseDirection',
transform: (value) => value?.key || '',
default: '',
},
'hotelBookType': {
key: 'hotelBookType',
transform: (value) => value?.key || '',
default: '',
},
'hotelRecommandRate': {
key: 'hotelRecommandRate',
transform: (value) => value?.key || '',
default: '',
},
'hotelStar': {
key: 'hotelStar',
transform: (value) => value?.key || '',
default: '',
},
}; };
let dest = {}; let dest = {};
const { departureDateType, applyDate, applyDate2, year, yearDiff, dates, months, date, ...omittedValue } = values; const { departureDateType, applyDate, applyDate2, year, yearDiff, dates, months, date, ...omittedValue } = values;
@ -274,6 +295,14 @@ function getFields(props) {
}; };
let baseChildren = []; let baseChildren = [];
baseChildren = [ baseChildren = [
item(
'keyword', // {...fieldComProps.keyword}
99,
<Form.Item name="keyword" {...fieldProps.keyword}>
<Input allowClear {...fieldProps.keyword} />
</Form.Item>,
fieldProps?.keyword?.col || 6
),
item( item(
'agency', 'agency',
99, 99,
@ -348,11 +377,11 @@ function getFields(props) {
item( item(
'countryArea', 'countryArea',
99, 99,
<Form.Item name={`countryArea`} initialValue={at(props, 'initialValue.countryArea')[0] || (fieldProps?.countryArea?.show_all ? { key: 'all', label: '所有国家' } : undefined)}> <Form.Item name={`countryArea`} initialValue={at(props, 'initialValue.countryArea')[0] || (fieldProps?.countryArea?.show_all ? { key: 'all', label: '国内外' } : undefined)}>
<Select style={{ width: '100%' }} placeholder="所有国家" labelInValue> <Select style={{ width: '100%' }} placeholder="国内外" labelInValue allowClear={fieldProps?.countryArea?.show_all || false}>
{fieldProps?.countryArea?.show_all && ( {fieldProps?.countryArea?.show_all && (
<Option key="all" value=""> <Option key="all" value="" disabled>
所有国家 国内外
</Option> </Option>
)} )}
<Option key="china" value="china"> <Option key="china" value="china">
@ -368,11 +397,11 @@ function getFields(props) {
item( item(
'orderStatus', 'orderStatus',
99, 99,
<Form.Item name={`orderStatus`} initialValue={at(props, 'initialValue.orderStatus')[0] || (fieldProps?.orderStatus?.show_all ? { key: '-1', label: '所有' } : undefined)}> <Form.Item name={`orderStatus`} initialValue={at(props, 'initialValue.orderStatus')[0] || (fieldProps?.orderStatus?.show_all ? { key: '-1', label: '成行状态' } : undefined)}>
<Select style={{ width: '100%' }} placeholder="所有状态" labelInValue> <Select style={{ width: '100%' }} placeholder="成行状态" labelInValue allowClear>
{fieldProps?.orderStatus?.show_all && ( {fieldProps?.orderStatus?.show_all && (
<Select.Option key="所有" value="-1"> <Select.Option key="-1" value="-1" disabled>
所有 成行状态
</Select.Option> </Select.Option>
)} )}
<Select.Option key="已成行" value="1"> <Select.Option key="已成行" value="1">
@ -398,10 +427,7 @@ function getFields(props) {
'departureDateType', 'departureDateType',
99, 99,
<Form.Item name={`departureDateType`} initialValue={at(props, 'initialValue.departureDateType')[0] || { key: 'departureDate', label: '抵达日期' }}> <Form.Item name={`departureDateType`} initialValue={at(props, 'initialValue.departureDateType')[0] || { key: 'departureDate', label: '抵达日期' }}>
<Select labelInValue={true} <Select labelInValue={true} style={{ width: '100%' }} placeholder="选择日期类型">
style={{ width: '100%' }}
placeholder="选择日期类型"
>
{departureDateTypes.map((ele) => ( {departureDateTypes.map((ele) => (
<Select.Option key={ele.key} value={ele.key} disabled={fieldProps?.departureDateType?.disabledKeys.includes(ele.key)}> <Select.Option key={ele.key} value={ele.key} disabled={fieldProps?.departureDateType?.disabledKeys.includes(ele.key)}>
{ele.label} {ele.label}
@ -492,6 +518,128 @@ function getFields(props) {
<SearchInput autoGet url="/service-Analyse2/GetGlobalDestinationInfo" map={{ 'c_id': 'key', 'cn_name': 'label' }} resultkey={'result'} placeholder="输入搜索城市: 中/英名字" /> <SearchInput autoGet url="/service-Analyse2/GetGlobalDestinationInfo" map={{ 'c_id': 'key', 'cn_name': 'label' }} resultkey={'result'} placeholder="输入搜索城市: 中/英名字" />
</Form.Item> </Form.Item>
), ),
item(
'cruiseDirection',
99,
<Form.Item name={`cruiseDirection`} initialValue={at(props, 'initialValue.cruiseDirection')[0] || undefined}>
<Select style={{ width: '100%' }} placeholder="上下水" labelInValue allowClear>
{fieldProps?.cruiseDirection?.show_all && (
<Option key="all" value="" disabled>
上下水
</Option>
)}
<Option key="1" value="1">
上水
</Option>
<Option key="2" value="2">
下水
</Option>
{/* <Option key="long" value="long">
长线
</Option> */}
</Select>
</Form.Item>,
3
),
item(
'cruiseBookType',
99,
<Form.Item name={`cruiseBookType`} initialValue={at(props, 'initialValue.cruiseBookType')[0] || (fieldProps?.cruiseBookType?.show_all ? { key: 'all', label: '预定类型' } : undefined)}>
<Select style={{ width: '100%' }} placeholder="预定类型" labelInValue allowClear>
{fieldProps?.cruiseBookType?.show_all && (
<Option key="all" value="" disabled>
预定类型
</Option>
)}
<Option key="1" value="1">
单订三峡
</Option>
<Option key="0" value="0">
其他
</Option>
</Select>
</Form.Item>,
3
),
item(
'roomsRange',
99,
<Form.Item noStyle>
<Input.Group compact>
<Form.Item name={'RoomNumStart'} noStyle>
<InputNumber style={{ width: 'calc(50% - 15px)', textAlign: 'center' }} placeholder="房间数" />
</Form.Item>
<Input style={{ width: 30, borderLeft: 0, borderRight: 0, pointerEvents: 'none', }} placeholder="~" disabled />
<Form.Item name={'RoomNumEnd'} noStyle>
<InputNumber style={{ width: 'calc(50% - 15px)', textAlign: 'center', borderLeft: 0 }} placeholder="房间数" />
</Form.Item>
</Input.Group>
</Form.Item>,
fieldProps?.roomsRange?.col || 4
),
item(
'personRange',
99,
<Form.Item noStyle>
<Input.Group compact>
<Form.Item name={'PersonNumStart'} noStyle>
<InputNumber style={{ width: 'calc(50% - 15px)', textAlign: 'center' }} placeholder="人数" />
</Form.Item>
<Input style={{ width: 30, borderLeft: 0, borderRight: 0, pointerEvents: 'none', }} placeholder="~" disabled />
<Form.Item name={'PersonNumEnd'} noStyle>
<InputNumber style={{ width: 'calc(50% - 15px)', textAlign: 'center', borderLeft: 0 }} placeholder="人数" />
</Form.Item>
</Input.Group>
</Form.Item>,
fieldProps?.personRange?.col || 4
),
item(
'hotelBookType',
99,
<Form.Item name={`hotelBookType`} initialValue={at(props, 'initialValue.hotelBookType')[0] || (fieldProps?.hotelBookType?.show_all ? { key: 'all', label: '预定类型' } : undefined)}>
<Select style={{ width: '100%' }} placeholder="预定类型" labelInValue allowClear={fieldProps?.hotelBookType?.show_all || false}>
{fieldProps?.hotelBookType?.show_all && (
<Option key="all" value="" disabled>
预定类型
</Option>
)}
<Option key="1" value="1">
代订
</Option>
<Option key="0" value="0">
自订
</Option>
</Select>
</Form.Item>,
3
),
item(
'hotelRecommandRate',
99,
<Form.Item name={`hotelRecommandRate`} initialValue={at(props, 'initialValue.hotelRecommandRate')[0] || (fieldProps?.hotelRecommandRate?.show_all ? { key: 'all', label: '推荐等级' } : undefined)}>
<Select style={{ width: '100%' }} placeholder="推荐等级" labelInValue allowClear={fieldProps?.hotelRecommandRate?.show_all || false}>
{fieldProps?.hotelRecommandRate?.show_all && (
<Option key="all" value="" disabled>
推荐等级
</Option>
)}
<Option key="1" value="1">
主推
</Option>
<Option key="0" value="0">
非主推
</Option>
</Select>
</Form.Item>,
3
),
item(
'hotelStar',
99,
<Form.Item name={`hotelStar`} initialValue={at(props, 'initialValue.hotelStar')[0] || undefined}>
<HotelStarSelect {...fieldProps.hotelStar} labelInValue={true} />
</Form.Item>
),
]; ];
baseChildren = baseChildren baseChildren = baseChildren
.map((x) => { .map((x) => {

@ -184,6 +184,19 @@ export const KPISubjects = [
// { key: 'sum_person_num', value: 'sum_person_num', label: '人数' }, // { key: 'sum_person_num', value: 'sum_person_num', label: '人数' },
]; ];
export const HotelStars = [
{ key: '1', value: '1', label: '五星' },
{ key: '2', value: '2', label: '四星' },
{ key: '3', value: '3', label: '三星' },
{ key: '4', value: '4', label: '二星' },
{ key: '8', value: '8', label: '准五星 ' },
{ key: '9', value: '9', label: '准四星' },
{ key: '10', value: '10', label: '客栈' },
{ key: '11', value: '11', label: '公寓' },
{ key: '12', value: '12', label: '四合院酒店' },
{ key: '13', value: '13', label: '豪华五星' },
];
/** /**
* 计算指标值的分段区间 * 计算指标值的分段区间
* @param {number} value * @param {number} value

@ -0,0 +1,163 @@
import { makeAutoObservable, runInAction, toJS } from 'mobx';
import { fetchJSON } from '../utils/request';
import { isEmpty, sortDescBy, objectMapper, groupBy, pick, unique, cloneDeep, omit, fixTo2Decimals } from '../utils/commons';
import { groupsMappedByCode, dataFieldAlias } from './../libs/ht';
import { DATE_FORMAT, SMALL_DATETIME_FORMAT } from './../config';
import moment from 'moment';
const fetchHotelData = async (param) => {
const defaultParam = {
DEI_SN: '',
City: '',
OrderState: '',
BookingType: '-1',
RecommendedLevel: '-1',
Star: '-1',
ArriveDateCheck: '0',
ArriveDateStart: '',
ArriveDateEnd: '',
ConfirmDateCheck: '0',
ConfirmDateStart: '',
ConfirmDateEnd: '',
Compare: '0',
CompareDateStart: '',
CompareDateEnd: '',
Area: '-1',
};
const json = await fetchJSON('/service-Analyse2/HotelReservation', { ...defaultParam, ...param });
return json.errcode === 0 ? json.result || [] : [];
};
const fetchCruiseData = async (param) => {
const defaultParam = {
DEI_SN: '',
OrderState: '', // 0: 不成行 1: 成行
ArriveDateStart: '',
ArriveDateEnd: '',
Compare: '',
CompareDateStart: '',
CompareDateEnd: '',
BookingType: '', // 0: 非单订三峡1: 单订三峡
ProductName: '',
Direction: '', // 1: 上水 2: 下水
VEI_SN: '-1', // 只要列出常用游船供应商选择
RoomNumStart: '0',
RoomNumEnd: '',
PersonNumStart: '0',
PersonNumEnd: '',
Country: '-1',
};
const json = await fetchJSON('/service-Analyse2/CruiseReservation', { ...defaultParam, ...param });
return json.errcode === 0 ? json.result || [] : [];
};
const paramKeyMapped = {
'DateType': [
{ key: 'ArriveDateCheck', transform: (val) => (val === 'startDate' ? '1' : '0') },
{ key: 'ConfirmDateCheck', transform: (val) => (val === 'confirmDate' ? '1' : '0') },
// { key: 'ApplyDateCheck', transform: (val) => (val === 'applyDate' ? '1' : '0') },
],
'DepartmentList': { key: 'DEI_SN' },
'orderStatus': { key: 'OrderState' },
'Date1': [{ key: 'ArriveDateStart' }, { key: 'ConfirmDateStart' }],
'Date2': [{ key: 'ArriveDateEnd' }, { key: 'ConfirmDateEnd' }],
'DateDiff1': { key: 'CompareDateStart' },
'DateDiff2': { key: 'CompareDateEnd' },
'keyword': { key: 'ProductName' },
'cruiseDirection': { key: 'Direction' },
'hotelStar': { key: 'Star' },
'hotelRecommandRate': { key: 'RecommendedLevel' },
'hotelBookType': { key: 'BookingType' },
'countryArea': { key: 'Area', transform: (val) => (val === 'china' ? '1' : val === 'foreign' ? '0' : '-1') },
};
class HotelCruise {
constructor(appStore) {
this.appStore = appStore;
makeAutoObservable(this);
}
async getCruiseData(param = {}) {
this.cruise.loading = true;
this.cruise.dataSource = [];
const _queryParam = objectMapper(param, paramKeyMapped);
const queryParam = omit({ ...this.searchValuesToSub, ..._queryParam }, ['DepartmentList', 'orderStatus', 'keyword', 'Date1', 'Date2', 'DateDiff1', 'DateDiff2', 'cruiseDirection']);
queryParam.Compare = isEmpty(param.DateDiff1) ? '' : '1';
const res = await fetchCruiseData(queryParam);
const resCP =
queryParam.Compare === ''
? res
: (res || []).map((ele) => ({
...ele,
TotalNumPercent: ele.CPTotalNum ? fixTo2Decimals(((ele.TotalNum - ele.CPTotalNum) / ele.CPTotalNum) * 100) : '-',
TotalPersonNumPercent: ele.CPTotalPersonNum ? fixTo2Decimals(((ele.TotalPersonNum - ele.CPTotalPersonNum) / ele.CPTotalPersonNum) * 100) : '-',
TotalProfitPercent: ele.CPTotalProfit ? fixTo2Decimals(((ele.TotalProfit - ele.CPTotalProfit) / ele.CPTotalProfit) * 100) : '-',
}));
runInAction(() => {
this.cruise.loading = false;
this.cruise.dataSource = resCP;
});
return this.cruise;
}
async getHotelData(param = {}) {
this.hotel.loading = true;
this.hotel.dataSource = [];
const _queryParam = objectMapper(param, paramKeyMapped);
const queryParam = omit({ ...this.searchValuesToSub, ..._queryParam }, [
'DepartmentList','orderStatus','keyword','Date1','Date2','DateDiff1','DateDiff2','DateType',
'hotelStar','hotelRecommandRate','hotelBookType','countryArea',
]);
queryParam.Compare = isEmpty(param.DateDiff1) ? '0' : '1';
const _res = await fetchHotelData(queryParam);
const res = (_res || []).map((ele) => ({ ...ele, RecommendRate_100: fixTo2Decimals(ele.RecommendRate * 100) + '%' }));
const resCP =
queryParam.Compare === '0'
? res
: (res || []).map((ele) => ({
...ele,
TotalNumPercent: ele.CPTotalNum ? fixTo2Decimals(((ele.TotalNum - ele.CPTotalNum) / ele.CPTotalNum) * 100) : '-',
RecomendNumPercent: ele.CPRecomendNum ? fixTo2Decimals(((ele.RecomendNum - ele.CPRecomendNum) / ele.CPRecomendNum) * 100) : '-',
RecommendRateDelta: fixTo2Decimals((ele.RecommendRate - (ele.CPRecommendRate || 0)) * 100),
CPRecommendRate_100: fixTo2Decimals(ele.CPRecommendRate * 100) + '%',
}));
runInAction(() => {
this.hotel.loading = false;
this.hotel.dataSource = resCP;
});
}
searchValues = {
date: moment(),
DateType: { key: 'confirmDate', label: '确认日期' },
WebCode: { key: '', label: '所有来源' },
// IncludeTickets: { key: '1', label: '含门票'},
DepartmentList: [{ key: '', label: '所有小组' }],
operator: '-1',
opisn: '-1',
};
searchValuesToSub = {};
setSearchValues(obj, values) {
this.searchValues = { ...this.searchValues, ...values };
this.searchValuesToSub = obj;
}
cruise = { loading: false, dataSource: [] };
hotel = { loading: false, dataSource: [] };
resetData = () => {
this.results.loading = false;
for (const key of Object.keys(this.results)) {
if (key !== 'loading') {
this.results[key] = [];
}
}
for (const key of Object.keys(this.hotel)) {
if (key !== 'loading') {
this.hotel[key] = [];
}
}
};
}
export default HotelCruise;

@ -18,6 +18,7 @@ import DataPivot from './DataPivot';
import MeetingData from './MeetingData2024'; import MeetingData from './MeetingData2024';
import MeetingData2025 from './MeetingData2025'; import MeetingData2025 from './MeetingData2025';
import SalesCRMData from './SalesCRMData'; import SalesCRMData from './SalesCRMData';
import HotelCruise from './HotelCruise';
class Index { class Index {
constructor() { constructor() {
this.dashboard_store = new DashboardStore(this); this.dashboard_store = new DashboardStore(this);
@ -39,6 +40,7 @@ class Index {
this.MeetingDataStore = new MeetingData(this); this.MeetingDataStore = new MeetingData(this);
this.MeetingData2025Store = new MeetingData2025(this); this.MeetingData2025Store = new MeetingData2025(this);
this.SalesCRMDataStore = new SalesCRMData(this); this.SalesCRMDataStore = new SalesCRMData(this);
this.HotelCruiseStore = new HotelCruise(this);
makeAutoObservable(this); makeAutoObservable(this);
} }

@ -0,0 +1,109 @@
import React, { Children, useContext, useState } from 'react';
import { observer } from 'mobx-react';
import { stores_Context } from '../config';
import moment from 'moment';
import { Row, Col, Table, Select, Space, Typography, Progress, Spin, Divider, Button, Switch } from 'antd';
import SearchForm from './../components/search/SearchForm';
import { VSTag, TableExportBtn } from './../components/Data';
const {Text} = Typography;
export default observer((props) => {
const { sale_store, date_picker_store: searchFormStore } = useContext(stores_Context);
const { customerServicesStore, HotelCruiseStore, date_picker_store } = useContext(stores_Context);
const { loading, dataSource } = HotelCruiseStore.cruise;
const { formValues, siderBroken } = searchFormStore;
const tableSorter = (a, b, colName) => (a[colName] - b[colName]);
const tableProps = {
size: 'small',
bordered: true, pagination: false,
columns: [
{ title: '产品', dataIndex: 'ProductName', key: 'ProductName' },
{
title: '房间数',
dataIndex: 'TotalNum',
key: 'TotalNum',
sorter: (a, b) => tableSorter(a, b, 'TotalNum'),
render: (v, r) => (
<>
<Space direction={'vertical'}>
<Text strong>
{v}
{r.CPTotalNum && <Text type="secondary"> VS {r.CPTotalNum}</Text>}
</Text>
{r.CPTotalNum && <VSTag diffPercent={r.TotalNumPercent} />}
</Space>
</>
),
},
{ title: '人数', dataIndex: 'TotalPersonNum', key: 'TotalPersonNum',
sorter: (a, b) => tableSorter(a, b, 'TotalPersonNum'),
render: (v, r) => (
<>
<Space direction={'vertical'}>
<Text strong>
{v}
{r.CPTotalPersonNum && <Text type="secondary"> VS {r.CPTotalPersonNum}</Text>}
</Text>
{r.CPTotalNum && <VSTag diffPercent={r.TotalPersonNumPercent} />}
</Space>
</>
),},
{ title: '总利润', dataIndex: 'TotalProfit', key: 'TotalProfit',
sorter: (a, b) => tableSorter(a, b, 'TotalProfit'),
render: (v, r) => (
<>
<Space direction={'vertical'}>
<Text strong>
{v}
{r.CPTotalProfit && <Text type="secondary"> VS {r.CPTotalProfit}</Text>}
</Text>
{r.CPTotalNum && <VSTag diffPercent={r.TotalProfitPercent} />}
</Space>
</>
), },
// { title: '', dataIndex: '', key: '' },
// { title: '', dataIndex: '', key: '' },
// { title: '', dataIndex: '', key: '' },
],
};
return (
<>
<Row gutter={16} className={siderBroken ? '' : 'sticky-top'}>
<Col md={24} lg={24} xxl={24}>
<SearchForm
defaultValue={{
initialValue: {
...date_picker_store.formValues,
...HotelCruiseStore.searchValues,
},
// 'countryArea',
shows: [
'DepartmentList', 'orderStatus', 'dates', 'keyword', 'cruiseDirection', 'agency',
// 'cruiseBookType', 'country', 'roomsRange', 'personRange'
],
sort: { keyword: 101, agency: 103, cruiseDirection: 102, country: 104 },
fieldProps: {
keyword: { placeholder: '产品名', col: 4 },
DepartmentList: { show_all: true, mode: 'multiple' },
orderStatus: { show_all: true },
cruiseDirection: { show_all: true },
// years: { hide_vs: false },
},
}}
onSubmit={(_err, obj, form) => {
HotelCruiseStore.setSearchValues(obj, form);
HotelCruiseStore.getCruiseData(obj);
}}
/>
</Col>
</Row>
<section>
<Table {...tableProps} {...{loading, dataSource}} rowKey={(record) => record.ProductName} />
</section>
</>
);
});

@ -0,0 +1,112 @@
import React, { useContext } from 'react';
import { observer } from 'mobx-react';
import { stores_Context } from '../config';
import { Row, Col, Table, Space, Typography } from 'antd';
import SearchForm from './../components/search/SearchForm';
import { VSTag, TableExportBtn } from './../components/Data';
const { Text } = Typography;
export default observer((props) => {
const { sale_store, date_picker_store: searchFormStore } = useContext(stores_Context);
const { customerServicesStore, date_picker_store, HotelCruiseStore } = useContext(stores_Context);
const { loading, dataSource } = HotelCruiseStore.hotel;
const { formValues, siderBroken } = searchFormStore;
const tableSorter = (a, b, colName) => (a[colName] - b[colName]);
const tableProps = {
size: 'small',
bordered: true,
pagination: false,
columns: [
{ title: '目的地', dataIndex: 'CityName', key: 'CityName' },
{
title: '总间夜',
dataIndex: 'TotalNum',
key: 'TotalNum',
sorter: (a, b) => tableSorter(a, b, 'TotalNum'),
render: (v, r) => (
<>
<Space direction={'vertical'}>
<Text strong>
{v}
{r.CPTotalNum && <Text type="secondary"> VS {r.CPTotalNum}</Text>}
</Text>
{r.CPTotalNum && <VSTag diffPercent={r.TotalNumPercent} />}
</Space>
</>
),
},
{
title: '主推',
dataIndex: 'RecomendNum',
key: 'RecomendNum',
sorter: (a, b) => tableSorter(a, b, 'RecomendNum'),
render: (v, r) => (
<>
<Space direction={'vertical'}>
<Text strong>
{v}
{r.CPRecomendNum && <Text type="secondary"> VS {r.CPRecomendNum}</Text>}
</Text>
{r.CPRecomendNum && <VSTag diffPercent={r.RecomendNumPercent} />}
</Space>
</>
),
},
{
title: '使用比例',
dataIndex: 'RecommendRate_100',
key: 'RecommendRate_100',
render: (v, r) => (
<>
<Space direction={'vertical'}>
<Text strong>
{v}
{r.RecommendRateDelta !== undefined && <Text type="secondary"> VS {r.CPRecommendRate_100}</Text>}
</Text>
{r.RecommendRateDelta !== undefined && <VSTag diffPercent={r.RecommendRateDelta} />}
</Space>
</>
),
},
],
};
return (
<>
<Row gutter={16} className={siderBroken ? '' : 'sticky-top'}>
<Col md={24} lg={24} xxl={24}>
<SearchForm
defaultValue={{
initialValue: {
...date_picker_store.formValues,
...HotelCruiseStore.searchValues,
},
// 'countryArea', 'DateType', 'dates',
shows: ['DepartmentList', 'countryArea', 'orderStatus', 'hotelBookType', 'hotelRecommandRate', 'hotelStar', 'DateType', 'dates'],
sort: { DateType: 101, dates: 102 },
fieldProps: {
DepartmentList: { show_all: true, mode: 'multiple' },
countryArea: { show_all: true },
orderStatus: { show_all: true },
hotelBookType: { show_all: true },
hotelRecommandRate: { show_all: true },
// years: { hide_vs: false },
DateType: { disabledKeys: ['applyDate'] },
},
}}
onSubmit={(_err, obj, form) => {
HotelCruiseStore.setSearchValues(obj, form);
HotelCruiseStore.getHotelData(obj);
}}
/>
</Col>
</Row>
<section>
<Table {...tableProps} bordered {...{ loading, dataSource }} rowKey={(record) => record.CityName} />
</section>
</>
);
});
Loading…
Cancel
Save