1.怎加批量录入价格功能

perf/export-docx
黄文强@HWQ-PC 1 year ago
parent 551b082168
commit 71c24be596

@ -1,243 +0,0 @@
import React, { useState } from 'react';
import { Table, Input, Button, DatePicker, Row, Col, Tag, Select } from 'antd';
const { RangePicker } = DatePicker;
const { Option } = Select;
const BatchImportPrice = () => {
const [startDate, setStartDate] = useState(null);
const [endDate, setEndDate] = useState(null);
const [startPeople, setStartPeople] = useState(1);
const [endPeople, setEndPeople] = useState(5);
const [dateRanges, setDateRanges] = useState([]);
const [peopleRanges, setPeopleRanges] = useState([]);
const [tableData, setTableData] = useState([]);
const [currency, setCurrency] = useState('RMB'); // RMB
const [type, setType] = useState('每人'); //
const handleGenerateTable = () => {
if (dateRanges.length === 0 || peopleRanges.length === 0) return;
const newData = dateRanges.flatMap(dateRange => {
const { startDate, endDate } = dateRange;
const dates = generateDateRange(startDate, endDate);
const row = { dateRange: `${startDate.format('YYYY-MM-DD')} ~ ${endDate.format('YYYY-MM-DD')}` };
peopleRanges.forEach(peopleRangeString => {
const [start, end] = peopleRangeString.split('-').map(Number);
generatePeopleRange(start, end).forEach(person => {
row[`${person}_adultPrice`] = '';
row[`${person}_childPrice`] = '';
});
});
dates.forEach(date => {
row[date] = '';
});
return row;
});
setTableData(newData);
};
const generateDateRange = (start, end) => {
const dates = [];
let currentDate = start.clone();
while (currentDate <= end) {
dates.push(currentDate.format('YYYY-MM-DD'));
currentDate = currentDate.add(1, 'day');
}
return dates;
};
const generatePeopleRange = (start, end) => {
const range = [];
for (let i = start; i <= end; i++) {
range.push(`人等${i}`);
}
return range;
};
const handleCellChange = (value, dateRange, peopleRange, type) => {
const newData = [...tableData];
const rowIndex = newData.findIndex(row => row.dateRange === dateRange);
newData[rowIndex][`${peopleRange}_${type}`] = value;
setTableData(newData);
};
const handleAddDateRange = () => {
if (startDate && endDate) {
const newDateRange = { startDate, endDate };
//
const isDateRangeExist = dateRanges.some(range => (
range.startDate.isSame(startDate, 'day') && range.endDate.isSame(endDate, 'day')
));
if (!isDateRangeExist) {
setDateRanges([...dateRanges, newDateRange]);
}
}
};
const handleAddPeopleRange = () => {
if (startPeople <= endPeople) {
const newPeopleRange = `${startPeople}-${endPeople}`;
//
const isPeopleRangeExist = peopleRanges.includes(newPeopleRange);
if (!isPeopleRangeExist) {
setPeopleRanges([...peopleRanges, newPeopleRange]);
}
}
};
const handleRemoveTag = (index, type) => {
if (type === 'date') {
setDateRanges(dateRanges.filter((_, i) => i !== index));
} else {
const removedPeopleRange = peopleRanges[index];
setPeopleRanges(peopleRanges.filter(range => range !== removedPeopleRange));
}
setTableData([]);
};
const [adultPrice, setAdultPrice] = useState('');
const [childPrice, setChildPrice] = useState('');
const handleAdultPriceChange = (value, dateRange) => {
const newData = [...tableData];
const rowIndex = newData.findIndex(row => row.dateRange === dateRange);
newData[rowIndex]['成人价'] = value;
setTableData(newData);
};
const handleChildPriceChange = (value, dateRange) => {
const newData = [...tableData];
const rowIndex = newData.findIndex(row => row.dateRange === dateRange);
newData[rowIndex]['儿童价'] = value;
setTableData(newData);
};
const columns = [
{
title: '日期\\人等',
dataIndex: 'dateRange',
key: 'dateRange',
},
...peopleRanges.flatMap(peopleRange => ([
{
title: peopleRange,
dataIndex: `${peopleRange}_price`,
key: `${peopleRange}_price`,
render: (text, record) => (
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
<Input
value={record[`${peopleRange}_adultPrice`]}
onChange={(e) => handleCellChange(e.target.value, record.dateRange, peopleRange, 'adultPrice')}
placeholder="成人价"
style={{ width: '45%' }}
suffix={`${currency}/${type}`}
/>
<Input
value={record[`${peopleRange}_childPrice`]}
onChange={(e) => handleCellChange(e.target.value, record.dateRange, peopleRange, 'childPrice')}
placeholder="儿童价"
style={{ width: '45%' }}
suffix={`${currency}/${type}`}
/>
</div>
),
}
])),
];
return (
<>
<Row>
<Col span={4}>
<Select value={currency} onChange={value => setCurrency(value)} style={{ width: '100%', marginTop: 10 }}>
<Option value="RMB">RMB</Option>
<Option value="MY">MY</Option>
</Select>
</Col>
<Col span={4}>
<Select value={type} onChange={value => setType(value)} style={{ width: '100%', marginTop: 10 }}>
<Option value="每人">每人</Option>
<Option value="美团">美团</Option>
</Select>
</Col>
</Row>
<Row gutter={16}>
<Col span={8}>
<RangePicker
onChange={(dates) => {
if (dates && dates.length === 2) {
setStartDate(dates[0]);
setEndDate(dates[1]);
} else {
setStartDate(null);
setEndDate(null);
}
}}
/>
</Col>
<Button onClick={handleAddDateRange} type="primary">记录有效期</Button>
</Row>
<Row gutter={16}>
<Col span={8}>
<Input.Group compact style={{ marginTop: 10 }}>
<Input
style={{ width: 100, textAlign: 'center' }}
placeholder="Start"
value={startPeople}
onChange={(e) => setStartPeople(parseInt(e.target.value, 10))}
/>
<Input
style={{ width: 30, borderLeft: 0, pointerEvents: 'none', backgroundColor: '#fff' }}
placeholder="~"
disabled
/>
<Input
style={{ width: 100, textAlign: 'center', borderLeft: 0 }}
placeholder="End"
value={endPeople}
onChange={(e) => setEndPeople(parseInt(e.target.value, 10))}
/>
</Input.Group>
</Col>
<Button onClick={handleAddPeopleRange} type="primary" style={{ marginTop: 10 }}>记录人等</Button>
</Row>
<Button onClick={handleGenerateTable} type="primary" style={{ marginTop: 10 }}>生成表格</Button>
<Row gutter={16} style={{ marginTop: '16px' }}>
<Col span={24}>
{dateRanges.map((dateRange, index) => (
<Tag key={index} closable onClose={() => handleRemoveTag(index, 'date')}>
{`${dateRange.startDate.format('YYYY-MM-DD')} ~ ${dateRange.endDate.format('YYYY-MM-DD')}`}
</Tag>
))}
{peopleRanges.map((peopleRange, index) => (
<Tag key={index} closable onClose={() => handleRemoveTag(index, 'people')}>
{peopleRange}
</Tag>
))}
</Col>
</Row>
<Table
columns={columns}
dataSource={tableData}
bordered
pagination={false}
style={{ marginTop: '16px' }}
/>
</>
);
};
export default BatchImportPrice;

@ -2,7 +2,7 @@ import React, { useState, useEffect, useRef, useMemo } from 'react';
import { Button, Card, Col, Row, Breadcrumb, Table, Popconfirm, Form, Input, InputNumber, Tag, Modal, Select, Tree } from 'antd';
import { Link } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import Date from '@/components/date';
import Date from '@/views/products/Detail/date';
import { searchAgencyAction, getAgencyProductsAction } from '@/stores/Products/Index';
import { useProductsTypes } from '@/hooks/useProductsSets';
import Extras from './Detail/Extras';
@ -10,7 +10,7 @@ import { groupBy } from '@/utils/commons';
import { useParams } from 'react-router-dom';
import { useHTLanguageSets } from '@/hooks/useHTLanguageSets';
import { useDefaultLgc } from '@/i18n/LanguageSwitcher';
import BatchImportPrice from '@/components/BatchImportPrice';
import BatchImportPrice from './Detail/BatchImportPrice1';
function Detail() {
const { t } = useTranslation();
const [form] = Form.useForm();
@ -43,7 +43,10 @@ function Detail() {
const [autoExpandParent, setAutoExpandParent] = useState(true);
const [dataList, setDataList] = useState([]);
const [defaultData, setDefaultData] = useState([]);
const [batchImportData, setBatchImportData] = useState([]);
const handleBatchImportData = (data) => {
setBatchImportData(data);
};
const productProject = {
"6": [],
@ -225,6 +228,7 @@ function Detail() {
newData.splice(index, 1, { ...item, ...restRow });
delete newData[index].quotation
delete newData[index].extras
console.log("newData",newData)
setQuotation(newData);
setEditingid('');
} else {
@ -305,6 +309,20 @@ function Detail() {
}
const handleBatchImportOK = () => {
console.log("quotation",quotation)
console.log('Batch Import Data:', batchImportData);
// tag validPeriod
const tempBatchImportData = batchImportData.map(item => {
const { tag, validPeriod, ...rest } = item;
return rest; //
});
// quotation
const newData = [...quotation, ...tempBatchImportData];
//
setQuotation(newData);
setBatchImportPriceVisible(false);
}
@ -711,6 +729,7 @@ const handleBatchImportOK = () => {
<Date onDateChange={handleDateChange} />
</Modal>
)}
{
batchImportPriceVisible && (
@ -721,7 +740,7 @@ const handleBatchImportOK = () => {
onCancel={() => setBatchImportPriceVisible(false)}
width="80%"
>
<BatchImportPrice/>
<BatchImportPrice onBatchImportData={handleBatchImportData}/>
</Modal>
)
}

@ -0,0 +1,324 @@
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';
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 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 = [];
// items
values.items.forEach((item) => {
// validPeriods
let tempValidPeriods = []
item.validPeriods?.forEach((period) => {
const validPeriod = period.validPeriod.map(date => date.format('YYYY-MM-DD')).join('~');
tempValidPeriods.push(validPeriod)
// tempSendData tag
});
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})
});
})
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);
});
});
setTableData(data);
onBatchImportData(data); //
};
const handleTableChange = (age_type, value, tag, validPeriod) => {
if (age_type === 'adult_cost') {
const updatedSendData = sendData.map((item) => {
if (item.validPeriod === validPeriod && item.tag === tag) {
return {
...item,
adult_cost: value, // adult_cost
};
}
return item; //
});
// sendDataole
onBatchImportData(updatedSendData);
setSendData(updatedSendData);
} else {
const updatedSendData = sendData.map((item) => {
if (item.validPeriod === validPeriod && 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) => (
<InputNumber
formatter={value => `${value}`}
parser={value => value.replace(/[^\d]/g, '')}
onChange={(value) => handleTableChange('adult_cost', value, tag, record.validPeriod)}
/>
),
},
{
title: '儿童价',
dataIndex: `childrenPrice${index + 1}`,
key: `childrenPrice${index + 1}`,
render: (text, record) => (
<InputNumber
formatter={value => `${value}`}
parser={value => value.replace(/[^\d]/g, '')}
onChange={(value) => handleTableChange('child_cost', value, tag, record.validPeriod)}
/>
),
}
]
});
});
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 (
<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>
<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>
<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 />
</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>
</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>
)}
</div>
);
};
export default BatchImportPrice;
Loading…
Cancel
Save