From 0d9a80cefd66d1df1b2029dcf818a31025389979 Mon Sep 17 00:00:00 2001 From: Lei OT Date: Wed, 31 Jul 2024 16:32:57 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BA=A7=E5=93=81=E7=BC=96=E8=BE=91=E9=A1=B5?= =?UTF-8?q?=E9=9D=A2:=20=E7=BB=84=E4=BB=B6=20=E6=96=B0=E5=A2=9E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/locales/en/products.json | 2 +- src/views/products/Detail.jsx | 1372 ++--------------- src/views/products/Detail/NewProductModal.jsx | 115 ++ src/views/products/Detail/ProductInfoForm.jsx | 6 +- 4 files changed, 266 insertions(+), 1229 deletions(-) create mode 100644 src/views/products/Detail/NewProductModal.jsx diff --git a/public/locales/en/products.json b/public/locales/en/products.json index 50bda51..79ca29e 100644 --- a/public/locales/en/products.json +++ b/public/locales/en/products.json @@ -115,5 +115,5 @@ "Weekdays": "Weekdays" }, - "#": "Products" + "#": "Product" } diff --git a/src/views/products/Detail.jsx b/src/views/products/Detail.jsx index 95eb087..87d8a1b 100644 --- a/src/views/products/Detail.jsx +++ b/src/views/products/Detail.jsx @@ -1,5 +1,28 @@ import React, { useState, useEffect } from 'react'; -import { Tooltip, Button, Card, Col, Row, Breadcrumb, Table, Popconfirm, Form, Input, InputNumber, Tag, Modal, Select, Tree, FloatButton, DatePicker, Spin, message, Divider,Empty, Flex } from 'antd'; +import { + Tooltip, + Button, + Card, + Col, + Row, + Breadcrumb, + Table, + Popconfirm, + Form, + Input, + InputNumber, + Tag, + Modal, + Select, + Tree, + FloatButton, + DatePicker, + Spin, + message, + Divider, + Empty, + Flex, +} from 'antd'; import { Link, useNavigate } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import { useProductsTypes, useProductsAuditStatesMapVal, useProductsTypesMapVal, useNewProductRecord } from '@/hooks/useProductsSets'; @@ -7,10 +30,9 @@ import Extras from './Detail/Extras'; import { isEmpty } from '@/utils/commons'; import SecondHeaderWrapper from '@/components/SecondHeaderWrapper'; import Header from './Detail/Header'; -import YearSelector from './Detail/YearSelector' +import YearSelector from './Detail/YearSelector'; import { useParams } from 'react-router-dom'; import useProductsStore from '@/stores/Products/Index'; -import postProductsSave from '@/stores/Products/Index'; import { useHTLanguageSets } from '@/hooks/useHTLanguageSets'; import { useDefaultLgc } from '@/i18n/LanguageSwitcher'; import BatchImportPrice from './Detail/BatchImportPrice'; @@ -21,1031 +43,180 @@ import { useDatePresets } from '@/hooks/useDatePresets'; import CitySelector from '@/components/CitySelector'; import { HT_HOST } from '@/config'; import { postJSON, postForm } from '@/utils/request'; -import RequireAuth from '@/components/RequireAuth' -import { PERM_ROLE_NEW } from '@/config' +import RequireAuth from '@/components/RequireAuth'; +import { PERM_ROLE_NEW } from '@/config'; import { create } from 'zustand'; import { PERM_PRODUCTS_MANAGEMENT, PERM_PRODUCTS_OFFER_AUDIT, PERM_PRODUCTS_OFFER_PUT } from '@/config'; import { usingStorage } from '@/hooks/usingStorage'; import ProductsTree from './Detail/ProductsTree'; import ProductInfo from './Detail/ProductInfo'; import useAuthStore from '@/stores/Auth'; +import NewProductModal from './Detail/NewProductModal'; function Detail() { - const { t } = useTranslation(); - const productsTypesMapVal = useProductsTypesMapVal(); - const [form] = Form.useForm(); - const navigate = useNavigate() - const { RangePicker } = DatePicker; - const [tags, setTags] = useState([]); - const [isModalVisible, setIsModalVisible] = useState(false); - const [selectedTag, setSelectedTag] = useState(null); - const [batchImportPriceVisible, setBatchImportPriceVisible] = useState(false); - const [quotationTableVisible, setQuotationTableVisible] = useState(false) - const [languageStatus, setLanguageStatus] = useState(null); - const [selectedNodeid, setSelectedNodeid] = useState(null); - const [remainderLanguage, setRemainderLanguage] = useState([]) - const [treeData, setTreeData] = useState([]); - const productsTypes = useProductsTypes(); - const [productsData, setProductsData] = useState(null); + // const { t } = useTranslation(); + const navigate = useNavigate(); const [quotation, setQuotation] = useState(null); const [lgc_details, setLgc_details] = useState(null); - const [languageLabel, setLanguageLabel] = useState(null); + // const [languageLabel, setLanguageLabel] = useState(null); const { travel_agency_id, audit_state, use_year } = useParams(); - const { language } = useDefaultLgc(); - const HTLanguageSets = useHTLanguageSets(); - const { Search } = Input; + // const HTLanguageSets = useHTLanguageSets(); + // const { Search } = Input; const [addProductVisible, setAddProductVisible] = useState(false); const [editingProduct, setEditingProduct] = useProductsStore((state) => [state.editingProduct, state.setEditingProduct]); - const [agencyProducts, setAgencyProducts,loading] = useProductsStore((state) => [state.agencyProducts, state.setAgencyProducts, state.loading]); + const [agencyProducts, setAgencyProducts, loading] = useProductsStore((state) => [state.agencyProducts, state.setAgencyProducts, state.loading]); const { getAgencyProducts, activeAgency } = useProductsStore(); - const [expandedKeys, setExpandedKeys] = useState([]); - const [searchValue, setSearchValue] = useState(''); - const [autoExpandParent, setAutoExpandParent] = useState(true); - const [dataList, setDataList] = useState([]); - const [defaultData, setDefaultData] = useState([]); - const [batchImportData, setBatchImportData] = useState([]); - const [addProductType, setAddProductType] = useState(''); - const [addproductName, setAddProductName] = useState(''); - const [dataFetched, setDataFetched] = useState(false); // 添加一个标志位 - const [selectedDays, setSelectedDays] = useState([]); - const [weekdays, setWeekdays] = useState([]); const [info, setInfo] = useState(); const yearOptions = []; const currentYear = dayjs().year(); const baseYear = Number(use_year === 'all' ? currentYear : use_year); for (let i = baseYear - 3; i <= baseYear + 3; i++) { - yearOptions.push({ label: i, value: i, }); + yearOptions.push({ label: i, value: i }); } - const [param, setParam] = useState({ pick_year: baseYear, pick_agency: travel_agency_id }); - const [pickYear, setPickYear] = useState(baseYear); - const handleYearChange = (value) => { - setPickYear(value); - setParam((pre) => ({ ...pre, ...{ pick_year: value } })); - }; const { travelAgencyId } = usingStorage(); - const handleGetAgencyProducts = ({pick_year, pick_agency, pick_state}={}) => { + const handleGetAgencyProducts = ({ pick_year, pick_agency, pick_state } = {}) => { const year = pick_year || use_year || dayjs().year(); const agency = pick_agency || travel_agency_id || travelAgencyId; const state = pick_state ?? audit_state; - console.log("loading",loading); getAgencyProducts({ travel_agency_id: agency, use_year: year, audit_state: state }); - console.log("loading",loading); - console.log("AgencyProducts",agencyProducts); + // console.log("AgencyProducts",agencyProducts); // navigate(`/products/${agency}/${year}/${audit_state}/edit`); - - }; - const travel_agency_name = activeAgency.travel_agency_name; - const audit_state_id = activeAgency.audit_state_id; - let isCanEditable = !(audit_state_id === 1 || audit_state_id === 3 || audit_state_id === -1) - const [currentQuotationRecord, setCurrentQuotationRecord] = useState({ - use_dates_start: null, - use_dates_end: null - }); - const formatDate = (date) => (date ? dayjs(date) : null); - const stateMapVal = useProductsAuditStatesMapVal(); - - const startDate = currentQuotationRecord.use_dates_start && dayjs(currentQuotationRecord.use_dates_start).isValid() - ? formatDate(currentQuotationRecord.use_dates_start) - : null; - const endDate = currentQuotationRecord.use_dates_end && dayjs(currentQuotationRecord.use_dates_end).isValid() - ? formatDate(currentQuotationRecord.use_dates_end) - : null; - - - const [editIndex, setEditIndex] = useState(null); - const presets = useDatePresets(); - const handleBatchImportData = (data) => { - setBatchImportData(data); }; - const days = [ - 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday' - ]; - const productProject = { - "6": [ - { code: "code", name: t('products:Code'), nameKey: 'products:Code' }, - { code: "city_name", name: t('products:City'), nameKey: 'products:City' }, - ], - "B": [ - { code: "code", name: t('products:Code'), nameKey: 'products:Code' }, - { code: "city_name", name: t('products:City'), nameKey: 'products:City' }, - { code: "km", name: t('products:KM'), nameKey: 'products:KM' }, - { - code: "remarks", - name: ( - - {t('products:Remarks')} - - ), - nameKey: 'products:Remarks', - }, - ], - "J": [ - { code: "code", name: t('products:Code'), nameKey: 'products:Code' }, - { code: "city_name", name: t('products:City'), nameKey: 'products:City' }, - { - code: "recommends_rate", - name: ( - - {t('products:recommendationRate')} - - ), - nameKey: 'products:recommendationRate', - }, - { code: "duration", name: t('products:Duration'), nameKey: 'products:Duration' }, - { - code: "dept_name", - name: ( - - {t('products:Dept')} - - ), - nameKey: 'products:Dept', - }, - { - code: "display_to_c", - name: ( - - {t('products:DisplayToC')} - - ), - nameKey: 'products:DisplayToC', - }, - { - code: "remarks", - name: ( - - {t('products:Remarks')} - - ), - nameKey: 'products:Remarks', - }, - ], - "Q": [ - { code: "code", name: t('products:Code'), nameKey: 'products:Code' }, - { code: "city_name", name: t('products:City'), nameKey: 'products:City' }, - { - code: "recommends_rate", - name: ( - - {t('products:recommendationRate')} - - ), - nameKey: 'products:recommendationRate', - }, - { code: "duration", name: t('products:Duration'), nameKey: 'products:Duration' }, - { - code: "dept_name", - name: ( - - {t('products:Dept')} - - ), - nameKey: 'products:Dept', - }, - { - code: "display_to_c", - name: ( - - {t('products:DisplayToC')} - - ), - nameKey: 'products:DisplayToC', - }, - { - code: "remarks", - name: ( - - {t('products:Remarks')} - - ), - nameKey: 'products:Remarks', - }, - ], - "D": [ - { code: "code", name: t('products:Code'), nameKey: 'products:Code' }, - { code: "city_name", name: t('products:City'), nameKey: 'products:City' }, - { - code: "recommends_rate", - name: ( - - {t('products:recommendationRate')} - - ), - nameKey: 'products:recommendationRate', - }, - { code: "duration", name: t('products:Duration'), nameKey: 'products:Duration' }, - { - code: "dept_name", - name: ( - - {t('products:Dept')} - - ), - nameKey: 'products:Dept', - }, - { - code: "display_to_c", - name: ( - - {t('products:DisplayToC')} - - ), - nameKey: 'products:DisplayToC', - }, - { - code: "remarks", - name: ( - - {t('products:Remarks')} - - ), - nameKey: 'products:Remarks', - }, - ], - "7": [ - { code: "code", name: t('products:Code'), nameKey: 'products:Code' }, - { code: "city_name", name: t('products:City'), nameKey: 'products:City' }, - { - code: "recommends_rate", - name: ( - - {t('products:recommendationRate')} - - ), - nameKey: 'products:recommendationRate', - }, - { code: "duration", name: t('products:Duration'), nameKey: 'products:Duration' }, - { code: "open_weekdays", name: t('products:OpenWeekdays'), nameKey: 'products:OpenWeekdays' }, - { - code: "remarks", - name: ( - - {t('products:Remarks')} - - ), - nameKey: 'products:Remarks', - }, - ], - "8": [ - { code: "code", name: t('products:Code') }, - { code: "city_name", name: t('products:City') }, - ], - "R": [ - { code: "code", name: t('products:Code'), nameKey: 'products:Code' }, - { code: "city_name", name: t('products:City'), nameKey: 'products:City' }, - ] - } - const [selectedCategory, setSelectedCategory] = useState([]); - - useEffect(() => { - setLanguageStatus(language); - const matchedLanguage = HTLanguageSets.find(HTLanguage => HTLanguage.key === language.toString()); - const languageLabel = matchedLanguage.label - setLanguageLabel(languageLabel) - setSelectedTag(languageLabel) - // setRemainderLanguage(HTLanguageSets.filter(item => item.key !== language.toString())) - - }, []); - useEffect(()=>{ - handleGetAgencyProducts(param); - },[param]); - - - - useEffect(() => { - editingProductQuotation(); - }, [treeData, editingProduct]) - - const editingProductQuotation = () => { - console.log("editingProduct", editingProduct) - const editingProductID = editingProduct.id; - console.log("editingProductID", editingProductID) - let stopProgram = false; - for (const element of treeData) { - if (stopProgram) { - return; - } - const childList = element.children; - for (const product of childList) { - const childrenID = product.key.split('-')[1]; - if (editingProductID == childrenID) { - const fatherKey = product.key.split('-')[0]; - setSelectedCategory(productProject[fatherKey]); - stopProgram = true; - const tempInfo = product._raw.info; - const tempLgc_details = product._raw.lgc_details.find(record => record.lgc === 2); - console.log("tempLgc_details", tempLgc_details); - const tempQuotation = product._raw.quotation; - console.log({ - info: tempInfo, - lgc_details: { - title: tempLgc_details.title, - description: tempLgc_details.descriptions - }, - }) - setQuotation(tempQuotation); - setTags([languageLabel]); - setRemainderLanguage(HTLanguageSets.filter(item => item.key !== language.toString())); - - form.setFieldsValue({ - info: tempInfo, - lgc_details: { - title: tempLgc_details.title, - description: tempLgc_details.descriptions - }, - }) - break; - } - } - - } - } // useEffect(() => { - // const fetchData = async () => { - // if (productsTypes.length > 0 && travel_agency_id && Object.keys(agencyProducts).length > 0) { - // const generateTreeData = (productsTypes, productsData) => { - // return productsTypes.map(type => ({ - // title: type.label, - // key: type.value, - // selectable: false, - // children: (productsData[type.value] || []).map(product => ({ - // title: product.info.title, - // key: `${type.value}-${product.info.id}`, - // _raw: product, - // })), - // })); - // }; - // const tempExpandedKeys = productsTypes.map(item => item.key); - // const treeData = generateTreeData(productsTypes, agencyProducts); - // setTreeData(treeData); - // setExpandedKeys(tempExpandedKeys); - // setProductsData(agencyProducts); - // setDefaultData(treeData); - // setDataList(flattenTreeData(treeData)); - // setDataFetched(true); + // editingProductQuotation(); + // }, [treeData, editingProduct]); + + // const editingProductQuotation = () => { + // console.log('editingProduct', editingProduct); + // const editingProductID = editingProduct.id; + // console.log('editingProductID', editingProductID); + // let stopProgram = false; + // for (const element of treeData) { + // if (stopProgram) { + // return; // } - // }; - // fetchData(); - // }, [productsTypes, travel_agency_id, use_year, audit_state, agencyProducts]); - - // const flattenTreeData = (tree) => { - // let flatList = []; - // const flatten = (nodes) => { - // nodes.forEach((node) => { - // flatList.push({ title: node.title, key: node.key }); - // if (node.children) { - // flatten(node.children); - // } - // }); - // }; - // flatten(tree); - // return flatList; - // }; - - // const getParentKey = (key, tree) => { - // let parentKey; - // for (let i = 0; i < tree.length; i++) { - // const node = tree[i]; - // if (node.children) { - // if (node.children.some((item) => item.key === key)) { - // parentKey = node.key; - // } else { - // const pKey = getParentKey(key, node.children); - // if (pKey) { - // parentKey = pKey; - // } + // const childList = element.children; + // for (const product of childList) { + // const childrenID = product.key.split('-')[1]; + // if (editingProductID == childrenID) { + // const fatherKey = product.key.split('-')[0]; + // setSelectedCategory(productProject[fatherKey]); + // stopProgram = true; + // const tempInfo = product._raw.info; + // const tempLgc_details = product._raw.lgc_details.find((record) => record.lgc === 2); + // console.log('tempLgc_details', tempLgc_details); + // const tempQuotation = product._raw.quotation; + // console.log({ + // info: tempInfo, + // lgc_details: { + // title: tempLgc_details.title, + // description: tempLgc_details.descriptions, + // }, + // }); + // setQuotation(tempQuotation); + // setTags([languageLabel]); + // setRemainderLanguage(HTLanguageSets.filter((item) => item.key !== language.toString())); + + // form.setFieldsValue({ + // info: tempInfo, + // lgc_details: { + // title: tempLgc_details.title, + // description: tempLgc_details.descriptions, + // }, + // }); + // break; // } // } // } - // return parentKey; - // }; - - // const titleRender = (node) => { - // const index = node.title.indexOf(searchValue); - // const beforeStr = node.title.substr(0, index); - // const afterStr = node.title.substr(index + searchValue.length); - // const highlighted = ( - // {searchValue} - // ); - - // return index > -1 ? ( - // - // {beforeStr} - // {highlighted} - // {afterStr} - // - // ) : ( - // {node.title} - // ); - // }; - - - // const onChange = (e) => { - // const { value } = e.target; - // const newExpandedKeys = dataList - // .filter(item => item.title.includes(value)) - // .map(item => getParentKey(item.key, defaultData)) - // .filter((item, i, self) => item && self.indexOf(item) === i); - // setExpandedKeys(newExpandedKeys); - // setSearchValue(value); - // setAutoExpandParent(true); - // }; - - // const onExpand = (keys) => { - // setExpandedKeys(keys); - // setAutoExpandParent(false); // }; - const edit = (record, index) => { - setQuotationTableVisible(true); - setEditIndex(index); - setCurrentQuotationRecord(record); - }; - - - const handleDelete = (index) => { - const newData = [...quotation]; - newData.splice(index, 1); - const sortedData = [...newData].sort((a, b) => { - const aValidPeriod = dayjs(a.use_dates_end).diff(dayjs(a.use_dates_start)); - const bValidPeriod = dayjs(b.use_dates_end).diff(dayjs(b.use_dates_start)); - if (aValidPeriod !== bValidPeriod) { - return aValidPeriod - bValidPeriod; - } - const aGroupSize = a.group_size_max - a.group_size_min; - const bGroupSize = b.group_size_max - b.group_size_min; - - return aGroupSize - bGroupSize; - }); - setQuotation(sortedData); - }; - - const handleAdd = () => { - const newData = { - adult_cost: 0, - child_cost: 0, - currency: '', - group_size_min: 0, - group_size_max: 0, - id: '', - lastedit_changed: '', - use_dates_start: '', - use_dates_end: '', - weekdays: '', - tempKey: Math.random() - }; - setQuotation([...quotation, newData]); - const index = [...quotation, newData].length - 1 - edit(newData, index); - }; - - const handleBatchImport = () => { - setBatchImportPriceVisible(true); - } - - const quotationTableVisibleOK = () => { - currentQuotationRecord.use_dates_start = dayjs(currentQuotationRecord.use_dates_start).format('YYYY-MM-DD') - currentQuotationRecord.use_dates_end = dayjs(currentQuotationRecord.use_dates_end).format('YYYY-MM-DD') - const tempQuotation = [...quotation]; - tempQuotation[editIndex] = { ...currentQuotationRecord, weekdays: weekdays }; - const sortedData = [...tempQuotation].sort((a, b) => { - const aValidPeriod = dayjs(a.use_dates_end).diff(dayjs(a.use_dates_start)); - const bValidPeriod = dayjs(b.use_dates_end).diff(dayjs(b.use_dates_start)); - - if (aValidPeriod !== bValidPeriod) { - return aValidPeriod - bValidPeriod; - } - const aGroupSize = a.group_size_max - a.group_size_min; - const bGroupSize = b.group_size_max - b.group_size_min; - - return aGroupSize - bGroupSize; - }); - setQuotation(sortedData); - setQuotationTableVisible(false); - } - const quotationTableVisibleCancel = () => { - setQuotationTableVisible(false); - } - - - const handleBatchImportOK = () => { - const tempBatchImportData = batchImportData.map(item => { - const { tag, validPeriod, ...rest } = item; - return rest; - }); - const newData = [...quotation, ...tempBatchImportData]; - const sortedData = [...newData].sort((a, b) => { - if (a.group_size_min !== b.group_size_min) { - return a.group_size_min - b.group_size_min; - } - - return a.group_size_max - b.group_size_max; - }); - - - setQuotation(sortedData); - setBatchImportPriceVisible(false); - } - - - - const columns = [ - { title: t('products:adultPrice'), dataIndex: 'adult_cost', width: '10%', editable: true }, - { title: t('products:childrenPrice'), dataIndex: 'child_cost', width: '10%', editable: true }, - { title: t('products:currency'), dataIndex: 'currency', width: '10%', editable: true }, - { - title: t('products:Types'), - dataIndex: 'unit', - width: '10%', - editable: true, - render: (text) => (text === '0' ? '每人' : text === '1' ? '每团' : text), - }, - { - title: t('products:number'), - dataIndex: 'group_size', - width: '20%', - editable: true, - render: (_, record) => `${record.group_size_min}-${record.group_size_max}` - }, - - { - title: t('products:validityPeriod'), - dataIndex: 'validityPeriod', - width: '20%', - editable: true, - render: (_, record) => `${record.use_dates_start}-${record.use_dates_end}` - }, - - { title: t('products:Weekdays'), dataIndex: 'weekdays', width: '10%' }, - - ]; - - // 根据条件判断是否要添加操作列 - if (!isCanEditable) { - columns.push({ - title: t('products:operation'), - dataIndex: 'operation', - render: (_, record, index) => { - const canEdit = record.audit_state_id === -1; - return ( - - {canEdit ? ( - edit(record, index)} style={{ marginRight: 8 }}>{t('Edit')} - ) : ( - {t('Edit')} - )} - {canEdit ? ( - handleDelete(index)}> - {t('Delete')} - - ) : ( - {t('Delete')} - )} - - ); - } - }); - } - - const handleTagClick = (tag) => { - setSelectedTag(tag); - const matchedLanguage = HTLanguageSets.find(language => language.label === tag); - const key = matchedLanguage ? matchedLanguage.key : null; - form.setFieldsValue({ - lgc_details: { - title: lgc_details[key] ? lgc_details[key].title : '', - description: lgc_details[key] ? lgc_details[key].description : '' - } - }); - setLanguageStatus(key) - - }; - - const showModal = () => setIsModalVisible(true); - - const handleOk = () => { - if (!selectedTag) return; - if (!remainderLanguage.some(item => item.label === selectedTag)) return; - if (remainderLanguage.includes(selectedTag)) return; - let tempRemainderLanguage = remainderLanguage.filter((item) => { - return item.label !== selectedTag; - }) - - - const matchedLanguage = HTLanguageSets.find(HTLanguage => HTLanguage.label === selectedTag); - const languageKey = parseInt(matchedLanguage.key) - if (!(languageKey in lgc_details)) { - const tempLgc_details = { - ...lgc_details, [languageKey]: { - title: "", - lgc: languageKey, - description: "", - id: "" - } - } - setLgc_details(tempLgc_details) - } - - setRemainderLanguage(tempRemainderLanguage) - setTags([...tags, selectedTag]) - - setSelectedTag(null); - setIsModalVisible(false); - } - - const handleCancel = () => setIsModalVisible(false); - - - const handleTagChange = (value) => { - setSelectedTag(value); - }; - - const handleChange = (field, value) => { - // 更新整个 lgc_details 对象 - const updatedLgcDetails = { - ...lgc_details, - [languageStatus]: { - ...lgc_details[languageStatus], - [field]: value, - lgc: languageStatus.toString(), - id: lgc_details[languageStatus]?.id || '' - } - }; - setLgc_details(updatedLgcDetails) - - }; - - const handleDayClick = (dayIndex) => { - const dayOfWeek = (dayIndex % 7) + 1; - - setSelectedDays((prevSelectedDays) => { - const updatedDays = prevSelectedDays.includes(dayOfWeek) - ? prevSelectedDays.filter((d) => d !== dayOfWeek) - : [...prevSelectedDays, dayOfWeek]; - const weekdaysString = updatedDays.sort().join(','); - setWeekdays(weekdaysString); - return updatedDays; - }); - }; - - //树组件方法 - const handleNodeSelect = (_, { node }) => { - setSelectedNodeid(node.key); - // const fatherKey = node.key.split('-')[0]; - const fatherKey = node._raw.info.product_type_id; - setSelectedCategory(productProject[fatherKey]); - setTags([languageLabel]); - // 如果点击的是同一个节点,不做任何操作 - if (selectedNodeid === node.key) return; - setLanguageStatus(language); - const matchedLanguage = HTLanguageSets.find(HTLanguage => HTLanguage.key === language.toString()); - const languageLabelRefresh = matchedLanguage.label; - setLanguageLabel(languageLabelRefresh); - setSelectedTag(languageLabelRefresh); - setRemainderLanguage(HTLanguageSets.filter(item => item.key !== language.toString())); - // setEditingProduct(node._raw); - if (!node._raw.info.id) { - let infoData = node._raw.info; - setInfo(node._raw.info); - const newLgcDetails = node._raw.lgc_details - setSelectedNodeid(node.key); - form.setFieldsValue({ - info: { - id: infoData.id || "", - title: infoData.title || "", - code: infoData.code || "", - type: infoData.product_type_id || "", - audit_state: "-1", - create_date: infoData.create_date || "", - created_by: infoData.created_by || "", - travel_agency_id: travel_agency_id || "", - travel_agency_name: activeAgency.travel_agency_name || "", - lastedit_changed: infoData.lastedit_changed || "", - remarks: infoData.remarks || "", - duration: infoData.duration || "", - duration_unit: infoData.duration_unit || "", - open_weekdays: infoData.open_weekdays || "", - recommends_rate: infoData.recommends_rate || "", - dept: infoData.dept_id || "", - display_to_c: infoData.display_to_c || "", - km: infoData.km || "", - city_name: infoData.city_name || "", - city_id: infoData.city_id || "", - // product_type_name: infoData.product_type_name || "", - // dept_name: infoData.dept_name || "", - - }, - lgc_details: { - lgc: language, - title: newLgcDetails[language]?.title || '', - description: newLgcDetails[language]?.description || '' - } - }) - setLgc_details([]) - setQuotation([{ - adult_cost: 0, - child_cost: 0, - currency: '', - group_size_min: 0, - group_size_max: 0, - id: '', - lastedit_changed: '', - use_dates_start: '', - use_dates_end: '', - weekdays: '', - tempKey: Math.random() - }]) - return - } else { - let initialQuotationData = null; - let infoData = null; - let lgcDetailsData = null; - console.log("") - // productsData[fatherKey].forEach(element => { - // if (element.info.id === node._raw.info.id) { - // initialQuotationData = element.quotation; - // infoData = element.info; - // lgcDetailsData = element.lgc_details.map(item => { - // const newItem = { - // ...item, - // description: item.descriptions, - // }; - // delete newItem.descriptions; - // return newItem; - // }); - // } - // }); - // const quotationData = initialQuotationData.map(element => { - // const updatedObject = { - // ...element, - // unit: element.unit_id, - // tempKey: Math.random() - // }; - // delete updatedObject.unit_name; - // delete updatedObject.unit_id; - // // delete updatedObject.audit_state_id; - // delete updatedObject.audit_state_name; - // return updatedObject; - // }); - - - // if (!node._raw.info.id) { - - // } - // // 累积 lgc_details 数据 - // let newLgcDetails = {}; - // if (lgcDetailsData) { - // lgcDetailsData.forEach(element => { - // newLgcDetails[element.lgc] = element; - // }); - // } - - // setLgc_details(newLgcDetails); - - - // let sortedData = [...quotationData].sort((a, b) => { - // // 计算有效期范围大小 - // const aValidPeriod = dayjs(a.use_dates_end).diff(dayjs(a.use_dates_start)); - // const bValidPeriod = dayjs(b.use_dates_end).diff(dayjs(b.use_dates_start)); - - // // 按照有效期范围大小升序排序 - // if (aValidPeriod !== bValidPeriod) { - // return aValidPeriod - bValidPeriod; - // } - - // // 如果有效期范围相同,则按照人数范围大小升序排序 - // const aGroupSize = a.group_size_max - a.group_size_min; - // const bGroupSize = b.group_size_max - b.group_size_min; - - // return aGroupSize - bGroupSize; - // }); - - // const tempInfo = { - // id: infoData.id || "", - // title: infoData.title || "", - // code: infoData.code || "", - // type: infoData.product_type_id || "", - // create_date: infoData.create_date || "", - // created_by: infoData.created_by || "", - // travel_agency_id: travel_agency_id || "", - // travel_agency_name: activeAgency.travel_agency_name || "", - // lastedit_changed: infoData.lastedit_changed || "", - // remarks: infoData.remarks || "", - // duration: infoData.duration || "", - // duration_unit: infoData.duration_unit || "", - // open_weekdays: infoData.open_weekdays || "", - // recommends_rate: infoData.recommends_rate || "", - // dept: infoData.dept_id || "", - // display_to_c: infoData.display_to_c || "", - // km: infoData.km || "", - // city_name: infoData.city_name || "", - // city_id: infoData.city_id || "", - // product_type_name: infoData.product_type_name || "", - // dept_name: infoData.dept_name || "", - // }; - // setInfo(tempInfo); - // setQuotation(sortedData); - // if (node._raw.info.id) { - // form.setFieldsValue({ - // info: tempInfo, - // lgc_details: { - // lgc: language, - // title: newLgcDetails[language]?.title || '', - // description: newLgcDetails[language]?.description || '' - // } - // }); - // } - } - - }; - -const isPermitted = useAuthStore((state) => state.isPermitted); -const [editable, setEditable] = useState(true); + const isPermitted = useAuthStore((state) => state.isPermitted); + const [editable, setEditable] = useState(true); useEffect(() => { const notAudit = activeAgency.audit_state_id < 0 || activeAgency.audit_state_id === 3; const hasAuditPer = isPermitted(PERM_PRODUCTS_OFFER_AUDIT); const hasEditPer = isPermitted(PERM_PRODUCTS_OFFER_PUT); - setEditable(hasAuditPer ? true : (notAudit && hasEditPer)); + setEditable(hasAuditPer ? true : notAudit && hasEditPer); // setEditable(true); // debug: 0 // console.log('editable', hasAuditPer, (notAudit && hasEditPer)); return () => {}; - }, [activeAgency, editingProduct]) - - //新增产品 - const newProduct = useNewProductRecord(); - // const { language } = useDefaultLgc(); - const handelAddProduct = () => { - // 找到对应的产品类型节点 - // const productTypeNode = treeData.find(item => item.key === addProductType); - const copyNewProduct = structuredClone(newProduct); - copyNewProduct.info.title = addproductName; - copyNewProduct.info.product_type_id = productsTypesMapVal[addProductType].value; - copyNewProduct.info.product_type_name = productsTypesMapVal[addProductType].label; - copyNewProduct.lgc_details[0].lgc = language; - setEditingProduct(copyNewProduct); - setAddProductVisible(false); - return false; - const tempAddData = { - info: { - id: "", - title: addproductName, - code: "", - type: addProductType, - create_date: "", - created_by: "", - travel_agency_id: "", - travel_agency_name: "", - lastedit_changed: "", - remarks: "", - duration: "", - duration_unit: "", - open_weekdays: "", - recommends_rate: "", - dept: "", - display_to_c: "", - km: "", - city_name: "", - city_id: "", - product_type_name: "", - dept_name: "", - }, - lgc_details: [ - ], - quotation: [] - } - const newChildren = [ - ...productTypeNode.children, - { - title: addproductName, - key: `${addProductType}-${Date.now()}`, - _raw: tempAddData - } - - ]; - // // 创建新的 treeData 数组,确保 React 能够检测到更改 - const newTreeData = treeData.map(item => { - if (item.key === addProductType) { - return { - ...item, - children: newChildren, - }; - } - return item; - }); - // 更新 treeData - // setEditingProduct(null); - setTreeData(newTreeData); - - let tempProductDataList = productsData[addProductType]; - tempProductDataList.push(tempAddData); - const newProductsData = { - ...productsData, // 假设使用了展开运算符来复制现有数组 - [addProductType]: tempProductDataList - }; - setProductsData(newProductsData); - setAddProductVisible(false); - } - - const renderFormItem = (item) => { - switch (item.code) { - case "duration": - return ; - case "display_to_c": - return ( - - ); - case "dept_name": - return ; - case "city_name": - return ; - default: - return ; - } - }; + }, [activeAgency, editingProduct]); //保存产品 const onSave = async (values) => { - let tempInfo - if (info.id === "") { + let tempInfo; + if (info.id === '') { tempInfo = { ...info, ...values.info, city_name: values.info.city_name.label, - audit_state: "-1" - } + audit_state: '-1', + }; delete tempInfo.product_type_name; delete tempInfo.dept_name; - let tempQuotation = quotation.map(element => { + let tempQuotation = quotation.map((element) => { const updateData = { ...element, - audit_state: "-1" - } - delete updateData.tempKey - return updateData - }) - let tempLgc_details = [{ ...lgc_details }] + audit_state: '-1', + }; + delete updateData.tempKey; + return updateData; + }); + let tempLgc_details = [{ ...lgc_details }]; const tempData = { travel_agency_id, info: tempInfo, quotation: tempQuotation, - lgc_details: Object.values(lgc_details) + lgc_details: Object.values(lgc_details), }; - console.log("tempData", tempData); + console.log('tempData', tempData); const { errcode, result } = await postJSON(`${HT_HOST}/Service_BaseInfoWeb/agency_product_save`, tempData); - console.log("result", result); + console.log('result', result); if (errcode === 0) { - message.success("保存成功"); - setDataFetched(false); + message.success('保存成功'); } else { message.error(`保存失败: ${result}`); } - return + return; } tempInfo = { ...info, ...values.info, - audit_state: "-1" - } + audit_state: '-1', + }; - console.log("tempInfo", tempInfo) + console.log('tempInfo', tempInfo); - let tempQuotation = quotation.map(element => { + let tempQuotation = quotation.map((element) => { const updateData = { ...element, - audit_state: "-1" - } - return updateData - }) - + audit_state: '-1', + }; + return updateData; + }); const tempData = { travel_agency_id, info: tempInfo, quotation: tempQuotation, - lgc_details: Object.values(lgc_details) + lgc_details: Object.values(lgc_details), }; - console.log("tempData", tempData) + console.log('tempData', tempData); // const { errcode, result } = await postProductsSave(tempData); const { errcode, result } = await postJSON(`${HT_HOST}/Service_BaseInfoWeb/agency_product_save`, tempData); if (errcode === 0) { - message.success("保存成功"); - setDataFetched(false); + message.success('保存成功'); } else { message.error(`保存失败: ${result}`); } - return - + return; }; //提交审核方法 @@ -1055,303 +226,52 @@ const [editable, setEditable] = useState(true); formData.append('travel_agency_id', travel_agency_id); try { const { errcode, result } = await postForm(`${HT_HOST}/Service_BaseInfoWeb/agency_submit`, formData); - console.log("errcode", errcode); + console.log('errcode', errcode); if (errcode === 0) { - message.success("提交审核成功"); + message.success('提交审核成功'); navigate(`/products/${travel_agency_id}/${use_year}/${audit_state}/audit`); } else { - message.error("提交审核失败"); + message.error('提交审核失败'); } - console.log("result", result); + console.log('result', result); } catch (error) { - console.error("提交审核请求失败", error); - message.error("提交审核请求失败"); + console.error('提交审核请求失败', error); + message.error('提交审核请求失败'); } }; - // const handleStateChange = (newState) => { - // console.log("newState",newState) - // if(newState === 'addProducts'){ - // setAddProductVisible(true); - // } - // if(newState === 'submitReview'){ - // submitReview(); - // } - // }; - return ( - - setAddProductVisible(true)} handleSubmitForAudit={submitReview} editable={editable} /> - // + setAddProductVisible(true)} + handleSubmitForAudit={submitReview} + editable={editable} + /> }> - {isEmpty(agencyProducts) ? : - <> - - {/* onNodeSelect={handleNodeSelect} */} - - -
- - {/* */} - {/* */} - {/* - - - - - */} - {/* */} - - {/* */} -
- {/* - } - > */} - {/*

{t('products:EditComponents.info')}

- - {selectedCategory.map((item, index) => { - return ( - - - {renderFormItem(item)} - - - ); - })} - */} - - {/*
- {tags.map(tag => ( - handleTagClick(tag)} - color={tag === selectedTag ? 'blue' : undefined} - style={{ cursor: 'pointer' }} - > - {tag} - - ))} - + -
- - - */} - - {/* - handleChange('title', e.target.value)} - disabled={isCanEditable} - /> - - - handleChange('description', e.target.value)} - disabled={isCanEditable} - /> - */} - {/*
*/} - {/* */} - - {/* */} - {/*

{t('products:supplierQuotation')}

*/} - {/* - - { - // !isCanEditable && - - } - - { - - } - */} - - {/* */} - {/* */} - - - {/* */} - - {/* */} - - {/* } onClick={() => setAddProductVisible(true)} /> */} -{/* - } - > - - } onClick={() => setAddProductVisible(true)} /> - - - } onClick={async () => { - const formData = new FormData(); - formData.append('use_year', use_year); - formData.append('travel_agency_id', travel_agency_id); - const { errcode, result } = await postForm(`${HT_HOST}/Service_BaseInfoWeb/agency_submit`, formData); - console.log("errcode", errcode); - if (errcode === 0) { - message.success("提交审核成功"); - navigate(`/products/${travel_agency_id}/${use_year}/${audit_state}/audit`); - } - console.log("result", result); - }} /> - - */} - {/* */} - {/* */} - - - - {/* setBatchImportPriceVisible(false)} - width={'90%'} - > - - */} - - setAddProductVisible(false)} - > -

选择产品类别

- - - -

新增产品名称

- setAddProductName(e.target.value)} - /> -
-{/* - -

成人价

- setCurrentQuotationRecord({ ...currentQuotationRecord, adult_cost: e })} /> -

儿童价

- setCurrentQuotationRecord({ ...currentQuotationRecord, child_cost: e })} /> -

币种

- -

类型

- - -

人等

-
-

有效期

- { - setCurrentQuotationRecord({ - ...currentQuotationRecord, - use_dates_start: dates[0], - use_dates_end: dates[1] - }); - }} - /> -

周末

- {days.map((day, index) => ( - - ))} - */} - } - + {isEmpty(agencyProducts) ? ( + + ) : ( + <> + + {/* onNodeSelect={handleNodeSelect} */} + + +
+ + +
+
+ + setAddProductVisible(false)} onCancel={() => setAddProductVisible(false)} /> + + + )} + ); } export default Detail; - - diff --git a/src/views/products/Detail/NewProductModal.jsx b/src/views/products/Detail/NewProductModal.jsx new file mode 100644 index 0000000..538e673 --- /dev/null +++ b/src/views/products/Detail/NewProductModal.jsx @@ -0,0 +1,115 @@ +import { useState, useEffect } from 'react'; +import { Form, Modal, Input } from 'antd'; +import { objectMapper } from '@/utils/commons'; +import { useTranslation } from 'react-i18next'; + +import ProductsTypesSelector from '@/components/ProductsTypesSelector'; +import useProductsStore from '@/stores/Products/Index'; +import { useNewProductRecord, useProductsTypesMapVal } from '@/hooks/useProductsSets'; +import { useDefaultLgc } from '@/i18n/LanguageSwitcher'; + +export const NewProductsForm = ({ initialValues, onFormInstanceReady, ...props }) => { + const { t } = useTranslation(); + const [form] = Form.useForm(); + + useEffect(() => { + onFormInstanceReady(form); + }, []); + + const onValuesChange = (changeValues, allValues) => {}; + + return ( +
+ + + + + + + + ); +}; +const formValuesMapper = (values) => { + const destinationObject = { + 'products_types': { + key: 'products_types', + transform: (value) => { + return Array.isArray(value) ? value.map((ele) => ele.key).join(',') : value ? value.value : '-1'; + }, + }, + }; + let dest = {}; + const { ...omittedValue } = values; + dest = { ...omittedValue, ...objectMapper(values, destinationObject) }; + for (const key in dest) { + if (Object.prototype.hasOwnProperty.call(dest, key)) { + dest[key] = typeof dest[key] === 'string' ? (dest[key] || '').trim() : dest[key]; + } + } + // omit empty + // Object.keys(dest).forEach((key) => (dest[key] == null || dest[key] === '' || dest[key].length === 0) && delete dest[key]); + return dest; +}; +/** + * + */ +export const NewProductModal = ({ source, action = '#' | 'o', open, onSubmit, onCancel, initialValues }) => { + const { t } = useTranslation(); + const [formInstance, setFormInstance] = useState(); + const [setEditingProduct] = useProductsStore((state) => [state.setEditingProduct]); + + const [copyLoading, setCopyLoading] = useState(false); + const productsTypesMapVal = useProductsTypesMapVal(); + const newProduct = useNewProductRecord(); + const { language } = useDefaultLgc(); + const handelAddProduct = (param) => { + const copyNewProduct = structuredClone(newProduct); + copyNewProduct.info.title = param.title; + copyNewProduct.info.product_type_id = productsTypesMapVal[param.products_type.value].value; + copyNewProduct.info.product_type_name = productsTypesMapVal[param.products_type.value].label; + copyNewProduct.lgc_details[0].lgc = language; + copyNewProduct.lgc_details[0].title = param.title; + setEditingProduct(copyNewProduct); + if (typeof onSubmit === 'function') { + onSubmit(); + } + return false; + }; + return ( + <> + { + onCancel(); + formInstance?.resetFields(); + }} + destroyOnClose + onOk={async () => { + try { + const values = await formInstance?.validateFields(); + // formInstance?.resetFields(); + const dest = formValuesMapper(values); + handelAddProduct(dest); + } catch (error) { + console.log('Failed:', error); + } + }}> + { + setFormInstance(instance); + }} + /> + + + ); +}; +export default NewProductModal; diff --git a/src/views/products/Detail/ProductInfoForm.jsx b/src/views/products/Detail/ProductInfoForm.jsx index 840d9c7..4472b26 100644 --- a/src/views/products/Detail/ProductInfoForm.jsx +++ b/src/views/products/Detail/ProductInfoForm.jsx @@ -22,7 +22,7 @@ import { PERM_PRODUCTS_MANAGEMENT, PERM_PRODUCTS_OFFER_AUDIT, PERM_PRODUCTS_OFFE const { RangePicker } = DatePicker; -const InfoForm = ({ formInstance, onSubmit, onReset, onValuesChange, editable, showSubmit, confirmText, formName, loading, ...props }) => { +const InfoForm = ({ onSubmit, onReset, onValuesChange, editable, showSubmit, confirmText, formName, loading, ...props }) => { const { t } = useTranslation('products'); const isPermitted = useAuthStore((state) => state.isPermitted); const [agencyProducts, editingProduct, setEditingProduct] = useProductsStore((state) => [state.agencyProducts, state.editingProduct, state.setEditingProduct]); @@ -49,7 +49,9 @@ const InfoForm = ({ formInstance, onSubmit, onReset, onValuesChange, editable, s return () => {}; }, [editingProduct?.info?.id]); - const ignoreEditable = isPermitted(PERM_PRODUCTS_OFFER_AUDIT); + const topPerm = isPermitted(PERM_PRODUCTS_OFFER_AUDIT); + const isNew = isEmpty(editingProduct?.info?.id); + const ignoreEditable = topPerm || isNew; const onFinish = (values) => { console.log('Received values of form, origin form value: \n', values);
- setCurrentQuotationRecord({ ...currentQuotationRecord, group_size_min: e })} - style={{ width: '50%', marginRight: '10px' }} - /> - - - setCurrentQuotationRecord({ ...currentQuotationRecord, group_size_max: e })} - style={{ width: '50%', marginLeft: '10px' }} - /> -