增加供应商价格管理页面

feature/price_manager
黄文强@HWQ-PC 1 year ago
parent 1142a1a893
commit 7b2c836e91

@ -52,7 +52,8 @@
"Notice": "通知",
"Report": "质量评分",
"Airticket": "机票订票",
"Products": "产品管理"
"Products": "产品管理",
"gysgl": "供应商价格管理"
},
"Validation": {
"Title": "温馨提示",

@ -31,7 +31,7 @@ import InvoicePaid from "@/views/invoice/Paid";
import InvoicePaidDetail from "@/views/invoice/PaidDetail";
import Airticket from "@/views/airticket/Index";
import ProductsIndex from '@/views/products/Index';
import Gysgl from "@/views/gysgl/Index"
import './i18n';
configure({
@ -67,6 +67,7 @@ const router = createBrowserRouter([
{ path: "invoice/paid/detail/:flid",element:<InvoicePaidDetail />},
{ path: "airticket",element:<Airticket />},
{ path: "products",element:<ProductsIndex />},
{ path: "gysgl",element:<Gysgl />},
]
},
{

@ -135,6 +135,7 @@ function App() {
</Link>
),
},
{key: 'gysgl', label:<Link to='/gysgl'>{t('menu.gysgl')}</Link>}
]}
/>
</Col>

@ -0,0 +1,581 @@
import React, { useState, useEffect, useRef } 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 DateComponent from './components/date';
import { fetchJSON } from "@/utils/request";
const cpxm = [
{ code: "code", name: "简码" },
{ code: "city_name", name: "城市" },
{ code: "remarks", name: "备注" },
{ code: "open_hours", name: "游览时间" },
{ code: "recommends_rate", name: "推荐指数" }
];
const initialData = [
{ key: '1', crj: '15', etj: "美元", bz: 'aa', lx: 'as', rq: 'dfae', rd: 'dawd', yxq: 'dawda' },
{ key: '2', crj: '15', etj: "美元", bz: 'aa', lx: 'as', rq: 'dfae', rd: 'dawd', yxq: 'dawda' },
{ key: '3', crj: '15', etj: "美元", bz: 'aa', lx: 'as', rq: 'dfae', rd: 'dawd', yxq: 'dawda' },
{ key: '4', crj: '15', etj: "美元", bz: 'aa', lx: 'as', rq: 'dfae', rd: 'dawd', yxq: 'dawda' },
];
const EditableCell = ({ editing, dataIndex, title, inputType, record, children, handleDateSelect, ...restProps }) => {
let inputNode = inputType === 'number' ? <InputNumber /> : <Input />;
if (dataIndex === 'yxq' && editing) {
return (
<td {...restProps}>
{children}
<Button onClick={() => handleDateSelect(record.key)}>选择日期</Button>
</td>
);
}
return (
<td {...restProps}>
{editing ? (
<Form.Item
name={dataIndex}
style={{ margin: 0 }}
rules={[{ required: true, message: `Please Input ${title}!` }]}
>
{inputNode}
</Form.Item>
) : (
children
)}
</td>
);
};
function Index() {
const { t, i18n } = useTranslation();
const [form] = Form.useForm();
const [quotation, setQuotation] = useState(initialData);
const [editingKey, setEditingKey] = useState('');
const [tags, setTags] = useState(['中文', 'English']);
const [isModalVisible, setIsModalVisible] = useState(false);
const [selectedTag, setSelectedTag] = useState('中文');
const [saveData, setSaveData] = useState(null);
const [datePickerVisible, setDatePickerVisible] = useState(false);
const [currentKey, setCurrentKey] = useState(null);
const [languageStatus, setLanguageStatus] = useState([{ "中文": { title: "", description: "" } }, { "English": { title: "", description: "" } }]);
const [formState, setFormState] = useState({});
const [selectedNodeKey, setSelectedNodeKey] = useState(null);
const isEditing = (record) => record.key === editingKey;
const edit = (record) => {
form.setFieldsValue({ ...record });
setEditingKey(record.key);
};
const cancel = () => {
setEditingKey('');
};
const handleSave = async (key) => {
try {
const row = await form.validateFields();
const newData = [...quotation];
const index = newData.findIndex((item) => key === item.key);
if (index > -1) {
const item = newData[index];
newData.splice(index, 1, { ...item, ...row });
setQuotation(newData);
setEditingKey('');
} else {
newData.push(row);
setQuotation(newData);
setEditingKey('');
}
} catch (errInfo) {
console.log('Validate Failed:', errInfo);
}
};
const handleDelete = (key) => {
const newData = [...quotation];
const index = newData.findIndex((item) => key === item.key);
newData.splice(index, 1);
setQuotation(newData);
};
const handleAdd = () => {
const newData = {
key: `${quotation.length + 1}`,
jg: '',
bz: '',
lx: '',
zm: '',
rq: '',
rd: '',
yxq: '',
};
setQuotation([...quotation, newData]);
};
const handleDateSelect = (key) => {
setCurrentKey(key);
setDatePickerVisible(true);
};
const handleDateChange = (date) => {
if (currentKey) {
const newData = [...quotation];
const index = newData.findIndex((item) => currentKey === item.key);
if (index > -1) {
newData[index].yxq = date;
setQuotation(newData);
setCurrentKey(null);
setDatePickerVisible(false);
}
}
};
const columns = [
{ title: '成人价', dataIndex: 'crj', width: '10%', editable: true },
{ title: '儿童价', dataIndex: 'etj', width: '10%', editable: true },
{ title: '币种', dataIndex: 'bz', width: '10%', editable: true },
{ title: '类型', dataIndex: 'lx', width: '10%', editable: true },
{ title: '人群', dataIndex: 'rq', width: '10%', editable: true },
{ title: '人等', dataIndex: 'rd', width: '10%', editable: true },
{ title: '有效期', dataIndex: 'yxq', width: '30%', editable: true },
{
title: '操作',
dataIndex: 'operation',
render: (_, record) => {
const editable = isEditing(record);
return editable ? (
<span>
<a href="#!" onClick={() => handleSave(record.key)} style={{ marginRight: 8 }}>保存</a>
<Popconfirm title="确定取消?" onConfirm={cancel}><a>取消</a></Popconfirm>
</span>
) : (
<span>
<a disabled={editingKey !== ''} onClick={() => edit(record)} style={{ marginRight: 8 }}>编辑</a>
<Popconfirm title="确定删除?" onConfirm={() => handleDelete(record.key)}>
<a>删除</a>
</Popconfirm>
</span>
);
},
},
];
const mergedColumns = columns.map((col) => {
if (!col.editable) {
return col;
}
return {
...col,
onCell: (record) => ({
record,
inputType: col.dataIndex === 'age' ? 'number' : 'text',
dataIndex: col.dataIndex,
title: col.title,
editing: isEditing(record),
handleDateSelect: handleDateSelect,
}),
};
});
const handleTagClick = (tag) => {
setSelectedTag(tag);
};
const showModal = () => setIsModalVisible(true);
const handleOk = () => setIsModalVisible(false);
const handleCancel = () => setIsModalVisible(false);
const handleTagChange = (value) => {
if (!tags.includes(value)) {
setTags([...tags, value]);
setLanguageStatus([...languageStatus, { [value]: { title: "", description: "" } }]);
}
setSelectedTag(value);
setIsModalVisible(false);
};
const handleChange = (field, value) => {
const updatedLanguageStatus = languageStatus.map(lang => {
if (lang[selectedTag]) {
return { ...lang, [selectedTag]: { ...lang[selectedTag], [field]: value } };
}
return lang;
});
setLanguageStatus(updatedLanguageStatus);
};
const findLanguageDetails = (tag) => {
const lang = languageStatus.find(lang => lang[tag]);
return lang ? lang[tag] : { title: "", description: "" };
};
//
const handleNodeSelect = async (_, { node }) => {
//
if (selectedNodeKey) {
await handleSaveForm();
}
//
setSelectedNodeKey(node.key);
//
if (formState[node.key]) {
form.setFieldsValue(formState[node.key]);
setQuotation(formState[node.key].quotation || []);
setLanguageStatus(formState[node.key].lgc_details || languageStatus);
} else {
form.resetFields();
setQuotation(initialData);
setLanguageStatus([{ "中文": { title: "", description: "" } }, { "English": { title: "", description: "" } }]);
}
};
const handleSaveForm = async () => {
try {
const values = await form.validateFields();
const newFormState = {
...formState,
[selectedNodeKey]: {
...values,
quotation,
lgc_details: languageStatus,
},
};
setFormState(newFormState);
} catch (error) {
console.error('Validation failed:', error);
}
};
const onSave = (values) => {
const tempData = values;
tempData['quotation'] = quotation;
tempData['extras'] = quotationBdcp;
tempData['lgc_details'] = languageStatus;
setSaveData(tempData);
console.log("保存的数据",tempData)
};
//
const initialDataBdcp = [
{ key: '1', mc: '15', jg: "美元", lx: 'aa' },
{ key: '2', mc: '15', jg: "美元", lx: 'aa' },
{ key: '3', mc: '15', jg: "美元", lx: 'aa' },
{ key: '4', mc: '15', jg: "美元", lx: 'aa' },
]
// const [form] = Form.useForm();
const [quotationBdcp, setQuotationBdcp] = useState(initialDataBdcp);
const isEditingBdcp = (record) => record.key === editingKeyBdcp;
const [editingKeyBdcp, setEditingKeyBdcp] = useState('');
const editBdcp = (record) => {
form.setFieldsValue({ ...record });
setEditingKeyBdcp(record.key);
};
const cancelBdcp = () => {
setEditingKeyBdcp('');
};
const EditableCellBdcp = ({
editing,
dataIndex,
title,
inputType,
record,
index,
children,
...restProps
}) => {
const inputNode = inputType === 'number' ? <InputNumber /> : <Input />;
return (
<td {...restProps}>
{editing ? (
<Form.Item
name={dataIndex}
style={{ margin: 0 }}
rules={[{ required: true, message: `请输入${title}` }]}
>
{inputNode}
</Form.Item>
) : (
children
)}
</td>
);
};
const bdcpColums = [
{ title: '名称', dataIndex: 'mc', width: '15%', editable: true },
{ title: '价格', dataIndex: 'jg', width: '15%', editable: true },
{ title: '类型', dataIndex: 'lx', width: '40%', editable: true },
{
title: '操作',
dataIndex: 'operation',
render: (_, record) => {
const editable = isEditingBdcp(record);
return editable ? (
<span>
<a href="#!" onClick={() => handleSaveBdcp(record.key)} style={{ marginRight: 8 }}>保存</a>
<Popconfirm title="确定取消?" onConfirm={cancelBdcp}><a>取消</a></Popconfirm>
</span>
) : (
<span>
<a disabled={editingKeyBdcp !== ''} onClick={() => editBdcp(record)} style={{ marginRight: 8 }}>编辑</a>
<Popconfirm title="确定删除?" onConfirm={() => handleDeleteBdcp(record.key)}>
<a>删除</a>
</Popconfirm>
</span>
);
},
},
].map(col => {
if (!col.editable) {
return col;
}
return {
...col,
onCell: record => ({
record,
inputType: col.dataIndex === 'jg' ? 'number' : 'text',
dataIndex: col.dataIndex,
title: col.title,
editing: isEditingBdcp(record),
}),
};
});
const handleAddBdcp = () => {
const newData = {
key: `${quotationBdcp.length + 1}`,
mc: '',
jg: '',
lx: '',
};
setQuotationBdcp([...quotationBdcp, newData]);
setEditingKeyBdcp(''); //
};
const handleSaveBdcp = async (key) => {
try {
const row = await form.validateFields();
const newData = [...quotationBdcp];
const index = newData.findIndex((item) => key === item.key);
if (index > -1) {
const item = newData[index];
newData.splice(index, 1, { ...item, ...row });
setQuotationBdcp(newData);
setEditingKeyBdcp('');
} else {
newData.push(row);
setQuotationBdcp(newData);
setEditingKeyBdcp('');
}
} catch (errInfo) {
console.log('Validate Failed:', errInfo);
}
};
const handleDeleteBdcp = (key) => {
const newData = [...quotationBdcp];
const index = newData.findIndex((item) => key === item.key);
newData.splice(index, 1);
setQuotationBdcp(newData);
};
const componentsBdcp = {
body: {
cell: EditableCellBdcp,
},
};
//Effect
useEffect(() => {
if (saveData) {
}
}, [saveData]);
useEffect(() => {
// const { errcode, result } = fetchJSON('http://127.0.0.1:4523/m1/2602949-1933890-default/Service_BaseInfoWeb/travel_agency_products');
console.log("get请求")
}, [])
useEffect(() => {
if (selectedNodeKey) {
handleSaveForm();
}
}, [selectedNodeKey]);
return (
<div>
<Row>
<Col span={6}>
<Card style={{ width: 350 }}>
<Tree
onSelect={handleNodeSelect}
treeData={[
{
title: '综费',
key: 'zf',
children: [{ title: '北京怡然假日', key: 'bjyrjr' }]
},
{
title: '车费',
key: 'cf',
children: [
{ title: '北京', key: 'bj' },
{ title: '天津', key: 'tj' },
{ title: '北京-天津', key: 'bj-tj-3-5' }
]
}
]}
/>
</Card>
</Col>
<Col span={18}>
<Form form={form} name="control-hooks" onFinish={onSave}>
<Card
style={{ width: 1250 }}
title={
<Breadcrumb items={[
{ title: <Link to={'/'}>供应商</Link> },
{ title: <Link to={'/aaa'}>综费</Link> },
{ title: '文章列表' }
]} />
}
>
<h2>产品项目</h2>
<Row gutter={16}>
{cpxm.map((item, index) => (
<Col span={8} key={index}>
<Form.Item name={['info', item.code]} label={item.name}>
<Input />
</Form.Item>
</Col>
))}
</Row>
<Card title={
<div>
{tags.map(tag => (
<Tag
key={tag}
onClick={() => handleTagClick(tag)}
color={tag === selectedTag ? 'blue' : undefined}
style={{ cursor: 'pointer' }}
>
{tag}
</Tag>
))}
<Tag onClick={showModal} style={{ cursor: 'pointer' }}>+</Tag>
</div>
}>
<Modal title="选择语言" visible={isModalVisible} onOk={handleOk} onCancel={handleCancel}>
<Select
showSearch
style={{ width: 200 }}
placeholder="选择语言"
optionFilterProp="children"
onChange={handleTagChange}
filterOption={(input, option) =>
option.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
}
>
<Select.Option value="Français">Français</Select.Option>
<Select.Option value="Español">Español</Select.Option>
<Select.Option value="Deutsch">Deutsch</Select.Option>
</Select>
</Modal>
<Form.Item label="名称">
<Input
style={{ width: 200 }}
value={findLanguageDetails(selectedTag).title}
onChange={(e) => handleChange('title', e.target.value)}
/>
</Form.Item>
<Form.Item label="描述">
<Input.TextArea
rows={4}
value={findLanguageDetails(selectedTag).description}
onChange={(e) => handleChange('description', e.target.value)}
/>
</Form.Item>
</Card>
</Card>
<Card style={{ width: 1250 }}>
<h2>供应商报价</h2>
<Form.Item name="quotation">
<Table
components={{ body: { cell: EditableCell } }}
bordered
dataSource={quotation}
columns={mergedColumns}
rowClassName="editable-row"
pagination={{ onChange: cancel }}
/>
<Button onClick={handleAdd} type="primary" style={{ marginBottom: 16 }}>
添加报价
</Button>
</Form.Item>
</Card>
<Card style={{ width: 1250 }}>
<h2>绑定产品</h2>
<Form.Item name="extras">
<Table
components={componentsBdcp}
bordered
dataSource={quotationBdcp}
columns={bdcpColums}
rowClassName="editable-row"
pagination={{ onChange: cancelBdcp }}
/>
<Button onClick={handleAddBdcp} type="primary" style={{ marginBottom: 16 }}>
添加报价
</Button>
</Form.Item>
</Card>
<Button type="primary" htmlType="submit" style={{ marginTop: 16, float: "right", marginRight: 100 }}>
保存
</Button>
</Form>
</Col>
</Row>
{datePickerVisible && (
<Modal
title="选择日期"
visible={datePickerVisible}
onOk={() => setDatePickerVisible(false)}
onCancel={() => setDatePickerVisible(false)}
>
<DateComponent onDateChange={handleDateChange} />
</Modal>
)}
</div>
);
}
export default Index;

@ -0,0 +1,86 @@
import React, { useState } from 'react';
import { DatePicker, Input, Button } from 'antd';
import dayjs from 'dayjs';
const DateComponent = ({ onDateChange }) => {
const dateFormat = 'YYYY/MM/DD';
const { RangePicker } = DatePicker;
const [selectedMonths, setSelectedMonths] = useState([]);
const [selectedDays, setSelectedDays] = useState([]);
const handleChange = (date, dateString) => {
const dateFw = dateString[0] + "-" + dateString[1];
onDateChange(dateFw);
};
const months = [
'January', 'February', 'March', 'April', 'May', 'June',
'July', 'August', 'September', 'October', 'November', 'December'
];
const days = [
'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'
];
const handleMonthClick = (month) => {
setSelectedMonths((prevSelectedMonths) => {
if (prevSelectedMonths.includes(month)) {
return prevSelectedMonths.filter((m) => m !== month);
} else {
return [...prevSelectedMonths, month];
}
});
};
const handleDayClick = (day) => {
setSelectedDays((prevSelectedDays) => {
if (prevSelectedDays.includes(day)) {
return prevSelectedDays.filter((d) => d !== day);
} else {
return [...prevSelectedDays, day];
}
});
};
return (
<div>
<h4>Title</h4>
<Input />
<h4>Data</h4>
<RangePicker
defaultValue={[dayjs('2015/01/01', dateFormat), dayjs('2015/01/01', dateFormat)]}
format={dateFormat}
onChange={handleChange}
/>
<h4>Months</h4>
<div>
{months.map((month, index) => (
<Button
key={index}
type={selectedMonths.includes(month) ? 'primary' : 'default'}
onClick={() => handleMonthClick(month)}
style={{ margin: '5px' }}
>
{month}
</Button>
))}
</div>
<h4>Weekdays</h4>
<div>
{days.map((day, index) => (
<Button
key={index}
type={selectedDays.includes(day) ? 'primary' : 'default'}
onClick={() => handleDayClick(day)}
style={{ margin: '5px' }}
>
{day}
</Button>
))}
</div>
</div>
);
};
export default DateComponent;
Loading…
Cancel
Save