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", "name": "global-highlights-hub",
"private": true, "private": true,
"version": "2.0.0-alpha.2", "version": "2.0.0-alpha.3",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "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',element:<RequireAuth subject={PERM_OVERSEA} result={true}><InvoicePaid /></RequireAuth>},
{ path: 'invoice/paid/detail/:flid', element: <RequireAuth subject={PERM_OVERSEA} result={true}><InvoicePaidDetail /></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',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",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/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>}, { 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 { create } from "zustand";
import { fetchJSON } from "@/utils/request"; import { fetchJSON, postForm } from "@/utils/request";
import { prepareUrl, isNotEmpty } from "@/utils/commons"; import { prepareUrl, isNotEmpty } from "@/utils/commons";
import { HT_HOST, DATE_FORMAT } from "@/config"; import { HT_HOST, DATE_FORMAT } from "@/config";
import dayjs from "dayjs"; import dayjs from "dayjs";
@ -15,7 +15,7 @@ const airTicketStore = create((set, get) => ({
const { setLoading, setPlanList } = get(); const { setLoading, setPlanList } = get();
setLoading(true); setLoading(true);
const searchParams = { const searchParams = {
vei_sn: 4272, //vei_sn, vei_sn: vei_sn,
FlightDate1: TimeStart, FlightDate1: TimeStart,
FlightDate2: TimeEnd, FlightDate2: TimeEnd,
GRI_Name: GRI_Name, GRI_Name: GRI_Name,
@ -30,23 +30,53 @@ const airTicketStore = create((set, get) => ({
async getPlanDetail(vei_sn, gri_sn) { async getPlanDetail(vei_sn, gri_sn) {
const { setPlanDetail } = get(); const { setPlanDetail } = get();
const searchParams = { const searchParams = {
vei_sn: 4272, //vei_sn, vei_sn: vei_sn,
gri_sn: 372928, //gri_sn gri_sn: gri_sn,
}; };
const { errcode, result } = await fetchJSON(`${HT_HOST}/Service_BaseInfoWeb/GetFlightPlanDetail`, searchParams); const { errcode, result } = await fetchJSON(`${HT_HOST}/Service_BaseInfoWeb/GetFlightPlanDetail`, searchParams);
const _result = errcode !== 0 ? [] : result; const _result = errcode !== 0 ? [] : result;
setPlanDetail(_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) { async getGuestList(coli_sn) {
const { setGuestList } = get(); const { setGuestList } = get();
const searchParams = { const searchParams = {
COLI_SN: 1097829, //coli_sn, COLI_SN: coli_sn,
}; };
const { errcode, result } = await fetchJSON(`${HT_HOST}/Service_BaseInfoWeb/GetFlightGuestInfo`, searchParams); const { errcode, result } = await fetchJSON(`${HT_HOST}/Service_BaseInfoWeb/GetFlightGuestInfo`, searchParams);
const _result = errcode !== 0 ? [] : result; const _result = errcode !== 0 ? [] : result;
setGuestList(_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; export default airTicketStore;

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

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

@ -46,33 +46,33 @@ const planListColumns = [
dataIndex: "ToCity", dataIndex: "ToCity",
}, },
{ {
title: "航", title: "航",
key: "FlightNo", key: "FlightNo",
dataIndex: "FlightNo", dataIndex: "FlightNo",
}, },
{ {
title: "起飞时间", title: "起飞时间",
key: "FlightTimeStart", key: "FlightStart",
dataIndex: "FlightTimeStart", dataIndex: "FlightStart",
render: text => formatColonTime(text), render: text => formatColonTime(text),
}, },
{ {
title: "落地时间", title: "落地时间",
key: "FlightTimeEnd", key: "FlightEnd",
dataIndex: "FlightTimeEnd", dataIndex: "FlightEnd",
render: text => formatColonTime(text), render: text => formatColonTime(text),
}, },
{ {
title: "是否出票", title: "是否出票",
key: "COLD_PlanVEI_SN", key: "CLF_SN",
dataIndex: "COLD_PlanVEI_SN", dataIndex: "CLF_SN",
render: (text, record) => "否", render: (text, record) => "否",
}, },
{ {
title: "操作", title: "操作",
key: "FlightInfo", key: "FlightInfo",
dataIndex: "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 { useState, useEffect } from "react";
import { Grid, Divider, Layout, Modal, Form, Input, Col, Row, Space, Collapse, Table, Button, Select, InputNumber, Typography } from "antd"; import { Grid, Divider, Layout, Modal, Form, Input, Col, Row, Space, Collapse, Table, Button, Select, App, Typography } from "antd";
import { PhoneOutlined, CustomerServiceOutlined, AudioOutlined, ArrowUpOutlined, ArrowDownOutlined } from "@ant-design/icons"; import { PhoneOutlined, FrownTwoTone, LikeTwoTone, ArrowUpOutlined, ArrowDownOutlined } from "@ant-design/icons";
import { useParams, useHref, useNavigate, NavLink } from "react-router-dom"; import { useParams, useHref, useNavigate, NavLink } from "react-router-dom";
import { isEmpty, formatColonTime } from "@/utils/commons"; import { isEmpty, formatColonTime } from "@/utils/commons";
import { OFFICEWEBVIEWERURL } from "@/config"; import { OFFICEWEBVIEWERURL } from "@/config";
@ -9,12 +9,21 @@ import airTicketStore from "@/stores/Airticket";
import { usingStorage } from "@/hooks/usingStorage"; import { usingStorage } from "@/hooks/usingStorage";
const AirticketPlan = props => { const AirticketPlan = props => {
const { coli_sn } = useParams(); const { coli_sn, gri_sn } = useParams();
const { travelAgencyId, loginToken } = usingStorage(); 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 reservationUrl = `https://p9axztuwd7x8a7.mycht.cn/Service_BaseInfoWeb/FlightPlanDocx?GRI_SN=${coli_sn}&VEI_SN=${travelAgencyId}`;
const reservationPreviewUrl = OFFICEWEBVIEWERURL + encodeURIComponent(reservationUrl); const reservationPreviewUrl = OFFICEWEBVIEWERURL + encodeURIComponent(reservationUrl);
const [form] = Form.useForm();
const { notification } = App.useApp();
//console.log(reservationPreviewUrl); //console.log(reservationPreviewUrl);
// //
@ -98,61 +107,163 @@ 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 Airticket_form = props => {
const aitInfo = props.airInfo; const airInfo = props.airInfo;
return ( return (
<> <>
<Row>
<Col md={4} lg={4} xxl={4}></Col>
<Col md={16} lg={16} xxl={16}>
<Form <Form
component={false} name={"ticket_form_" + airInfo.id}
name={"ticket_form_" + aitInfo.id}
labelCol={{ labelCol={{
span: 8, span: 6,
}} }}
wrapperCol={{ wrapperCol={{
span: 16, span: 16,
}} }}
style={{ initialValues={airInfo}
maxWidth: 600, onFinish={values => {
}} postFlightDetail(airInfo.CLF_SN, airInfo.GRI_SN, airInfo.VEI_SN, airInfo, values)
initialValues={{ .then(() => {
remember: true, notification.success({
message: `成功`,
description: "机票信息保存成功!",
placement: "top",
duration: 4,
icon: <LikeTwoTone />,
});
})
.catch(() => {
notification.error({
message: `错误`,
description: "保存失败",
placement: "top",
duration: 4,
icon: <FrownTwoTone />,
});
});
}} }}
// onFinish={onFinish}
// onFinishFailed={onFinishFailed}
autoComplete="off"> autoComplete="off">
<Form.Item label="城市" name="password" rules={[{ required: true }]}> <Form.Item label="城市">
<Space.Compact> <Space>
<Input placeholder="出发" prefix={<ArrowUpOutlined />} value={aitInfo.FromCity} /> <Form.Item name="FromCity" noStyle>
<Input placeholder="抵达" prefix={<ArrowDownOutlined />} value={aitInfo.ToCity} /> <Input placeholder="出发" prefix={<ArrowUpOutlined />} />
</Space.Compact> </Form.Item>
<Form.Item name="ToCity" noStyle>
<Input placeholder="抵达" prefix={<ArrowDownOutlined />} />
</Form.Item>
</Space>
</Form.Item> </Form.Item>
<Form.Item label="日期和航班" name="username" rules={[{ required: true }]}>
<Space.Compact> <Form.Item label="出发日期、航司、航班">
<Input value={aitInfo.StartDate} /> <Space>
<Form.Item name="StartDate" noStyle>
<Input placeholder="出发日期" />
</Form.Item>
<Form.Item name="FlightCompany" noStyle>
<Input placeholder="航空公司" /> <Input placeholder="航空公司" />
<Input placeholder="航班号" value={aitInfo.FlightNo} />
</Space.Compact>
</Form.Item> </Form.Item>
<Form.Item label="出发" name="password" rules={[{ required: true }]}> <Form.Item name="FlightNo" noStyle>
<Space.Compact> <Input placeholder="航班号" />
</Form.Item>
</Space>
</Form.Item>
<Form.Item label="出发">
<Space>
<Form.Item name="FromAirport" noStyle>
<Input placeholder="机场" /> <Input placeholder="机场" />
</Form.Item>
<Form.Item name="FromTerminal" noStyle>
<Input placeholder="航站楼" /> <Input placeholder="航站楼" />
<Input placeholder="出发时间" value={formatColonTime(aitInfo.FlightTimeStart)} />
</Space.Compact>
</Form.Item> </Form.Item>
<Form.Item label="抵达" name="password" rules={[{ required: true }]}> <Form.Item name="FlightStart" noStyle>
<Space.Compact> <Input placeholder="出发时间" />
</Form.Item>
</Space>
</Form.Item>
<Form.Item label="抵达">
<Space>
<Form.Item name="ToAirport" noStyle>
<Input placeholder="机场" /> <Input placeholder="机场" />
</Form.Item>
<Form.Item name="ToTerminal" noStyle>
<Input placeholder="航站楼" /> <Input placeholder="航站楼" />
<Input placeholder="抵达时间" value={formatColonTime(aitInfo.FlightTimeEnd)} />
</Space.Compact>
</Form.Item> </Form.Item>
<Form.Item label="仓位和行李" name="password"> <Form.Item name="FlightEnd" noStyle>
<Space.Compact> <Input placeholder="抵达时间" />
</Form.Item>
</Space>
</Form.Item>
<Form.Item label="仓位和行李">
<Space>
<Form.Item name="FlightCabin" noStyle>
<Input placeholder="仓位" /> <Input placeholder="仓位" />
<Input placeholder="行李" />
</Space.Compact>
</Form.Item> </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>
<Form.Item <Form.Item
wrapperCol={{ wrapperCol={{
offset: 14, offset: 14,
@ -162,15 +273,19 @@ const AirticketPlan = props => {
<Button type="primary" htmlType="submit"> <Button type="primary" htmlType="submit">
保存机票信息 保存机票信息
</Button> </Button>
<Button type="dashed" htmlType="submit"> <Button type="dashed">添加出票信息和费用</Button>
添加出票信息和费用
</Button>
</Space> </Space>
</Form.Item> </Form.Item>
<Divider orientation="left">费用列表</Divider>
<Table bordered={true} rowKey="id" columns={guestListColumns} dataSource={guestList} loading={loading} pagination={false} />
</Form> </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 => { ? planDetail.map(item => {
return { return {
key: item.id, key: item.id,
label: `${item.StartDate} 计划: ${item.FlightInfo}`, label: `${item.StartDate}`,
children: <Airticket_form airInfo={item} />, children: <Airticket_form airInfo={item} />,
}; };
}) })
@ -222,7 +337,7 @@ const AirticketPlan = props => {
const TicketModal = () => { const TicketModal = () => {
return ( return (
<> <>
<Modal title="Basic Modal" open={isModalOpen} onOk={handleOk} onCancel={handleCancel}> <Modal title="费用信息" open={isModalOpen} onOk={handleOk} onCancel={handleCancel}>
<Form <Form
form={ticket_form} form={ticket_form}
labelCol={{ labelCol={{
@ -329,9 +444,8 @@ const AirticketPlan = props => {
// end // end
useEffect(() => { useEffect(() => {
getPlanDetail(travelAgencyId, coli_sn); getPlanDetail(travelAgencyId, gri_sn);
getGuestList(travelAgencyId, coli_sn); getGuestList(travelAgencyId, coli_sn);
console.log(detail_items());
}, []); }, []);
return ( return (

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

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

Loading…
Cancel
Save