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,13 +9,22 @@ 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();
// console.log(reservationPreviewUrl); const { notification } = App.useApp();
//console.log(reservationPreviewUrl);
// //
const guestListColumns = [ 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 Airticket_form = props => {
const aitInfo = props.airInfo; const airInfo = props.airInfo;
return ( return (
<> <>
<Form <Row>
component={false} <Col md={4} lg={4} xxl={4}></Col>
name={"ticket_form_" + aitInfo.id} <Col md={16} lg={16} xxl={16}>
labelCol={{ <Form
span: 8, name={"ticket_form_" + airInfo.id}
}} labelCol={{
wrapperCol={{ span: 6,
span: 16, }}
}} wrapperCol={{
style={{ span: 16,
maxWidth: 600, }}
}} initialValues={airInfo}
initialValues={{ onFinish={values => {
remember: true, postFlightDetail(airInfo.CLF_SN, airInfo.GRI_SN, airInfo.VEI_SN, airInfo, values)
}} .then(() => {
// onFinish={onFinish} notification.success({
// onFinishFailed={onFinishFailed} message: `成功`,
autoComplete="off"> description: "机票信息保存成功!",
<Form.Item label="城市" name="password" rules={[{ required: true }]}> placement: "top",
<Space.Compact> duration: 4,
<Input placeholder="出发" prefix={<ArrowUpOutlined />} value={aitInfo.FromCity} /> icon: <LikeTwoTone />,
<Input placeholder="抵达" prefix={<ArrowDownOutlined />} value={aitInfo.ToCity} /> });
</Space.Compact> })
</Form.Item> .catch(() => {
<Form.Item label="日期和航班" name="username" rules={[{ required: true }]}> notification.error({
<Space.Compact> message: `错误`,
<Input value={aitInfo.StartDate} /> description: "保存失败",
<Input placeholder="航空公司" /> placement: "top",
<Input placeholder="航班号" value={aitInfo.FlightNo} /> duration: 4,
</Space.Compact> icon: <FrownTwoTone />,
</Form.Item> });
<Form.Item label="出发" name="password" rules={[{ required: true }]}> });
<Space.Compact> }}
<Input placeholder="机场" /> autoComplete="off">
<Input placeholder="航站楼" /> <Form.Item label="城市">
<Input placeholder="出发时间" value={formatColonTime(aitInfo.FlightTimeStart)} /> <Space>
</Space.Compact> <Form.Item name="FromCity" noStyle>
</Form.Item> <Input placeholder="出发" prefix={<ArrowUpOutlined />} />
<Form.Item label="抵达" name="password" rules={[{ required: true }]}> </Form.Item>
<Space.Compact> <Form.Item name="ToCity" noStyle>
<Input placeholder="机场" /> <Input placeholder="抵达" prefix={<ArrowDownOutlined />} />
<Input placeholder="航站楼" /> </Form.Item>
<Input placeholder="抵达时间" value={formatColonTime(aitInfo.FlightTimeEnd)} /> </Space>
</Space.Compact> </Form.Item>
</Form.Item>
<Form.Item label="仓位和行李" name="password"> <Form.Item label="出发日期、航司、航班">
<Space.Compact> <Space>
<Input placeholder="仓位" /> <Form.Item name="StartDate" noStyle>
<Input placeholder="行李" /> <Input placeholder="出发日期" />
</Space.Compact> </Form.Item>
</Form.Item> <Form.Item name="FlightCompany" noStyle>
<Form.Item <Input placeholder="航空公司" />
wrapperCol={{ </Form.Item>
offset: 14, <Form.Item name="FlightNo" noStyle>
span: 16, <Input placeholder="航班号" />
}}> </Form.Item>
<Space> </Space>
<Button type="primary" htmlType="submit"> </Form.Item>
保存机票信息 <Form.Item label="出发">
</Button> <Space>
<Button type="dashed" htmlType="submit"> <Form.Item name="FromAirport" noStyle>
添加出票信息和费用 <Input placeholder="机场" />
</Button> </Form.Item>
</Space> <Form.Item name="FromTerminal" noStyle>
</Form.Item> <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> <Form.Item
<Table bordered={true} rowKey="id" columns={guestListColumns} dataSource={guestList} loading={loading} pagination={false} /> wrapperCol={{
</Form> 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 => { ? 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,371 +1,366 @@
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%' },
const handleInputConfirm = () => { {
if (minPeople && maxPeople) { title: t('products:Types'),
const tag = `${minPeople}-${maxPeople}`; dataIndex: 'unit',
if (tags.indexOf(tag) === -1) { width: '10%',
setTags([...tags, tag]); editable: true,
} render: (text) => (text === '0' ? '每人' : text === '1' ? '每团' : text),
} },
setMinPeople(''); {
setMaxPeople(''); title: t('products:number'),
}; dataIndex: 'group_size',
width: '10%',
const handleCheckboxChange = (checkedValues) => { editable: true,
setCheckedDays(checkedValues); render: (_, record) => `${record.group_size_min}-${record.group_size_max}`
}; },
{
const generateTableData = () => { title: t('products:validityPeriod'),
const values = form.getFieldsValue(); dataIndex: 'validityPeriod',
const weekdays = checkedDays.join(','); width: '20%',
let tempSendData = []; editable: true,
console.log("values",values) render: (_, record) => dayjs(record.use_dates_start).format('YYYY-MM-DD') + '~' + dayjs(record.use_dates_end).format('YYYY-MM-DD')
// items },
values.items.forEach((item, index) => { { title: t('products:Weekdays'), dataIndex: 'weekdays', width: '10%' },
// 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 [priceForm] = Form.useForm()
const [previewData, setPreviewData] = useState([])
// const presets = useDatePresets()
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 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) => { currency: definition.currency,
if (age_type === 'adult_cost') { unit: definition.unitName,
console.log("sendData", sendData) use_dates_start: definition.useDate[0],
const updatedSendData = sendData.map((item) => { use_dates_end: definition.useDate[1],
console.log("item.priceType === priceType", item.priceType === priceType) weekdays: definition.weekend.join(','),
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);
} }
}; })
previewList.push(...previewPrice)
})
setPreviewData(previewList)
}
const generatePeopleColumns = () => { const PriceInput = (props) => {
const columns = []; const { id, value = {}, onChange } = props
tags.forEach((tag, index) => { const [numberStart, setNumberStart] = useState(0)
columns.push({ const [numberEnd, setNumberEnd] = useState(0)
title: tag, const [audultPrice, setAudultPrice] = useState(0)
children: [ const [childrenPrice, setChildrenPrice] = useState(0)
{ const triggerChange = (changedValue) => {
title: '成人价', onChange?.({
dataIndex: `adultPrice${index + 1}`, numberStart,
key: `adultPrice${index + 1}`, numberEnd,
render: (text, record, rowIndex) => { audultPrice,
const sameTagRecords = tableData.filter(item => item.priceType === record.priceType); childrenPrice,
const firstTagIndex = tableData.findIndex(item => item.priceType === record.priceType && item.validPeriod === sameTagRecords[0].validPeriod); ...value,
...changedValue,
if (rowIndex === firstTagIndex) { })
return { }
children: ( const onNumberStartChange = (e) => {
<InputNumber const newNumber = parseInt(e.target.value || '0', 10)
formatter={value => `${value}`} if (Number.isNaN(numberStart)) {
parser={value => value.replace(/[^\d]/g, '')} return
onChange={(value) => handleTableChange('adult_cost', value, tag, record.priceType)} }
/> if (!('numberStart' in value)) {
), setNumberStart(newNumber);
props: { }
rowSpan: sameTagRecords.length, triggerChange({
}, numberStart: newNumber,
}; })
} else { }
return { const onNumberEndChange = (e) => {
props: { const newNumber = parseInt(e.target.value || '0', 10)
rowSpan: 0, if (Number.isNaN(numberEnd)) {
}, return
}; }
} if (!('numberEnd' in value)) {
}, setNumberEnd(newNumber)
}, }
{ triggerChange({
title: '儿童价', numberEnd: newNumber,
dataIndex: `childrenPrice${index + 1}`, });
key: `childrenPrice${index + 1}`, };
render: (text, record, rowIndex) => { const onAudultPriceChange = (e) => {
const sameTagRecords = tableData.filter(item => item.priceType === record.priceType); const newNumber = parseInt(e.target.value || '0', 10)
const firstTagIndex = tableData.findIndex(item => item.priceType === record.priceType && item.validPeriod === sameTagRecords[0].validPeriod); if (Number.isNaN(audultPrice)) {
return
if (rowIndex === firstTagIndex) { }
return { if (!('audultPrice' in value)) {
children: ( setAudultPrice(newNumber)
<InputNumber }
formatter={value => `${value}`} triggerChange({
parser={value => value.replace(/[^\d]/g, '')} audultPrice: newNumber,
onChange={(value) => handleTableChange('child_cost', value, tag, record.priceType)} })
/> }
), const onChildrenPriceChange = (e) => {
props: { const newNumber = parseInt(e.target.value || '0', 10)
rowSpan: sameTagRecords.length, if (Number.isNaN(childrenPrice)) {
}, return
}; }
} else { if (!('childrenPrice' in value)) {
return { setChildrenPrice(newNumber)
props: { }
rowSpan: 0, triggerChange({
}, childrenPrice: newNumber,
}; })
}
},
}
]
});
});
return columns;
}; };
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 ( return (
<div> <Space.Compact id={id}>
<Card <Input
size="small" type="text"
title="选择人等、周末" value={value.numberStart || numberStart}
style={{ marginBottom: 16 }} onChange={onNumberStartChange}
> style={{
<Row> width: '20%',
<Col> }}
<Input.Group compact style={{ marginTop: 10 }}> />
<Input <Input
style={{ width: 100, textAlign: 'center' }} type="text"
placeholder="Start" value={value.numberEnd || numberEnd}
value={minPeople} onChange={onNumberEndChange}
onChange={(e) => setMinPeople(e.target.value)} style={{
/> width: '40%',
<Input }}
style={{ width: 30, borderLeft: 0, pointerEvents: 'none', backgroundColor: '#fff' }} addonBefore="~"
placeholder="~" />
disabled <Input
/> type="text"
<Input value={value.audultPrice || audultPrice}
style={{ width: 100, textAlign: 'center', borderLeft: 0 }} onChange={onAudultPriceChange}
placeholder="End" style={{
value={maxPeople} width: '70%',
onChange={(e) => setMaxPeople(e.target.value)} }}
/> addonBefore="成人价"
</Input.Group> />
</Col> <Input
type="text"
<Col> value={value.childrenPrice || childrenPrice}
<Button size="small" type="primary" onClick={handleInputConfirm} style={{ marginLeft: 12, marginTop: 12 }}> onChange={onChildrenPriceChange}
添加人等 style={{
</Button> width: '70%',
</Col> }}
</Row> addonBefore="儿童价"
<div style={{ marginTop: 16 }}> />
{tags.map((tag) => ( </Space.Compact>
<Tag key={tag} closable onClose={() => handleTagClose(tag)}> )
{tag} }
</Tag>
))}
</div>
<Checkbox.Group
style={{ marginTop: 16 }}
options={['5', '6', '7']}
onChange={handleCheckboxChange}
/>
</Card>
<Form const priceInitialValues = {
labelCol={{ span: 6 }} "defList": [
wrapperCol={{ span: 18 }} //
form={form} {
name="dynamic_form_complex" "useDate": [
style={{ maxWidth: 600 }} dayjs().add(1, 'year').startOf("y"), dayjs().add(1, 'year').endOf("y")
autoComplete="off" ],
initialValues={{ items: [{}] }} "unitName": "每人",
> "currency": "CNY",
<Form.List name="items"> "weekend": [
{(fields, { add, remove }) => ( "5",
<div style={{ display: 'flex', rowGap: 16, flexDirection: 'column' }}> "6"
{fields.map((field, index) => ( ],
<Card "priceList": [
size="small" {
title={`批量设置价格 ${index + 1}`} "priceInput": {
key={field.key} "numberStart": 1,
extra={<CloseOutlined onClick={() => remove(field.name)} />} "numberEnd": 2,
> "audultPrice": 0,
<Form.Item label="类型" name={[field.name, 'type']}> "childrenPrice": 0
<Select placeholder="选择类型"> }
<Option value="每人">每人</Option> },
<Option value="每团">每团</Option> {
</Select> "priceInput": {
</Form.Item> "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']}> return (
<Select placeholder="选择币种"> <Row gutter={16} justify="center">
<Option value="CNY">CNY</Option> <Col span={12}>
<Option value="USD">USD</Option> <Form
</Select> labelCol={{ span: 3 }}
</Form.Item> 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.Item label="币种" name={[field.name, 'currency']}>
<Form.List name={[field.name, 'validPeriods']}> <Select placeholder="选择币种">
{(periodFields, periodOpt) => ( <Option value="CNY">CNY</Option>
<div style={{ display: 'flex', flexDirection: 'column', rowGap: 16 }}> <Option value="USD">USD</Option>
{periodFields.map((periodField, idx) => ( </Select>
<Space key={periodField.key}> </Form.Item>
<Form.Item noStyle name={[periodField.name, 'validPeriod']}> <Form.Item label="有效期" name={[field.name, 'useDate']}>
<RangePicker allowClear={true} inputReadOnly={true} presets={presets} placeholder={['From', 'Thru']}/> <RangePicker style={{width: '100%'}} allowClear={true} inputReadOnly={true} presets={presets} placeholder={['From', 'Thru']} />
</Form.Item> </Form.Item>
<CloseOutlined onClick={() => periodOpt.remove(periodField.name)} /> <Form.Item label="周末" name={[field.name, 'weekend']}>
</Space> <Checkbox.Group
))} options={['5', '6', '7']}
<Button type="dashed" onClick={() => periodOpt.add()} block> />
+ 新增有效期 </Form.Item>
</Button> <Form.Item label="人等">
</div> <Form.List name={[field.name, 'priceList']}>
)} {(priceFieldList, priceOptList) => (
</Form.List> <Flex gap="middle" vertical>
</Form.Item> {priceFieldList.map((priceField, index) => (
</Card> <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> </Button>
</div> </Flex>
)} )}
</Form.List> </Form.List>
</Form> </Form.Item>
</Card>
<Button type="primary" onClick={generateTableData} style={{ marginTop: 20 }}> ))}
生成表格 <Button type="dashed" onClick={() => add()} block>
</Button> + 新增价格设置
</Button>
{tableData.length > 0 && ( </Flex>
<div style={{ overflowX: 'auto' }}> )}
<Table </Form.List>
style={{ marginTop: 20 }} <Form.Item noStyle shouldUpdate>
columns={columns} {() => (
dataSource={tableData} <Typography className='hidden'>
pagination={false} <pre>{JSON.stringify(priceForm.getFieldsValue(), null, 2)}</pre>
/> </Typography>
</div>
)} )}
</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; export default BatchImportPrice;

Loading…
Cancel
Save