完成批量设置价格界面

perf/export-docx
Jimmy Liow 1 year ago
parent f68370fa72
commit cae1a8774a

@ -1213,11 +1213,11 @@ function Detail() {
</Row> </Row>
<Modal <Modal
title="批量添加价格" title='批量设置价格'
visible={batchImportPriceVisible} open={batchImportPriceVisible}
onOk={handleBatchImportOK} onOk={handleBatchImportOK}
onCancel={() => setBatchImportPriceVisible(false)} onCancel={() => setBatchImportPriceVisible(false)}
width="80%" width={620}
> >
<BatchImportPrice onBatchImportData={handleBatchImportData} /> <BatchImportPrice onBatchImportData={handleBatchImportData} />
</Modal> </Modal>

@ -1,574 +1,301 @@
import { useEffect, useState } from 'react'; import { useState } from 'react';
import { Button, Card, Checkbox, Col, DatePicker, Typography, Form, Input, Row, Select, Space, Tag, Table, InputNumber } from 'antd'; import { Button, Card, Checkbox, Col, Flex, DatePicker, Typography, Form, Input, Row, Select, Space } from 'antd';
import dayjs from "dayjs";
import { CloseOutlined } from '@ant-design/icons'; import { CloseOutlined } 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 [priceForm] = Form.useForm();
const [peopleForm] = Form.useForm(); const presets = useDatePresets();
const [tags, setTags] = useState([]); const PriceInput = (props) => {
const [minPeople, setMinPeople] = useState(''); const { id, value = {}, onChange } = props
const [maxPeople, setMaxPeople] = useState(''); const [numberStart, setNumberStart] = useState(0)
const [checkedDays, setCheckedDays] = useState([]); const [numberEnd, setNumberEnd] = useState(0)
const [tableData, setTableData] = useState([]); const [audultPrice, setAudultPrice] = useState(0)
const [sendData, setSendData] = useState(null); const [childrenPrice, setChildrenPrice] = useState(0)
const presets = useDatePresets(); const triggerChange = (changedValue) => {
onChange?.({
useEffect(() => { numberStart,
peopleForm.setFieldValue({ numberEnd,
"items": [ audultPrice,
{ childrenPrice,
"weekend": [ ...value,
"5", ...changedValue,
"6",
"7"
],
"peopleList": [
{
"peoplePrice": "22",
"numberStart": "1",
"numberEnd": "2",
"audultPrice": "23",
"childrenPrice": "44"
},
{
"numberStart": "3",
"numberEnd": "5",
"audultPrice": "24",
"childrenPrice": "12"
}
]
}
]
}) })
}) }
const onNumberStartChange = (e) => {
const handleTagClose = (removedTag) => { const newNumber = parseInt(e.target.value || '0', 10)
setTags(tags.filter(tag => tag !== removedTag)); if (Number.isNaN(numberStart)) {
}; return
}
const handleInputConfirm = () => { if (!('numberStart' in value)) {
if (minPeople && maxPeople) { setNumberStart(newNumber);
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)
});
//
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) => {
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);
}
};
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 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(),
];
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) => { triggerChange({
const newNumber = parseInt(e.target.value || '0', 10) numberStart: newNumber,
if (Number.isNaN(numberStart)) { })
return }
} const onNumberEndChange = (e) => {
if (!('numberStart' in value)) { const newNumber = parseInt(e.target.value || '0', 10)
setNumberStart(newNumber); if (Number.isNaN(numberEnd)) {
} return
triggerChange({
numberStart: newNumber,
})
} }
const onNumberEndChange = (e) => { if (!('numberEnd' in value)) {
const newNumber = parseInt(e.target.value || '0', 10) setNumberEnd(newNumber)
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) => { triggerChange({
const newNumber = parseInt(e.target.value || '0', 10) numberEnd: newNumber,
if (Number.isNaN(childrenPrice)) { });
return };
} const onAudultPriceChange = (e) => {
if (!('childrenPrice' in value)) { const newNumber = parseInt(e.target.value || '0', 10)
setChildrenPrice(newNumber) if (Number.isNaN(audultPrice)) {
} return
triggerChange({ }
childrenPrice: newNumber, if (!('audultPrice' in value)) {
}) setAudultPrice(newNumber)
}; }
return ( triggerChange({
<Space.Compact id={id}> audultPrice: newNumber,
<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 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 ( return (
<Row gutter={16}> <Space.Compact id={id}>
<Col span={10}> <Input
<Form type="text"
labelCol={{ span: 6 }} value={value.numberStart || numberStart}
wrapperCol={{ span: 18 }} onChange={onNumberStartChange}
form={peopleForm} style={{
name="peopleForm" width: '20%',
autoComplete="off" }}
initialValues={{ />
"items": [ <Input
{ type="text"
"weekend": [ value={value.numberEnd || numberEnd}
"5", onChange={onNumberEndChange}
"6", style={{
"7" width: '40%',
], }}
addonBefore="~"
"prieceList": [ />
{ <Input
"priceInput": { type="text"
"numberStart": 1, value={value.audultPrice || audultPrice}
"numberEnd": 2, onChange={onAudultPriceChange}
"audultPrice": 0, style={{
"childrenPrice": 0 width: '70%',
} }}
}, addonBefore="成人价"
{ />
"priceInput": { <Input
"numberStart": 3, type="text"
"numberEnd": 4, value={value.childrenPrice || childrenPrice}
"audultPrice": 0, onChange={onChildrenPriceChange}
"childrenPrice": 0 style={{
} width: '70%',
}, }}
{ addonBefore="儿童价"
"priceInput": { />
"numberStart": 5, </Space.Compact>
"numberEnd": 6, )
"audultPrice": 0, }
"childrenPrice": 0
} const priceInitialValues = {
}, "items": [
{ //
"priceInput": { {
"numberStart": 7, "useDate": [
"numberEnd": 9, dayjs().add(1, 'year').startOf("y"), dayjs().add(1, 'year').endOf("y")
"audultPrice": 0, ],
"childrenPrice": 0 "unitName": "每人",
} "currency": "CNY",
} "weekend": [
] "5",
} "6"
] ],
}} "prieceList": [
> {
<Form.List name="items" > "priceInput": {
{(fields, { add, remove }) => ( "numberStart": 1,
<div style={{ display: 'flex', rowGap: 16, flexDirection: 'column' }}> "numberEnd": 2,
{fields.map((field, index) => ( "audultPrice": 0,
<Card "childrenPrice": 0
size="small" }
title={`周末、人等`} },
key={field.key} {
> "priceInput": {
<Form.Item label="周末" name={[field.name, 'weekend']}> "numberStart": 3,
"numberEnd": 4,
<Checkbox.Group "audultPrice": 0,
options={['5', '6', '7']} "childrenPrice": 0
onChange={handleCheckboxChange} }
/> },
</Form.Item> {
"priceInput": {
"numberStart": 5,
<Form.Item label="价格"> "numberEnd": 6,
<Form.List name={[field.name, 'prieceList']}> "audultPrice": 0,
{(priceFields, priceOpt) => ( "childrenPrice": 0
<> }
{priceFields.map((priceField) => ( },
<Space key={priceField.key}> {
<Form.Item noStyle name={[priceField.name, 'priceInput']}> "priceInput": {
<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"
],
"prieceList": [
{
"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
}
}
]
}
]
}
return (
<Row gutter={16} justify="center">
<Col span={24}>
<Form
labelCol={{ span: 3 }}
wrapperCol={{ span: 20 }}
form={priceForm}
name="priceForm"
autoComplete="off"
initialValues={priceInitialValues}
>
<Form.List name="items">
{(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>
<CloseOutlined onClick={() => priceOpt.remove(priceField.name)} /> <Form.Item label="币种" name={[field.name, 'currency']}>
</Space> <Select placeholder="选择币种">
))} <Option value="CNY">CNY</Option>
<Button type="dashed" onClick={() => priceOpt.add()} block> <Option value="USD">USD</Option>
+ 新增人等 </Select>
</Button> </Form.Item>
</> <Form.Item label="有效期" name={[field.name, 'useDate']}>
)} <RangePicker style={{width: '100%'}} allowClear={true} inputReadOnly={true} presets={presets} placeholder={['From', 'Thru']} />
</Form.List> </Form.Item>
</Form.Item> <Form.Item label="周末" name={[field.name, 'weekend']}>
<Checkbox.Group
options={['5', '6', '7']}
</Card> />
))} </Form.Item>
</div> <Form.Item label="人等">
)} <Form.List name={[field.name, 'prieceList']}>
</Form.List> {(prieceFieldList, priceOptList) => (
<Form.Item noStyle shouldUpdate> <Flex gap="middle" vertical>
{() => ( {prieceFieldList.map((priceField) => (
<Typography> <Space key={priceField.key}>
<pre>{JSON.stringify(peopleForm.getFieldsValue(), null, 2)}</pre> <Form.Item noStyle name={[priceField.name, 'priceInput']}>
</Typography> <PriceInput />
)} </Form.Item>
</Form.Item> <CloseOutlined onClick={() => priceOptList.remove(priceField.name)} />
</Form> </Space>
</Col>
<Col span={14}>
<Form
labelCol={{ span: 6 }}
wrapperCol={{ span: 18 }}
form={form}
name="dynamic_form_complex"
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>
<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="有效期">
<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>
))} ))}
<Button type="dashed" onClick={() => add()} block> <Button type="dashed" onClick={() => priceOptList.add()} block>
+ 新增价格设置 + 新增人等
</Button> </Button>
</div> </Flex>
)} )}
</Form.List> </Form.List>
<Form.Item noStyle shouldUpdate> </Form.Item>
{() => ( </Card>
<Typography> ))}
<pre>{JSON.stringify(form.getFieldsValue(), null, 2)}</pre> <Button type="dashed" onClick={() => add()} block>
</Typography> + 新增价格设置
)} </Button>
</Form.Item> </Flex>
</Form> )}
</Form.List>
<Button type="primary" onClick={generateTableData} style={{ marginTop: 20 }}> <Form.Item noStyle shouldUpdate>
生成表格 {() => (
</Button> <Typography className='hidden'>
<pre>{JSON.stringify(priceForm.getFieldsValue(), null, 2)}</pre>
{tableData.length > 0 && ( </Typography>
<div style={{ overflowX: 'auto' }}>
<Table
style={{ marginTop: 20 }}
columns={columns}
dataSource={tableData}
pagination={false}
/>
</div>
)} )}
</Col> </Form.Item>
</Row> </Form>
); </Col>
</Row>
);
}; };
export default BatchImportPrice; export default BatchImportPrice;

Loading…
Cancel
Save