Merge remote-tracking branch 'origin/main'

# Conflicts:
#	src/views/products/Detail.jsx
perf/export-docx
Lei OT 1 year ago
commit 6f761a233e

@ -1,7 +1,7 @@
{
"name": "global-highlights-hub",
"private": true,
"version": "2.0.0-alpha.2",
"version": "2.0.0-alpha.3",
"type": "module",
"scripts": {
"dev": "vite",

@ -0,0 +1 @@
npm version prerelease

@ -68,7 +68,7 @@ const initRouter = async () => {
{ path: 'invoice/paid',element:<RequireAuth subject={PERM_OVERSEA} result={true}><InvoicePaid /></RequireAuth>},
{ path: 'invoice/paid/detail/:flid', element: <RequireAuth subject={PERM_OVERSEA} result={true}><InvoicePaidDetail /></RequireAuth>},
{ path: 'airticket',element: <RequireAuth subject={PERM_AIR_TICKET} result={true}><Airticket /></RequireAuth>},
{ path: 'airticket/plan/:coli_sn',element:<RequireAuth subject={PERM_AIR_TICKET} result={true}><AirticketPlan /></RequireAuth>},
{ path: 'airticket/plan/:coli_sn/:gri_sn',element:<RequireAuth subject={PERM_AIR_TICKET} result={true}><AirticketPlan /></RequireAuth>},
{ path: "products",element: <RequireAuth subject={PERM_PRODUCTS_MANAGEMENT} result={true}><ProductsManage /></RequireAuth>},
{ path: "products/:travel_agency_id/:use_year/:audit_state/audit",element:<RequireAuth subject={PERM_PRODUCTS_MANAGEMENT} result={true}><ProductsAudit /></RequireAuth>},
{ path: "products/:travel_agency_id/:use_year/:audit_state/edit",element:<RequireAuth subject={PERM_PRODUCTS_OFFER_PUT} result={true}><ProductsDetail /></RequireAuth>},

@ -1,5 +1,5 @@
import { create } from "zustand";
import { fetchJSON } from "@/utils/request";
import { fetchJSON, postForm } from "@/utils/request";
import { prepareUrl, isNotEmpty } from "@/utils/commons";
import { HT_HOST, DATE_FORMAT } from "@/config";
import dayjs from "dayjs";
@ -15,7 +15,7 @@ const airTicketStore = create((set, get) => ({
const { setLoading, setPlanList } = get();
setLoading(true);
const searchParams = {
vei_sn: 4272, //vei_sn,
vei_sn: vei_sn,
FlightDate1: TimeStart,
FlightDate2: TimeEnd,
GRI_Name: GRI_Name,
@ -30,23 +30,53 @@ const airTicketStore = create((set, get) => ({
async getPlanDetail(vei_sn, gri_sn) {
const { setPlanDetail } = get();
const searchParams = {
vei_sn: 4272, //vei_sn,
gri_sn: 372928, //gri_sn
vei_sn: vei_sn,
gri_sn: gri_sn,
};
const { errcode, result } = await fetchJSON(`${HT_HOST}/Service_BaseInfoWeb/GetFlightPlanDetail`, searchParams);
const _result = errcode !== 0 ? [] : result;
setPlanDetail(_result);
},
async postFlightDetail(CLF_SN, GRI_SN, VEI_SN, original_values, info_object) {
const formData = new FormData();
formData.append("CLF_SN", CLF_SN ? CLF_SN : "");
formData.append("GRI_SN", GRI_SN);
formData.append("VEI_SN", VEI_SN);
for (const [key, value] of Object.entries(original_values)) {
formData.append(key, value); //先用原始数据填充一遍,确保复制了全部数据到新表
}
for (const [key, value] of Object.entries(info_object)) {
formData.set(key, value); //再用新值覆盖
}
const postUrl = HT_HOST + "/Service_BaseInfoWeb/edit_or_new_flight_info";
return postForm(postUrl, formData).then(json => {
if (json.errcode == 0) {
return json;
} else {
throw new Error(json.errmsg + ": " + json.errcode);
}
});
},
async getGuestList(coli_sn) {
const { setGuestList } = get();
const searchParams = {
COLI_SN: 1097829, //coli_sn,
COLI_SN: coli_sn,
};
const { errcode, result } = await fetchJSON(`${HT_HOST}/Service_BaseInfoWeb/GetFlightGuestInfo`, searchParams);
const _result = errcode !== 0 ? [] : result;
setGuestList(_result);
},
// async getFlightCostList(CLF_SN) {
// const searchParams = {
// CLF_SN: CLF_SN,
// };
// const { errcode, result } = await fetchJSON(`${HT_HOST}/Service_BaseInfoWeb/Get_flight_cost`, searchParams);
// const _result = errcode !== 0 ? [] : result;
// console.log(_result);
// return _result;
// },
}));
export default airTicketStore;

@ -43,7 +43,7 @@ async function fetchLastRequet() {
const initialState = {
tokenInterval: null,
tokenTimeout: true,
tokenTimeout: false,// 开发时候用false正式环境true,
loginStatus: 0,
defaltRoute: '',
currentUser: {

@ -356,7 +356,6 @@ function Management() {
showSizeChanger: true,
showTotal: (total) => { return t('Total') + `${total}` }
}}
onChange={(pagination) => { onSearchClick(pagination.current) }}
columns={accountListColumns} dataSource={accountList}
/>
</Col>

@ -46,33 +46,33 @@ const planListColumns = [
dataIndex: "ToCity",
},
{
title: "航",
title: "航",
key: "FlightNo",
dataIndex: "FlightNo",
},
{
title: "起飞时间",
key: "FlightTimeStart",
dataIndex: "FlightTimeStart",
key: "FlightStart",
dataIndex: "FlightStart",
render: text => formatColonTime(text),
},
{
title: "落地时间",
key: "FlightTimeEnd",
dataIndex: "FlightTimeEnd",
key: "FlightEnd",
dataIndex: "FlightEnd",
render: text => formatColonTime(text),
},
{
title: "是否出票",
key: "COLD_PlanVEI_SN",
dataIndex: "COLD_PlanVEI_SN",
key: "CLF_SN",
dataIndex: "CLF_SN",
render: (text, record) => "否",
},
{
title: "操作",
key: "FlightInfo",
dataIndex: "FlightInfo",
render: (text, record) => <NavLink to={`/airticket/plan/${record.COLI_SN}`}>{"编辑"}</NavLink>,
render: (text, record) => <NavLink to={`/airticket/plan/${record.COLI_SN}/${record.GRI_SN}`}>{"编辑"}</NavLink>,
},
];

@ -1,6 +1,6 @@
import { useState, useEffect } from "react";
import { Grid, Divider, Layout, Modal, Form, Input, Col, Row, Space, Collapse, Table, Button, Select, InputNumber, Typography } from "antd";
import { PhoneOutlined, CustomerServiceOutlined, AudioOutlined, ArrowUpOutlined, ArrowDownOutlined } from "@ant-design/icons";
import { Grid, Divider, Layout, Modal, Form, Input, Col, Row, Space, Collapse, Table, Button, Select, App, Typography } from "antd";
import { PhoneOutlined, FrownTwoTone, LikeTwoTone, ArrowUpOutlined, ArrowDownOutlined } from "@ant-design/icons";
import { useParams, useHref, useNavigate, NavLink } from "react-router-dom";
import { isEmpty, formatColonTime } from "@/utils/commons";
import { OFFICEWEBVIEWERURL } from "@/config";
@ -9,13 +9,22 @@ import airTicketStore from "@/stores/Airticket";
import { usingStorage } from "@/hooks/usingStorage";
const AirticketPlan = props => {
const { coli_sn } = useParams();
const { coli_sn, gri_sn } = useParams();
const { travelAgencyId, loginToken } = usingStorage();
const [getPlanDetail, planDetail, getGuestList, guestList, loading] = airTicketStore(state => [state.getPlanDetail, state.planDetail, state.getGuestList, state.guestList, state.loading]);
const [getPlanDetail, planDetail, getGuestList, guestList, loading, postFlightDetail, getFlightCostList] = airTicketStore(state => [
state.getPlanDetail,
state.planDetail,
state.getGuestList,
state.guestList,
state.loading,
state.postFlightDetail,
state.getFlightCostList,
]);
const reservationUrl = `https://p9axztuwd7x8a7.mycht.cn/Service_BaseInfoWeb/FlightPlanDocx?GRI_SN=${coli_sn}&VEI_SN=${travelAgencyId}`;
const reservationPreviewUrl = OFFICEWEBVIEWERURL + encodeURIComponent(reservationUrl);
// console.log(reservationPreviewUrl);
const [form] = Form.useForm();
const { notification } = App.useApp();
//console.log(reservationPreviewUrl);
//
const guestListColumns = [
@ -98,79 +107,185 @@ const AirticketPlan = props => {
},
];
//
const costListColumns = [
{
title: "费用类型",
key: "CostType",
dataIndex: "CostType",
},
{
title: "金额",
key: "Cost",
dataIndex: "Cost",
},
{
title: "PNR",
key: "PNR",
dataIndex: "PNR",
},
{
title: "FlightCost",
key: "FlightCost",
dataIndex: "FlightCost",
},
{
title: "Discount",
key: "Discount",
dataIndex: "Discount",
},
{
title: "ServiceFee",
key: "ServiceFee",
dataIndex: "ServiceFee",
},
{
title: "DateTime",
key: "DateTime",
dataIndex: "DateTime",
},
{
title: "FlightType",
key: "FlightType",
dataIndex: "FlightType",
},
{
title: "Memo",
key: "Memo",
dataIndex: "Memo",
},
{
title: "编辑",
key: "CLF_SN",
dataIndex: "CLF_SN", //GRI_SN VEI_SN
},
];
const Airticket_form = props => {
const aitInfo = props.airInfo;
const airInfo = props.airInfo;
return (
<>
<Form
component={false}
name={"ticket_form_" + aitInfo.id}
labelCol={{
span: 8,
}}
wrapperCol={{
span: 16,
}}
style={{
maxWidth: 600,
}}
initialValues={{
remember: true,
}}
// onFinish={onFinish}
// onFinishFailed={onFinishFailed}
autoComplete="off">
<Form.Item label="城市" name="password" rules={[{ required: true }]}>
<Space.Compact>
<Input placeholder="出发" prefix={<ArrowUpOutlined />} value={aitInfo.FromCity} />
<Input placeholder="抵达" prefix={<ArrowDownOutlined />} value={aitInfo.ToCity} />
</Space.Compact>
</Form.Item>
<Form.Item label="日期和航班" name="username" rules={[{ required: true }]}>
<Space.Compact>
<Input value={aitInfo.StartDate} />
<Input placeholder="航空公司" />
<Input placeholder="航班号" value={aitInfo.FlightNo} />
</Space.Compact>
</Form.Item>
<Form.Item label="出发" name="password" rules={[{ required: true }]}>
<Space.Compact>
<Input placeholder="机场" />
<Input placeholder="航站楼" />
<Input placeholder="出发时间" value={formatColonTime(aitInfo.FlightTimeStart)} />
</Space.Compact>
</Form.Item>
<Form.Item label="抵达" name="password" rules={[{ required: true }]}>
<Space.Compact>
<Input placeholder="机场" />
<Input placeholder="航站楼" />
<Input placeholder="抵达时间" value={formatColonTime(aitInfo.FlightTimeEnd)} />
</Space.Compact>
</Form.Item>
<Form.Item label="仓位和行李" name="password">
<Space.Compact>
<Input placeholder="仓位" />
<Input placeholder="行李" />
</Space.Compact>
</Form.Item>
<Form.Item
wrapperCol={{
offset: 14,
span: 16,
}}>
<Space>
<Button type="primary" htmlType="submit">
保存机票信息
</Button>
<Button type="dashed" htmlType="submit">
添加出票信息和费用
</Button>
</Space>
</Form.Item>
<Row>
<Col md={4} lg={4} xxl={4}></Col>
<Col md={16} lg={16} xxl={16}>
<Form
name={"ticket_form_" + airInfo.id}
labelCol={{
span: 6,
}}
wrapperCol={{
span: 16,
}}
initialValues={airInfo}
onFinish={values => {
postFlightDetail(airInfo.CLF_SN, airInfo.GRI_SN, airInfo.VEI_SN, airInfo, values)
.then(() => {
notification.success({
message: `成功`,
description: "机票信息保存成功!",
placement: "top",
duration: 4,
icon: <LikeTwoTone />,
});
})
.catch(() => {
notification.error({
message: `错误`,
description: "保存失败",
placement: "top",
duration: 4,
icon: <FrownTwoTone />,
});
});
}}
autoComplete="off">
<Form.Item label="城市">
<Space>
<Form.Item name="FromCity" noStyle>
<Input placeholder="出发" prefix={<ArrowUpOutlined />} />
</Form.Item>
<Form.Item name="ToCity" noStyle>
<Input placeholder="抵达" prefix={<ArrowDownOutlined />} />
</Form.Item>
</Space>
</Form.Item>
<Form.Item label="出发日期、航司、航班">
<Space>
<Form.Item name="StartDate" noStyle>
<Input placeholder="出发日期" />
</Form.Item>
<Form.Item name="FlightCompany" noStyle>
<Input placeholder="航空公司" />
</Form.Item>
<Form.Item name="FlightNo" noStyle>
<Input placeholder="航班号" />
</Form.Item>
</Space>
</Form.Item>
<Form.Item label="出发">
<Space>
<Form.Item name="FromAirport" noStyle>
<Input placeholder="机场" />
</Form.Item>
<Form.Item name="FromTerminal" noStyle>
<Input placeholder="航站楼" />
</Form.Item>
<Form.Item name="FlightStart" noStyle>
<Input placeholder="出发时间" />
</Form.Item>
</Space>
</Form.Item>
<Form.Item label="抵达">
<Space>
<Form.Item name="ToAirport" noStyle>
<Input placeholder="机场" />
</Form.Item>
<Form.Item name="ToTerminal" noStyle>
<Input placeholder="航站楼" />
</Form.Item>
<Form.Item name="FlightEnd" noStyle>
<Input placeholder="抵达时间" />
</Form.Item>
</Space>
</Form.Item>
<Form.Item label="仓位和行李">
<Space>
<Form.Item name="FlightCabin" noStyle>
<Input placeholder="仓位" />
</Form.Item>
<Form.Item name="Baggage" noStyle>
<Input placeholder="行李说明" />
</Form.Item>
</Space>
</Form.Item>
<Form.Item label="备注" name="FlightMemo">
<Input.TextArea rows={5} />
</Form.Item>
<Divider orientation="left">费用列表</Divider>
<Table bordered={true} rowKey="id" columns={guestListColumns} dataSource={guestList} loading={loading} pagination={false} />
</Form>
<Form.Item
wrapperCol={{
offset: 14,
span: 16,
}}>
<Space>
<Button type="primary" htmlType="submit">
保存机票信息
</Button>
<Button type="dashed">添加出票信息和费用</Button>
</Space>
</Form.Item>
</Form>
</Col>
<Col md={4} lg={4} xxl={4}></Col>
</Row>
<Row>
<Col md={24} lg={24} xxl={24}>
<Divider orientation="left">费用列表</Divider>
<Table bordered={true} rowKey="CLC_SN" columns={costListColumns} dataSource={airInfo.Flightcost_AsJOSN} loading={loading} pagination={false} />
</Col>
</Row>
</>
);
};
@ -180,7 +295,7 @@ const AirticketPlan = props => {
? planDetail.map(item => {
return {
key: item.id,
label: `${item.StartDate} 计划: ${item.FlightInfo}`,
label: `${item.StartDate}`,
children: <Airticket_form airInfo={item} />,
};
})
@ -222,7 +337,7 @@ const AirticketPlan = props => {
const TicketModal = () => {
return (
<>
<Modal title="Basic Modal" open={isModalOpen} onOk={handleOk} onCancel={handleCancel}>
<Modal title="费用信息" open={isModalOpen} onOk={handleOk} onCancel={handleCancel}>
<Form
form={ticket_form}
labelCol={{
@ -329,9 +444,8 @@ const AirticketPlan = props => {
// end
useEffect(() => {
getPlanDetail(travelAgencyId, coli_sn);
getPlanDetail(travelAgencyId, gri_sn);
getGuestList(travelAgencyId, coli_sn);
console.log(detail_items());
}, []);
return (

@ -1182,7 +1182,6 @@ function Detail() {
}
{
!isCanEditable &&
<Button onClick={handleBatchImport} type="primary" style={{ marginTop: 16, marginLeft: 16 }}>批量添加</Button>
}
</Form.Item>
@ -1229,11 +1228,11 @@ function Detail() {
</Flex>
<Modal
title="批量添加价格"
title='批量设置价格'
open={batchImportPriceVisible}
onOk={handleBatchImportOK}
onCancel={() => setBatchImportPriceVisible(false)}
width="80%"
width={'90%'}
>
<BatchImportPrice onBatchImportData={handleBatchImportData} />
</Modal>

@ -1,371 +1,366 @@
import React, { useState } from 'react';
import { Button, Card, Checkbox, Col, DatePicker, Form, Input, Row, Select, Space, Tag, Table, InputNumber } from 'antd';
import { CloseOutlined } from '@ant-design/icons';
import dayjs from 'dayjs';
import { useState } from 'react';
import { Button, Card, Checkbox, Table, Col, Flex, DatePicker, Typography, Form, Input, Row, Select, Space } from 'antd';
import dayjs from "dayjs";
import { useTranslation } from 'react-i18next';
import { CloseOutlined, StarOutlined } from '@ant-design/icons';
import { useDatePresets } from '@/hooks/useDatePresets';
const { Option } = Select;
const { RangePicker } = DatePicker;
const BatchImportPrice = ({ onBatchImportData }) => {
const [form] = Form.useForm();
const [tags, setTags] = useState([]);
const [minPeople, setMinPeople] = useState('');
const [maxPeople, setMaxPeople] = useState('');
const [checkedDays, setCheckedDays] = useState([]);
const [tableData, setTableData] = useState([]);
const [sendData, setSendData] = useState(null);
const presets = useDatePresets();
const { t } = useTranslation()
const handleTagClose = (removedTag) => {
setTags(tags.filter(tag => tag !== removedTag));
};
const handleInputConfirm = () => {
if (minPeople && maxPeople) {
const tag = `${minPeople}-${maxPeople}`;
if (tags.indexOf(tag) === -1) {
setTags([...tags, tag]);
}
}
setMinPeople('');
setMaxPeople('');
};
const handleCheckboxChange = (checkedValues) => {
setCheckedDays(checkedValues);
};
const generateTableData = () => {
const values = form.getFieldsValue();
const weekdays = checkedDays.join(',');
let tempSendData = [];
console.log("values",values)
// items
values.items.forEach((item, index) => {
// validPeriods
let tempValidPeriods = []
item.validPeriods?.forEach((period) => {
console.log("period",period)
const validPeriod = period.validPeriod.map(date => date.format('YYYY-MM-DD')).join('~');
tempValidPeriods.push(validPeriod)
// tempSendData tag
});
const priceType = `批量设置价格 ${index + 1} ${item.currency}/${item.type}`
let tempData = []
const unit_name = item.type
const currency = item.currency
tags.forEach((tag) => {
tempValidPeriods.forEach(validPeriod => {
const group_size_min = tag.split('-')[0]
const group_size_max = tag.split('-')[1]
let unit_id = null
const use_dates_start = validPeriod.split('~')[0]
const use_dates_end = validPeriod.split('~')[1]
if (unit_name === "每人") {
unit_id = 0
} else {
unit_id = 1
}
tempData.push({ group_size_min, group_size_max, validPeriod, unit_id, unit_name, use_dates_start, use_dates_end, currency, weekdays, tag, priceType })
});
})
console.log("tempData", tempData)
tempSendData.push(...tempData)
const previewTableColumns = [
{ title: t('products:adultPrice'), dataIndex: 'adult_cost', width: '10%' },
{ title: t('products:childrenPrice'), dataIndex: 'child_cost', width: '10%' },
{ title: t('products:currency'), dataIndex: 'currency', width: '10%' },
{
title: t('products:Types'),
dataIndex: 'unit',
width: '10%',
editable: true,
render: (text) => (text === '0' ? '每人' : text === '1' ? '每团' : text),
},
{
title: t('products:number'),
dataIndex: 'group_size',
width: '10%',
editable: true,
render: (_, record) => `${record.group_size_min}-${record.group_size_max}`
},
{
title: t('products:validityPeriod'),
dataIndex: 'validityPeriod',
width: '20%',
editable: true,
render: (_, record) => dayjs(record.use_dates_start).format('YYYY-MM-DD') + '~' + dayjs(record.use_dates_end).format('YYYY-MM-DD')
},
{ title: t('products:Weekdays'), dataIndex: 'weekdays', width: '10%' },
]
});
//
setSendData([...tempSendData]); // 使 setSendData
const data = [];
values.items.forEach((item, index) => {
item.validPeriods?.forEach((period, idx) => {
const row = {
key: `${index}-${idx}`,
priceType: `批量设置价格 ${index + 1} ${item.currency}/${item.type}`,
validPeriod: period.validPeriod.map(date => date.format('YYYY-MM-DD')).join('~'),
currency: item.currency,
type: item.type,
};
tags.forEach((tag, tagIndex) => {
row[`adultPrice${tagIndex + 1}`] = 0; // Initialize with 0
row[`childrenPrice${tagIndex + 1}`] = 0; // Initialize with 0
});
data.push(row);
});
});
// setSendData([...tempSendData,data]);
setTableData(data);
// onBatchImportData(data); //
};
const [priceForm] = Form.useForm()
const [previewData, setPreviewData] = useState([])
const presets = useDatePresets()
const previewSetupPrice = () => {
let previewList = []
const defList = priceForm.getFieldsValue().defList
defList.forEach(definition => {
const previewPrice = definition?.priceList.map(price => {
return {
adult_cost: price.priceInput.audultPrice,
child_cost: price.priceInput.childrenPrice,
group_size_min: price.priceInput.numberStart,
group_size_max: price.priceInput.numberEnd,
const handleTableChange = (age_type, value, tag, priceType) => {
if (age_type === 'adult_cost') {
console.log("sendData", sendData)
const updatedSendData = sendData.map((item) => {
console.log("item.priceType === priceType", item.priceType === priceType)
console.log("item.priceType", item.priceType)
console.log("priceType", priceType)
if (item.priceType === priceType && item.tag === tag) {
return {
...item,
adult_cost: value, // adult_cost
};
}
return item; //
});
// sendData
console.log("updatedSendData", updatedSendData)
onBatchImportData(updatedSendData);
setSendData(updatedSendData);
} else {
const updatedSendData = sendData.map((item) => {
if (item.priceType === priceType && item.tag === tag) {
return {
...item,
child_cost: value, // child_cost
};
}
return item; //
});
// sendData
onBatchImportData(updatedSendData);
setSendData(updatedSendData);
currency: definition.currency,
unit: definition.unitName,
use_dates_start: definition.useDate[0],
use_dates_end: definition.useDate[1],
weekdays: definition.weekend.join(','),
}
};
})
previewList.push(...previewPrice)
})
setPreviewData(previewList)
}
const generatePeopleColumns = () => {
const columns = [];
tags.forEach((tag, index) => {
columns.push({
title: tag,
children: [
{
title: '成人价',
dataIndex: `adultPrice${index + 1}`,
key: `adultPrice${index + 1}`,
render: (text, record, rowIndex) => {
const sameTagRecords = tableData.filter(item => item.priceType === record.priceType);
const firstTagIndex = tableData.findIndex(item => item.priceType === record.priceType && item.validPeriod === sameTagRecords[0].validPeriod);
if (rowIndex === firstTagIndex) {
return {
children: (
<InputNumber
formatter={value => `${value}`}
parser={value => value.replace(/[^\d]/g, '')}
onChange={(value) => handleTableChange('adult_cost', value, tag, record.priceType)}
/>
),
props: {
rowSpan: sameTagRecords.length,
},
};
} else {
return {
props: {
rowSpan: 0,
},
};
}
},
},
{
title: '儿童价',
dataIndex: `childrenPrice${index + 1}`,
key: `childrenPrice${index + 1}`,
render: (text, record, rowIndex) => {
const sameTagRecords = tableData.filter(item => item.priceType === record.priceType);
const firstTagIndex = tableData.findIndex(item => item.priceType === record.priceType && item.validPeriod === sameTagRecords[0].validPeriod);
if (rowIndex === firstTagIndex) {
return {
children: (
<InputNumber
formatter={value => `${value}`}
parser={value => value.replace(/[^\d]/g, '')}
onChange={(value) => handleTableChange('child_cost', value, tag, record.priceType)}
/>
),
props: {
rowSpan: sameTagRecords.length,
},
};
} else {
return {
props: {
rowSpan: 0,
},
};
}
},
}
]
});
});
return columns;
const PriceInput = (props) => {
const { id, value = {}, onChange } = props
const [numberStart, setNumberStart] = useState(0)
const [numberEnd, setNumberEnd] = useState(0)
const [audultPrice, setAudultPrice] = useState(0)
const [childrenPrice, setChildrenPrice] = useState(0)
const triggerChange = (changedValue) => {
onChange?.({
numberStart,
numberEnd,
audultPrice,
childrenPrice,
...value,
...changedValue,
})
}
const onNumberStartChange = (e) => {
const newNumber = parseInt(e.target.value || '0', 10)
if (Number.isNaN(numberStart)) {
return
}
if (!('numberStart' in value)) {
setNumberStart(newNumber);
}
triggerChange({
numberStart: newNumber,
})
}
const onNumberEndChange = (e) => {
const newNumber = parseInt(e.target.value || '0', 10)
if (Number.isNaN(numberEnd)) {
return
}
if (!('numberEnd' in value)) {
setNumberEnd(newNumber)
}
triggerChange({
numberEnd: newNumber,
});
};
const onAudultPriceChange = (e) => {
const newNumber = parseInt(e.target.value || '0', 10)
if (Number.isNaN(audultPrice)) {
return
}
if (!('audultPrice' in value)) {
setAudultPrice(newNumber)
}
triggerChange({
audultPrice: newNumber,
})
}
const onChildrenPriceChange = (e) => {
const newNumber = parseInt(e.target.value || '0', 10)
if (Number.isNaN(childrenPrice)) {
return
}
if (!('childrenPrice' in value)) {
setChildrenPrice(newNumber)
}
triggerChange({
childrenPrice: newNumber,
})
};
const columns = [
{
title: ' ',
dataIndex: 'priceType',
key: 'priceType',
width: "10%",
render: (text, record, index) => {
const obj = {
children: text,
props: {},
};
if (index > 0 && text === tableData[index - 1].priceType) {
obj.props.rowSpan = 0;
} else {
obj.props.rowSpan = tableData.filter(item => item.priceType === text).length;
}
return obj;
},
},
{
title: '有效期\\人等',
dataIndex: 'validPeriod',
key: 'validPeriod',
width: "15%"
},
...generatePeopleColumns(),
];
return (
<div>
<Card
size="small"
title="选择人等、周末"
style={{ marginBottom: 16 }}
>
<Row>
<Col>
<Input.Group compact style={{ marginTop: 10 }}>
<Input
style={{ width: 100, textAlign: 'center' }}
placeholder="Start"
value={minPeople}
onChange={(e) => setMinPeople(e.target.value)}
/>
<Input
style={{ width: 30, borderLeft: 0, pointerEvents: 'none', backgroundColor: '#fff' }}
placeholder="~"
disabled
/>
<Input
style={{ width: 100, textAlign: 'center', borderLeft: 0 }}
placeholder="End"
value={maxPeople}
onChange={(e) => setMaxPeople(e.target.value)}
/>
</Input.Group>
</Col>
<Col>
<Button size="small" type="primary" onClick={handleInputConfirm} style={{ marginLeft: 12, marginTop: 12 }}>
添加人等
</Button>
</Col>
</Row>
<div style={{ marginTop: 16 }}>
{tags.map((tag) => (
<Tag key={tag} closable onClose={() => handleTagClose(tag)}>
{tag}
</Tag>
))}
</div>
<Checkbox.Group
style={{ marginTop: 16 }}
options={['5', '6', '7']}
onChange={handleCheckboxChange}
/>
</Card>
<Space.Compact id={id}>
<Input
type="text"
value={value.numberStart || numberStart}
onChange={onNumberStartChange}
style={{
width: '20%',
}}
/>
<Input
type="text"
value={value.numberEnd || numberEnd}
onChange={onNumberEndChange}
style={{
width: '40%',
}}
addonBefore="~"
/>
<Input
type="text"
value={value.audultPrice || audultPrice}
onChange={onAudultPriceChange}
style={{
width: '70%',
}}
addonBefore="成人价"
/>
<Input
type="text"
value={value.childrenPrice || childrenPrice}
onChange={onChildrenPriceChange}
style={{
width: '70%',
}}
addonBefore="儿童价"
/>
</Space.Compact>
)
}
<Form
labelCol={{ span: 6 }}
wrapperCol={{ span: 18 }}
form={form}
name="dynamic_form_complex"
style={{ maxWidth: 600 }}
autoComplete="off"
initialValues={{ items: [{}] }}
>
<Form.List name="items">
{(fields, { add, remove }) => (
<div style={{ display: 'flex', rowGap: 16, flexDirection: 'column' }}>
{fields.map((field, index) => (
<Card
size="small"
title={`批量设置价格 ${index + 1}`}
key={field.key}
extra={<CloseOutlined onClick={() => remove(field.name)} />}
>
<Form.Item label="类型" name={[field.name, 'type']}>
<Select placeholder="选择类型">
<Option value="每人">每人</Option>
<Option value="每团">每团</Option>
</Select>
</Form.Item>
const priceInitialValues = {
"defList": [
//
{
"useDate": [
dayjs().add(1, 'year').startOf("y"), dayjs().add(1, 'year').endOf("y")
],
"unitName": "每人",
"currency": "CNY",
"weekend": [
"5",
"6"
],
"priceList": [
{
"priceInput": {
"numberStart": 1,
"numberEnd": 2,
"audultPrice": 0,
"childrenPrice": 0
}
},
{
"priceInput": {
"numberStart": 3,
"numberEnd": 4,
"audultPrice": 0,
"childrenPrice": 0
}
},
{
"priceInput": {
"numberStart": 5,
"numberEnd": 6,
"audultPrice": 0,
"childrenPrice": 0
}
},
{
"priceInput": {
"numberStart": 7,
"numberEnd": 9,
"audultPrice": 0,
"childrenPrice": 0
}
}
]
},
//
{
"useDate": [
dayjs().add(1, 'year').subtract(2, "M").startOf("M"), dayjs().add(1, 'year').endOf("M")
],
"unitName": "每人",
"currency": "CNY",
"weekend": [
"5",
"6"
],
"priceList": [
{
"priceInput": {
"numberStart": 1,
"numberEnd": 2,
"audultPrice": 0,
"childrenPrice": 0
}
},
{
"priceInput": {
"numberStart": 3,
"numberEnd": 4,
"audultPrice": 0,
"childrenPrice": 0
}
},
{
"priceInput": {
"numberStart": 5,
"numberEnd": 6,
"audultPrice": 0,
"childrenPrice": 0
}
},
{
"priceInput": {
"numberStart": 7,
"numberEnd": 9,
"audultPrice": 0,
"childrenPrice": 0
}
}
]
}
]
}
<Form.Item label="币种" name={[field.name, 'currency']}>
<Select placeholder="选择币种">
<Option value="CNY">CNY</Option>
<Option value="USD">USD</Option>
</Select>
</Form.Item>
return (
<Row gutter={16} justify="center">
<Col span={12}>
<Form
labelCol={{ span: 3 }}
wrapperCol={{ span: 20 }}
form={priceForm}
name="priceForm"
autoComplete="off"
initialValues={priceInitialValues}
>
<Form.List name="defList">
{(fields, { add, remove }) => (
<Flex gap="middle" vertical>
{fields.map((field, index) => (
<Card
size="small"
title={index==0?'旺季':index==1?'淡季':'其他'}
key={field.key}
extra={index==0?null:<CloseOutlined onClick={() => {
remove(field.name)
}} />}
>
<Form.Item label="类型" name={[field.name, 'unitName']}>
<Select placeholder="选择类型">
<Option value="每人">每人</Option>
<Option value="每团">每团</Option>
</Select>
</Form.Item>
<Form.Item label="有效期">
<Form.List name={[field.name, 'validPeriods']}>
{(periodFields, periodOpt) => (
<div style={{ display: 'flex', flexDirection: 'column', rowGap: 16 }}>
{periodFields.map((periodField, idx) => (
<Space key={periodField.key}>
<Form.Item noStyle name={[periodField.name, 'validPeriod']}>
<RangePicker allowClear={true} inputReadOnly={true} presets={presets} placeholder={['From', 'Thru']}/>
</Form.Item>
<CloseOutlined onClick={() => periodOpt.remove(periodField.name)} />
</Space>
))}
<Button type="dashed" onClick={() => periodOpt.add()} block>
+ 新增有效期
</Button>
</div>
)}
</Form.List>
</Form.Item>
</Card>
<Form.Item label="币种" name={[field.name, 'currency']}>
<Select placeholder="选择币种">
<Option value="CNY">CNY</Option>
<Option value="USD">USD</Option>
</Select>
</Form.Item>
<Form.Item label="有效期" name={[field.name, 'useDate']}>
<RangePicker style={{width: '100%'}} allowClear={true} inputReadOnly={true} presets={presets} placeholder={['From', 'Thru']} />
</Form.Item>
<Form.Item label="周末" name={[field.name, 'weekend']}>
<Checkbox.Group
options={['5', '6', '7']}
/>
</Form.Item>
<Form.Item label="人等">
<Form.List name={[field.name, 'priceList']}>
{(priceFieldList, priceOptList) => (
<Flex gap="middle" vertical>
{priceFieldList.map((priceField, index) => (
<Space key={priceField.key}>
<Form.Item noStyle name={[priceField.name, 'priceInput']}>
<PriceInput />
</Form.Item>
{index==0?<StarOutlined />:<CloseOutlined onClick={() => priceOptList.remove(priceField.name)} />}
</Space>
))}
<Button type="dashed" onClick={() => add()} block>
+ 新增价格设置
<Button type="dashed" onClick={() => priceOptList.add()} block>
+ 新增人等
</Button>
</div>
)}
</Form.List>
</Form>
<Button type="primary" onClick={generateTableData} style={{ marginTop: 20 }}>
生成表格
</Button>
{tableData.length > 0 && (
<div style={{ overflowX: 'auto' }}>
<Table
style={{ marginTop: 20 }}
columns={columns}
dataSource={tableData}
pagination={false}
/>
</div>
</Flex>
)}
</Form.List>
</Form.Item>
</Card>
))}
<Button type="dashed" onClick={() => add()} block>
+ 新增价格设置
</Button>
</Flex>
)}
</Form.List>
<Form.Item noStyle shouldUpdate>
{() => (
<Typography className='hidden'>
<pre>{JSON.stringify(priceForm.getFieldsValue(), null, 2)}</pre>
</Typography>
)}
</div>
);
</Form.Item>
</Form>
</Col>
<Col span={12}>
<Button type="dashed" onClick={() => previewSetupPrice()} block>
预览
</Button>
<Table
bordered
pagination={false}
dataSource={previewData}
columns={previewTableColumns}
/>
</Col>
</Row>
);
};
export default BatchImportPrice;

Loading…
Cancel
Save