diff --git a/public/locales/zh/common.json b/public/locales/zh/common.json index d689719..f99dd71 100644 --- a/public/locales/zh/common.json +++ b/public/locales/zh/common.json @@ -52,7 +52,8 @@ "Notice": "通知", "Report": "质量评分", "Airticket": "机票订票", - "Products": "产品管理" + "Products": "产品管理", + "gysgl": "供应商价格管理" }, "Validation": { "Title": "温馨提示", diff --git a/src/main.jsx b/src/main.jsx index 0f7c4fc..d0b8310 100644 --- a/src/main.jsx +++ b/src/main.jsx @@ -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:}, { path: "airticket",element:}, { path: "products",element:}, + { path: "gysgl",element:}, ] }, { diff --git a/src/views/App.jsx b/src/views/App.jsx index cbb2949..3678318 100644 --- a/src/views/App.jsx +++ b/src/views/App.jsx @@ -135,6 +135,7 @@ function App() { ), }, + {key: 'gysgl', label:{t('menu.gysgl')}} ]} /> diff --git a/src/views/gysgl/Index.jsx b/src/views/gysgl/Index.jsx new file mode 100644 index 0000000..46fb28a --- /dev/null +++ b/src/views/gysgl/Index.jsx @@ -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' ? : ; + if (dataIndex === 'yxq' && editing) { + return ( + + {children} + + + ); + } + + return ( + + {editing ? ( + + {inputNode} + + ) : ( + children + )} + + ); +}; + +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 ? ( + + handleSave(record.key)} style={{ marginRight: 8 }}>保存 + 取消 + + ) : ( + + edit(record)} style={{ marginRight: 8 }}>编辑 + handleDelete(record.key)}> + 删除 + + + ); + }, + }, + ]; + + + 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' ? : ; + return ( + + {editing ? ( + + {inputNode} + + ) : ( + children + )} + + ); + }; + 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 ? ( + + handleSaveBdcp(record.key)} style={{ marginRight: 8 }}>保存 + 取消 + + ) : ( + + editBdcp(record)} style={{ marginRight: 8 }}>编辑 + handleDeleteBdcp(record.key)}> + 删除 + + + ); + }, + }, + ].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 ( +
+ + + + + + + + +
+ 供应商 }, + { title: 综费 }, + { title: '文章列表' } + ]} /> + } + > +

产品项目

+ + {cpxm.map((item, index) => ( + + + + + + ))} + + + + {tags.map(tag => ( + handleTagClick(tag)} + color={tag === selectedTag ? 'blue' : undefined} + style={{ cursor: 'pointer' }} + > + {tag} + + ))} + + +
+ }> + + + + + + handleChange('title', e.target.value)} + /> + + + handleChange('description', e.target.value)} + /> + + + + + +

供应商报价

+ + + + + + + +

绑定产品

+ +
+ + + + + + + + + + + {datePickerVisible && ( + setDatePickerVisible(false)} + onCancel={() => setDatePickerVisible(false)} + > + + + )} + + ); +} +export default Index; + + diff --git a/src/views/gysgl/components/date.jsx b/src/views/gysgl/components/date.jsx new file mode 100644 index 0000000..51bc9ca --- /dev/null +++ b/src/views/gysgl/components/date.jsx @@ -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 ( +
+

Title

+ +

Data

+ +

Months

+
+ {months.map((month, index) => ( + + ))} +
+

Weekdays

+
+ {days.map((day, index) => ( + + ))} +
+
+ ); +}; + +export default DateComponent;