|
|
|
@ -1,102 +1,56 @@
|
|
|
|
|
import { createContext, useContext, useState } from 'react'
|
|
|
|
|
import { Flex, Button, Image, Divider, Typography, Empty, Skeleton, Row, Col, InputNumber, Form, DatePicker, Input } from 'antd'
|
|
|
|
|
import { createContext, useContext } from 'react'
|
|
|
|
|
import {
|
|
|
|
|
Flex,
|
|
|
|
|
Button,
|
|
|
|
|
Image,
|
|
|
|
|
Divider,
|
|
|
|
|
Typography,
|
|
|
|
|
Empty,
|
|
|
|
|
Skeleton,
|
|
|
|
|
Row,
|
|
|
|
|
Col,
|
|
|
|
|
} from 'antd'
|
|
|
|
|
|
|
|
|
|
const HotelContext = createContext()
|
|
|
|
|
|
|
|
|
|
export function SearchForm({ onSearch, onInit }) {
|
|
|
|
|
const [searchForm] = Form.useForm()
|
|
|
|
|
|
|
|
|
|
onInit(searchForm)
|
|
|
|
|
|
|
|
|
|
const handelFormFinish = () => {
|
|
|
|
|
const formValue = searchForm.getFieldValue()
|
|
|
|
|
// setSearchParams({
|
|
|
|
|
// hotel: formValue.hotelName,
|
|
|
|
|
// checkin: formValue.dataRange[0].format('YYYY-MM-DD'),
|
|
|
|
|
// checkout: formValue.dataRange[1].format('YYYY-MM-DD')
|
|
|
|
|
// })
|
|
|
|
|
|
|
|
|
|
onSearch(formValue)
|
|
|
|
|
|
|
|
|
|
// setLoading(true)
|
|
|
|
|
// searchByCriteria(formValue)
|
|
|
|
|
// .finally(() => setLoading(false))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<Form
|
|
|
|
|
name='searchForm'
|
|
|
|
|
form={searchForm}
|
|
|
|
|
layout='inline'
|
|
|
|
|
onFinish={handelFormFinish}
|
|
|
|
|
onFinishFailed={() => console.info('onFinishFailed')}
|
|
|
|
|
autoComplete='off'
|
|
|
|
|
>
|
|
|
|
|
<Form.Item
|
|
|
|
|
label={'酒店名称'}
|
|
|
|
|
name='hotelName'
|
|
|
|
|
rules={[
|
|
|
|
|
{
|
|
|
|
|
required: true,
|
|
|
|
|
message: '必填',
|
|
|
|
|
},
|
|
|
|
|
]}
|
|
|
|
|
>
|
|
|
|
|
<Input placeholder={'不能为空'} />
|
|
|
|
|
</Form.Item>
|
|
|
|
|
<Form.Item
|
|
|
|
|
label={'入住时间'}
|
|
|
|
|
name='dataRange'
|
|
|
|
|
allowClear={false}
|
|
|
|
|
rules={[
|
|
|
|
|
{
|
|
|
|
|
required: true,
|
|
|
|
|
message: '必填',
|
|
|
|
|
},
|
|
|
|
|
]}
|
|
|
|
|
>
|
|
|
|
|
<DatePicker.RangePicker placeholder={['入住日期', '退房日期']} />
|
|
|
|
|
</Form.Item>
|
|
|
|
|
<Form.Item>
|
|
|
|
|
<Button type='primary' htmlType='submit'>搜索</Button>
|
|
|
|
|
</Form.Item>
|
|
|
|
|
</Form>
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function HotelList({ dataSource, loading, onChange }) {
|
|
|
|
|
|
|
|
|
|
if (dataSource && dataSource.length > 0) {
|
|
|
|
|
const itemList = dataSource.map((data, index) => {
|
|
|
|
|
return (
|
|
|
|
|
<>
|
|
|
|
|
<Skeleton active loading={loading} key={index}>
|
|
|
|
|
<Row gutter={16} className='rounded shadow-md hover:shadow-lg hover:shadow-gray-400 p-2 border-solid border border-gray-100'>
|
|
|
|
|
<Row
|
|
|
|
|
gutter={16}
|
|
|
|
|
className="rounded shadow-md hover:shadow-lg hover:shadow-gray-400 p-2 border-solid border border-gray-100"
|
|
|
|
|
>
|
|
|
|
|
<Col span={24}>
|
|
|
|
|
<Flex
|
|
|
|
|
vertical gap='small'
|
|
|
|
|
align='flex-start'
|
|
|
|
|
justify='flex-start'
|
|
|
|
|
vertical
|
|
|
|
|
gap="small"
|
|
|
|
|
align="flex-start"
|
|
|
|
|
justify="flex-start"
|
|
|
|
|
>
|
|
|
|
|
<Typography.Title level={5}>{data.hotel_name}</Typography.Title>
|
|
|
|
|
<Typography.Text type="secondary">
|
|
|
|
|
{data.address}
|
|
|
|
|
</Typography.Text>
|
|
|
|
|
<span>{data.base_price.Price ?? 0} 起</span>
|
|
|
|
|
<Button
|
|
|
|
|
size="small"
|
|
|
|
|
type="primary"
|
|
|
|
|
onClick={() => onChange(data)}
|
|
|
|
|
>
|
|
|
|
|
<Typography.Title level={5}>
|
|
|
|
|
{data.hotel_name}
|
|
|
|
|
</Typography.Title>
|
|
|
|
|
<Typography.Text type='secondary'>{data.address}</Typography.Text>
|
|
|
|
|
<span>{data.base_price.Price??0} 起</span>
|
|
|
|
|
<Button size='small' type='primary' onClick={() => onChange(data)}>
|
|
|
|
|
查看房型
|
|
|
|
|
</Button>
|
|
|
|
|
</Flex>
|
|
|
|
|
</Col>
|
|
|
|
|
</Row>
|
|
|
|
|
</Skeleton>
|
|
|
|
|
</>
|
|
|
|
|
)
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<HotelContext.Provider value={{ onChange }}>
|
|
|
|
|
<Flex vertical gap='small'>
|
|
|
|
|
<Flex vertical gap="small">
|
|
|
|
|
{itemList}
|
|
|
|
|
</Flex>
|
|
|
|
|
</HotelContext.Provider>
|
|
|
|
@ -107,23 +61,20 @@ export function HotelList({ dataSource, loading, onChange }) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function RoomList({ dataSource, loading, onChange }) {
|
|
|
|
|
|
|
|
|
|
const triggerChange = (changedValue) => {
|
|
|
|
|
onChange?.(
|
|
|
|
|
changedValue
|
|
|
|
|
)
|
|
|
|
|
onChange?.(changedValue)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (dataSource && dataSource.length > 0) {
|
|
|
|
|
const itemList = dataSource.map((room, index) => {
|
|
|
|
|
let roomImage = <Empty description={false}/>
|
|
|
|
|
let roomImage = <Empty description={false} />
|
|
|
|
|
if (room?.Images && room?.Images.length > 0) {
|
|
|
|
|
roomImage = <Image src={room?.Images[0].Url} />
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<Skeleton active loading={loading} key={index}>
|
|
|
|
|
<div className='rounded shadow-md hover:shadow-lg hover:shadow-gray-400 p-2 border-solid border border-gray-100'>
|
|
|
|
|
<div className="rounded shadow-md hover:shadow-lg hover:shadow-gray-400 p-2 border-solid border border-gray-100">
|
|
|
|
|
<Typography.Title level={5}>
|
|
|
|
|
{room.RoomName}, {room.BedTypeDesc}
|
|
|
|
|
</Typography.Title>
|
|
|
|
@ -131,17 +82,15 @@ export function RoomList({ dataSource, loading, onChange }) {
|
|
|
|
|
<Col span={4}>
|
|
|
|
|
<Flex vertical>
|
|
|
|
|
{roomImage}
|
|
|
|
|
<span>大小: {room.Area??0}m²</span>
|
|
|
|
|
<span>大小: {room.Area ?? 0}m²</span>
|
|
|
|
|
</Flex>
|
|
|
|
|
</Col>
|
|
|
|
|
<Col span={20}>
|
|
|
|
|
{
|
|
|
|
|
room.RatePlans.map((plan, index) => {
|
|
|
|
|
{room.RatePlans.map((plan, index) => {
|
|
|
|
|
return (
|
|
|
|
|
<PlanItem key={index} room={room} plan={plan}></PlanItem>
|
|
|
|
|
)
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
})}
|
|
|
|
|
</Col>
|
|
|
|
|
</Row>
|
|
|
|
|
</div>
|
|
|
|
@ -151,7 +100,7 @@ export function RoomList({ dataSource, loading, onChange }) {
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<HotelContext.Provider value={{ triggerChange }}>
|
|
|
|
|
<Flex gap='middle' vertical>
|
|
|
|
|
<Flex gap="middle" vertical>
|
|
|
|
|
{itemList}
|
|
|
|
|
</Flex>
|
|
|
|
|
</HotelContext.Provider>
|
|
|
|
@ -164,7 +113,8 @@ export function RoomList({ dataSource, loading, onChange }) {
|
|
|
|
|
const getMealDesc = (plan) => {
|
|
|
|
|
const type = plan.MealType
|
|
|
|
|
let desc = '未知'
|
|
|
|
|
if (type === 1) desc = '早' + plan.Breakfast + '中' + plan.Lunch + '晚' + plan.Dinner
|
|
|
|
|
if (type === 1)
|
|
|
|
|
desc = '早' + plan.Breakfast + '中' + plan.Lunch + '晚' + plan.Dinner
|
|
|
|
|
else if (type === 2) desc = '半包'
|
|
|
|
|
else if (type === 3) desc = '全包'
|
|
|
|
|
else if (type === 4) desc = '午/晚二选一'
|
|
|
|
@ -173,20 +123,30 @@ const getMealDesc = (plan) => {
|
|
|
|
|
return desc
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const PlanItem = ({room, plan}) => {
|
|
|
|
|
const PlanItem = ({ room, plan }) => {
|
|
|
|
|
const { triggerChange } = useContext(HotelContext)
|
|
|
|
|
return (
|
|
|
|
|
<>
|
|
|
|
|
<Row gutter={[16, 16]} className=' divide-y divide-slate-700'>
|
|
|
|
|
<Col span={6}><span>餐: {getMealDesc(plan)}</span></Col>
|
|
|
|
|
<Col span={6}><span>{plan.Cancelable ? plan.CancelRulesText.join(';') : plan.CancelableText}</span></Col>
|
|
|
|
|
<Row gutter={[16, 16]} className=" divide-y divide-slate-700">
|
|
|
|
|
<Col span={6}>
|
|
|
|
|
<span>餐: {getMealDesc(plan)}</span>
|
|
|
|
|
</Col>
|
|
|
|
|
<Col span={6}>
|
|
|
|
|
<span>
|
|
|
|
|
{plan.Cancelable
|
|
|
|
|
? plan.CancelRulesText.join(';')
|
|
|
|
|
: plan.CancelableText}
|
|
|
|
|
</span>
|
|
|
|
|
</Col>
|
|
|
|
|
<Col span={6}>
|
|
|
|
|
<b>{plan.PriceUnit}</b>
|
|
|
|
|
<small>{plan.Currency}</small>
|
|
|
|
|
</Col>
|
|
|
|
|
<Col span={4}><Button size='small' onClick={() => triggerChange({room, plan})}>
|
|
|
|
|
<Col span={4}>
|
|
|
|
|
<Button size="small" onClick={() => triggerChange({ room, plan })}>
|
|
|
|
|
选他
|
|
|
|
|
</Button></Col>
|
|
|
|
|
</Button>
|
|
|
|
|
</Col>
|
|
|
|
|
</Row>
|
|
|
|
|
<Divider />
|
|
|
|
|
</>
|
|
|
|
|