From 6bd60b7578a319d88dae5a56547eae99f344941d Mon Sep 17 00:00:00 2001 From: Lei OT Date: Mon, 21 Jul 2025 14:49:51 +0800 Subject: [PATCH 01/56] =?UTF-8?q?perf:=20=E4=BF=9D=E5=AD=98=E4=BA=A7?= =?UTF-8?q?=E5=93=81:=20=E4=BF=A1=E6=81=AF=E5=8F=98=E6=9B=B4=E5=AD=97?= =?UTF-8?q?=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/products/Detail/ProductInfo.jsx | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/views/products/Detail/ProductInfo.jsx b/src/views/products/Detail/ProductInfo.jsx index d30d8a3..43f19ab 100644 --- a/src/views/products/Detail/ProductInfo.jsx +++ b/src/views/products/Detail/ProductInfo.jsx @@ -5,7 +5,7 @@ import { useProductsTypesMapVal, useNewProductRecord } from '@/hooks/useProducts import useProductsStore, { postProductsSaveAction } from '@/stores/Products/Index'; import useAuthStore from '@/stores/Auth'; import { PERM_PRODUCTS_MANAGEMENT, PERM_PRODUCTS_OFFER_PUT, PERM_PRODUCTS_INFO_PUT, PERM_PRODUCTS_NEW } from '@/config'; -import { isEmpty, pick } from '@/utils/commons'; +import { isEmpty, objectMapper, pick, unique } from '@/utils/commons'; import ProductInfoForm from './ProductInfoForm'; import { usingStorage } from '@/hooks/usingStorage'; import Extras from './Extras'; @@ -50,13 +50,20 @@ const ProductInfo = ({ ...props }) => { setLgcEdits({}); setInfoEditStatus(''); + setEditKeys([]); return () => {}; }, [activeAgency, editingProduct]); const [infoEditStatus, setInfoEditStatus] = useState(''); const [lgcEdits, setLgcEdits] = useState({}); - const onValuesChange = (changedValues, forms) => { + // const [editChanged, setEditChanged] = useState({}); + const [editKeys, setEditKeys] = useState([]); + + const onValuesChange = (changedValues) => { // console.log('onValuesChange', changedValues); + const changedKeys = objectMapper(changedValues, { 'city': 'city_id', 'dept': 'dept_id', 'product_title': 'title'}); + setEditKeys(prev => unique([...prev, ...Object.keys(changedKeys)])); + // const preValues = pick(editingProduct.info, editKeys); if ('product_title' in changedValues) { setInfoEditStatus('2'); setLgcEdits({...lgcEdits, '2': {'edit_status': '2'}}); @@ -71,6 +78,9 @@ const ProductInfo = ({ ...props }) => { const onSave = async (err, values, forms) => { values.travel_agency_id = activeAgency.travel_agency_id; + const editChanged = pick(editingProduct.info, editKeys); + // console.log("editKeys pre values", editKeys, editChanged); + const copyNewProduct = structuredClone(newProductRecord); const poster = { // ...(topPerm ? { } : { 'audit_state': -1 }), // 高级权限: 不变更状态值 @@ -78,9 +88,10 @@ const ProductInfo = ({ ...props }) => { // "created_by": userId, 'travel_agency_id': activeAgency.travel_agency_id, // "travel_agency_name": "", - // "lastedit_changed": "", - "edit_status": infoEditStatus || editingProduct.info.edit_status, + 'lastedit_changed': editChanged, // isEmpty(editChanged) ? "" : JSON.stringify(editChanged), + 'edit_status': infoEditStatus || editingProduct.info.edit_status, }; + // console.log("ready to post", poster); const copyFields = pick(editingProduct.info, ['product_type_id']); // 'title', const readyToSubInfo = { ...copyNewProduct.info, ...editingProduct.info, title: editingProduct.info.product_title, ...values.info, ...copyFields, ...poster }; // console.log('onSave', editingProduct.info, readyToSubInfo); @@ -95,8 +106,9 @@ const ProductInfo = ({ ...props }) => { } } - // console.log('before save', '\n lgcEdits:', lgcEdits, '\n mergedLgc', mergedLgc); + // console.log('before save', readyToSubInfo, '\n lgcEdits:', lgcEdits, '\n mergedLgc', mergedLgc); // return false; // debug: 0 + // throw new Error("Test save"); /** 提交保存 */ setLoading(true); const { success, result } = await postProductsSaveAction({ From 3c7028cfc63233c0a346a09f0f747c7936bbf27c Mon Sep 17 00:00:00 2001 From: Lei OT Date: Mon, 21 Jul 2025 14:50:07 +0800 Subject: [PATCH 02/56] # --- src/config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config.js b/src/config.js index 25c1040..d714edd 100644 --- a/src/config.js +++ b/src/config.js @@ -42,7 +42,7 @@ export const PERM_TRAIN_TICKET = '/train-ticket/all' // 价格管理 export const PERM_PRODUCTS_MANAGEMENT = '/products/*'; // 管理 export const PERM_PRODUCTS_NEW = '/products/new'; // 新增产品 -export const PERM_PRODUCTS_INFO_AUDIT = '/products/info/audit'; // 信息.审核 +export const PERM_PRODUCTS_INFO_AUDIT = '/products/info/audit'; // 信息.审核 @deprecated export const PERM_PRODUCTS_INFO_PUT = '/products/info/put'; // 信息.录入 export const PERM_PRODUCTS_OFFER_AUDIT = '/products/offer/audit'; // 价格.审核 export const PERM_PRODUCTS_OFFER_PUT = '/products/offer/put'; // 价格.录入 From 5c5d10ef274086f6178ff5b6f6cb3a7131d4065b Mon Sep 17 00:00:00 2001 From: Lei OT Date: Fri, 18 Jul 2025 14:25:10 +0800 Subject: [PATCH 03/56] =?UTF-8?q?perf:=20=E5=8C=85=E4=BB=B7=E7=BA=BF?= =?UTF-8?q?=E8=B7=AF=E5=A2=9E=E5=8A=A0=E2=80=9C=E5=8C=85=E4=BB=B7=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E2=80=9D=E3=80=81=E2=80=9C=E6=8E=92=E5=BA=8F=E2=80=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/locales/en/products.json | 2 ++ public/locales/zh/products.json | 2 ++ src/hooks/useProductsSets.js | 27 +++++++++++++++-- src/views/products/Detail/ProductInfoForm.jsx | 29 ++++++++++++++++++- 4 files changed, 56 insertions(+), 4 deletions(-) diff --git a/public/locales/en/products.json b/public/locales/en/products.json index 7f4357f..529a790 100644 --- a/public/locales/en/products.json +++ b/public/locales/en/products.json @@ -49,6 +49,8 @@ "RecommendsRate": "Recommends Rate", "OpenWeekdays": "Open Weekdays", "DisplayToC": "Display To C", + "SortOrder": "Sort order", + "subTypeD": "Package Type", "Dept": "Dept", "Code": "Code", "City": "City", diff --git a/public/locales/zh/products.json b/public/locales/zh/products.json index a0ef6fa..dc7ff30 100644 --- a/public/locales/zh/products.json +++ b/public/locales/zh/products.json @@ -50,6 +50,8 @@ "RecommendsRate": "推荐指数", "OpenWeekdays": "开放时间", "DisplayToC": "报价信显示", + "SortOrder": "排序", + "subTypeD": "包价类型", "Dept": "小组", "Code": "简码", "City": "城市", diff --git a/src/hooks/useProductsSets.js b/src/hooks/useProductsSets.js index 6a3d464..6db9308 100644 --- a/src/hooks/useProductsSets.js +++ b/src/hooks/useProductsSets.js @@ -96,20 +96,21 @@ export const useProductsAuditStatesMapVal = (value) => { }; /** - * @ignore + * */ export const useProductsTypesFieldsets = (type) => { const [isPermitted] = useAuthStore((state) => [state.isPermitted]); const infoDefault = [['city'], ['title']]; const infoAdmin = ['title', 'product_title', 'code', 'remarks', 'dept']; // 'display_to_c' - const infoDisplay = isPermitted(PERM_PRODUCTS_MANAGEMENT) ? ['display_to_c'] : []; + const infoDisplay = isPermitted(PERM_PRODUCTS_MANAGEMENT) ? ['display_to_c', 'sort_order'] : []; const infoRecDisplay = isPermitted(PERM_PRODUCTS_MANAGEMENT) ? ['recommends_rate'] : []; + const subTypeD = isPermitted(PERM_PRODUCTS_MANAGEMENT) ? ['sub_type_D'] : []; const infoTypesMap = { '6': [[...infoDisplay], []], 'B': [['km', ...infoDisplay], []], 'J': [[...infoRecDisplay, 'duration', ...infoDisplay], ['description']], 'Q': [[...infoRecDisplay, 'duration', ...infoDisplay], ['description']], - 'D': [[...infoRecDisplay, 'duration', ...infoDisplay], ['description']], + 'D': [[...infoRecDisplay, 'duration', ...infoDisplay, ...subTypeD], ['description']], '7': [[...infoRecDisplay, 'duration', 'open_weekdays', ...infoDisplay], ['description']], 'R': [[...infoDisplay], ['description']], '8': [[...infoDisplay], []], @@ -152,6 +153,8 @@ export const useNewProductRecord = () => { 'create_date': '', 'created_by': '', 'edit_status': 2, + 'sort_order': '', + 'sub_type_D': '', }, lgc_details: [ { @@ -182,3 +185,21 @@ export const useNewProductRecord = () => { ], }; }; + +export const PackageTypes = [ + { key: 35001, value: 35001, label: '飞机接送' }, + { key: 35002, value: 35002, label: '车站接送' }, + { key: 35003, value: 35003, label: '码头接送' }, + { key: 35004, value: 35004, label: '一天游' }, + { key: 35005, value: 35005, label: '半天游' }, + { key: 35006, value: 35006, label: '夜间活动' }, + { key: 35007, value: 35007, label: '大车游' }, + { key: 35008, value: 35008, label: '单车单导' }, + { key: 35009, value: 35009, label: '单租车' }, + { key: 35010, value: 35010, label: '单导游' }, + { key: 35011, value: 35011, label: '火车站接送' }, + { key: 35012, value: 35012, label: '门票预定' }, + { key: 35013, value: 35013, label: '车导费' }, + { key: 35014, value: 35014, label: '其它(餐补等)' }, +]; + diff --git a/src/views/products/Detail/ProductInfoForm.jsx b/src/views/products/Detail/ProductInfoForm.jsx index 4642e57..dbb41e5 100644 --- a/src/views/products/Detail/ProductInfoForm.jsx +++ b/src/views/products/Detail/ProductInfoForm.jsx @@ -5,7 +5,7 @@ import { useTranslation } from 'react-i18next'; import { useWeekdays } from '@/hooks/useDatePresets'; import DeptSelector from '@/components/DeptSelector'; import CitySelector from '@/components/CitySelector'; -import { useProductsTypesFieldsets } from '@/hooks/useProductsSets'; +import { useProductsTypesFieldsets, PackageTypes } from '@/hooks/useProductsSets'; import useProductsStore from '@/stores/Products/Index'; import ProductInfoLgc from './ProductInfoLgc'; import ProductInfoQuotation from './ProductInfoQuotation'; @@ -306,6 +306,33 @@ function getFields(props) { , fieldProps?.display_to_c?.col || midCol ), + item( + 'sub_type_D', + 99, + + - - - - - - handleLngChange(e.target.value)}> - 中文 - English - - - - - - - + + + + + + + + handleLngChange(e.target.value)}> + 中文 + English + + + + + + + - ) + ); } -export default Login +export default Login; From 07e67c50fb56b0d321df60bd8d67723da399506a Mon Sep 17 00:00:00 2001 From: Lei OT Date: Wed, 23 Jul 2025 11:55:58 +0800 Subject: [PATCH 10/56] =?UTF-8?q?perf:=20=E4=BA=BA=E7=AD=89=E7=9A=84?= =?UTF-8?q?=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/useProductsSets.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hooks/useProductsSets.js b/src/hooks/useProductsSets.js index 17072c7..c291cbf 100644 --- a/src/hooks/useProductsSets.js +++ b/src/hooks/useProductsSets.js @@ -205,5 +205,5 @@ export const PackageTypes = [ ]; export const formatGroupSize = (min, max) => { - return max === 1000 ? min === 0 ? '不限人等' : `${min}人以上` : `${min}-${max}`; + return max === 1000 ? min === 0 ? '不分人等' : `${min}人以上` : `${min}-${max}`; }; From 9feadeb69d30606803b193291eff7a729c189a34 Mon Sep 17 00:00:00 2001 From: LiaoYijun Date: Wed, 23 Jul 2025 16:07:33 +0800 Subject: [PATCH 11/56] =?UTF-8?q?feat:=20=E4=BB=B7=E6=A0=BC=E5=8F=98?= =?UTF-8?q?=E6=9B=B4=E5=82=A8=E5=AD=98=E5=88=B0=E5=AF=B9=E8=B1=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/stores/Products/Index.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/stores/Products/Index.js b/src/stores/Products/Index.js index cb90470..7da1344 100644 --- a/src/stores/Products/Index.js +++ b/src/stores/Products/Index.js @@ -367,7 +367,7 @@ export const useProductsStore = create( } else { mergedList = quotationList.map(prevQuotation => { if (prevQuotation.key === formValues.key) { - const changedList = [] + const changedObject = {} for (const [key, value] of Object.entries(formValues)) { if (key === 'use_dates' || key === 'id' || key === 'key') continue @@ -375,9 +375,7 @@ export const useProductsStore = create( const hasChanged = preValue !== value if (hasChanged) { - changedList.push({ - [key]: preValue, - }) + changedObject[key] = value } } @@ -393,7 +391,7 @@ export const useProductsStore = create( use_dates_start: formValues.use_dates_start, use_dates_end: formValues.use_dates_end, weekdays: formValues.weekdays, - lastedit_changed: JSON.stringify(changedList, null, 2) + lastedit_changed: changedObject } } else { return prevQuotation From cdfb5b77d0eb930bda582ca68f959743d0d9e8c6 Mon Sep 17 00:00:00 2001 From: LiaoYijun Date: Wed, 23 Jul 2025 17:00:44 +0800 Subject: [PATCH 12/56] =?UTF-8?q?perf:=20=E5=88=A0=E9=99=A4=E4=B8=8D?= =?UTF-8?q?=E7=94=A8=E7=9A=84=20Log=E8=BF=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/app-logo.jpg | Bin 34937 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 public/app-logo.jpg diff --git a/public/app-logo.jpg b/public/app-logo.jpg deleted file mode 100644 index 0969a97e2dc500e2def13ff6d423329fa4d8cc48..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 34937 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 aN&pqAi8D$ugow+D|17ZoXW!E0^uGWAOmNx& From 2bbbae6f9449248afde740f54e351bf2f18f9f62 Mon Sep 17 00:00:00 2001 From: Lei OT Date: Wed, 23 Jul 2025 14:52:20 +0800 Subject: [PATCH 13/56] =?UTF-8?q?=E2=8F=B3feat:=20=E5=AE=A1=E6=A0=B8:=20?= =?UTF-8?q?=E6=9F=A5=E7=9C=8B=E4=BB=B7=E6=A0=BC=E5=8E=86=E5=8F=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/products/Audit.jsx | 135 +++++++++++++++++++++++++++-------- 1 file changed, 106 insertions(+), 29 deletions(-) diff --git a/src/views/products/Audit.jsx b/src/views/products/Audit.jsx index 43cadb0..873942c 100644 --- a/src/views/products/Audit.jsx +++ b/src/views/products/Audit.jsx @@ -17,47 +17,123 @@ import { ClockCircleFilled, ClockCircleOutlined, PlusCircleFilled, PlusCircleOut const parseJson = (str) => { let result; if (str === null || str === undefined || str === '') { - return []; + return {}; } try { result = JSON.parse(str); - return result; + return Array.isArray(result) ? result.reduce((acc, cur) => ({ ...acc, ...cur }), {}) : result; } catch (e) { - return []; + return {}; } }; - const columnsSets = t => [ - { key: 'adult', title: t('AgeType.Adult'), width: '12rem', render: (_, { adult_cost, currency, unit_id, unit_name, lastedit_changed }) => { - const _changed = parseJson(lastedit_changed)?.reduce((acc, cur) => ({...acc, ...cur}), {}); - const preValue = isNotEmpty(_changed.adult_cost) ?
{_changed.adult_cost}
: null; - return (
{preValue}{`${adult_cost} ${currency} / ${t(`PriceUnit.${unit_id}`)}`}
)} }, - { key: 'child', title: t('AgeType.Child'), width: '12rem', render: (_, { child_cost, currency, unit_id, unit_name, lastedit_changed }) => { - const _changed = parseJson(lastedit_changed)?.reduce((acc, cur) => ({...acc, ...cur}), {}); - const preValue = isNotEmpty(_changed.child_cost) ?
{_changed.child_cost}
: null; - return
{preValue}{`${child_cost} ${currency} / ${t(`PriceUnit.${unit_id}`)}`}
; - } }, + const columnsSets = (t, colorize = true) => [ + { + key: 'adult', + title: t('AgeType.Adult'), + width: '12rem', + render: (_, { adult_cost, currency, unit_id, unit_name, audit_state_id, lastedit_changed }) => { + const _changed = parseJson(lastedit_changed); + const ifCompare = colorize && ![-1, 1, 2].includes(audit_state_id); + const ifData = isNotEmpty(_changed.adult_cost) || isNotEmpty(_changed.unit_id) || isNotEmpty(_changed.currency); + const preValue = + ifCompare && ifData ? ( +
{`${_changed.adult_cost} ${_changed.currency || currency} / ${t(`PriceUnit.${_changed.unit_id || unit_id}`)}`}
+ ) : null; + const editCls = ifCompare && ifData ? 'text-danger' : ''; + return ( +
+ {preValue} + {`${adult_cost} ${currency} / ${t(`PriceUnit.${unit_id}`)}`} +
+ ); + }, + }, + { + key: 'child', + title: t('AgeType.Child'), + width: '12rem', + render: (_, { child_cost, currency, unit_id, unit_name, audit_state_id, lastedit_changed }) => { + const _changed = parseJson(lastedit_changed); + const ifCompare = colorize && ![-1, 1, 2].includes(audit_state_id); + const ifData = isNotEmpty(_changed.child_cost) || isNotEmpty(_changed.unit_id) || isNotEmpty(_changed.currency); + const preValue = + ifCompare && ifData ? ( +
{`${_changed.child_cost} ${_changed.currency || currency} / ${t(`PriceUnit.${_changed.unit_id || unit_id}`)}`}
+ ) : null; + const editCls = ifCompare && ifData ? 'text-danger' : ''; + return ( +
+ {preValue} + {`${child_cost} ${currency} / ${t(`PriceUnit.${unit_id}`)}`} +
+ ); + }, + }, // {key: 'unit', title: t('Unit'), }, { key: 'groupSize', dataIndex: ['group_size_min'], - title: t('group_size'), width: '6rem', + title: t('group_size'), + width: '6rem', render: (_, { audit_state_id, group_size_min, group_size_max, lastedit_changed }) => { - const _changed = parseJson(lastedit_changed)?.reduce((acc, cur) => ({...acc, ...cur}), {}); - const preValue = ![-1, 1, 2].includes(audit_state_id) && (isNotEmpty(_changed.group_size_min) || isNotEmpty(_changed.group_size_max)) ?
{`${_changed.group_size_min ?? group_size_min} - ${_changed.group_size_max ?? group_size_max}`}
: null; - return
{preValue}{formatGroupSize(group_size_min, group_size_max)}
; - } + const _changed = parseJson(lastedit_changed); + const preValue = + colorize && ![-1, 1, 2].includes(audit_state_id) && (isNotEmpty(_changed.group_size_min) || isNotEmpty(_changed.group_size_max)) ? ( +
{`${_changed.group_size_min ?? group_size_min} - ${_changed.group_size_max ?? group_size_max}`}
+ ) : null; + const editCls = colorize && ![-1, 1, 2].includes(audit_state_id) && (isNotEmpty(_changed.group_size_min) || isNotEmpty(_changed.group_size_max)) ? 'text-danger' : ''; + return ( +
+ {preValue} + {formatGroupSize(group_size_min, group_size_max)} +
+ ); + }, }, { key: 'useDates', dataIndex: ['use_dates_start'], - title: t('use_dates'), width: '12rem', - render: (_, { use_dates_start, use_dates_end, weekdays }) => `${use_dates_start} ~ ${use_dates_end}`, // + (weekdays ? `, ${t('OnWeekdays')}${weekdays}` : ''), + title: t('use_dates'), + width: '12rem', + render: (_, { use_dates_start, use_dates_end, weekdays, audit_state_id, lastedit_changed }) => { + const _changed = parseJson(lastedit_changed); + const preValue = + colorize && ![-1, 1, 2].includes(audit_state_id) && (isNotEmpty(_changed.use_dates_start) || isNotEmpty(_changed.use_dates_end)) ? ( +
+ {isNotEmpty(_changed.use_dates_start) ? {_changed.use_dates_start} : use_dates_start} ~{' '} + {isNotEmpty(_changed.use_dates_end) ? {_changed.use_dates_end} : use_dates_end} +
+ ) : null; + const editCls = colorize && ![-1, 1, 2].includes(audit_state_id) && (isNotEmpty(_changed.use_dates_start) || isNotEmpty(_changed.use_dates_end)) ? 'text-danger' : ''; + return ( +
+ {preValue} + {`${use_dates_start} ~ ${use_dates_end}`} +
+ ); + }, + }, + { + key: 'weekdays', + dataIndex: ['weekdays'], + title: t('Weekdays'), + width: '6rem', + render: (text, { weekdays, audit_state_id, lastedit_changed }) => { + const _changed = parseJson(lastedit_changed); + const ifCompare = colorize && ![-1, 1, 2].includes(audit_state_id); + const ifData = !isEmpty((_changed.weekdayList || []).filter(s => s)); + const preValue = + ifCompare && ifData ? ( +
{_changed.weekdayList}
+ ) : null; + const editCls = ifCompare && ifData ? 'text-danger' : ''; + return
{preValue}{text || t('Unlimited')}
; + }, }, - { key: 'weekdays', dataIndex: ['weekdays'], title: t('Weekdays'), width: '6rem', render: (text, r) => text || t('Unlimited') }, ]; -const PriceLogPopover = ({ title, fetchData, ...props}) => { +const PriceLogPopover = ({ title, fetchData, triggerProps={}, ...props}) => { const { t } = useTranslation('products'); const [open, setOpen] = useState(false); const [logData, setLogData] = useState([]); @@ -65,7 +141,7 @@ const PriceLogPopover = ({ title, fetchData, ...props}) => { const data = await fetchData(); setLogData(data); }; - const columns = [...columnsSets(t), { title: '时间', dataIndex: 'updatetime', key: 'updatetime'}]; + const columns = [...columnsSets(t, false), { title: '时间', dataIndex: 'updatetime', key: 'updatetime'}]; return ( { } content={ <> - +
} trigger={['click']} @@ -89,7 +165,7 @@ const PriceLogPopover = ({ title, fetchData, ...props}) => { onOpenChange={(v) => { setOpen(v); }}> - @@ -186,20 +262,21 @@ const PriceTable = ({ productType, dataSource, refresh }) => { }, { title: '', - key: 'action2', width: '6rem', + key: 'action2', width: '6rem', className: 'bg-white', onCell: (r, index) => ({ rowSpan: r.rowSpan, }), render: (_, r) => { const showPublicBtn = null; // r.pendingQuotation ? : null; - const btn2 = ( + const btn2 = r.pendingQuotation ? ( getRunning({ travel_agency_id, product_id: r.info.id, price_id: r.id })} {...{ travel_agency_id, product_id: r.info.id, price_id: r.id }} /> - ); - return
{btn2}
; + ) : null; + return
{btn2}
; }, } ]; From 9e09a5a1f6cfa8e25fa72ed4cbc5a5becc962ca8 Mon Sep 17 00:00:00 2001 From: LiaoYijun Date: Thu, 24 Jul 2025 09:55:23 +0800 Subject: [PATCH 14/56] =?UTF-8?q?perf:=20=E4=BB=B7=E6=A0=BC=E6=B2=A1?= =?UTF-8?q?=E6=9C=89=E6=94=B9=E5=8F=98=E8=BF=94=E5=9B=9E{}?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/stores/Products/Index.js | 4 ++-- src/views/products/Detail/ProductInfoForm.jsx | 8 ++++++++ src/views/products/Detail/ProductInfoQuotation.jsx | 1 + 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/stores/Products/Index.js b/src/stores/Products/Index.js index 7da1344..64ef53c 100644 --- a/src/stores/Products/Index.js +++ b/src/stores/Products/Index.js @@ -360,7 +360,7 @@ export const useProductsStore = create( if (formValues.fresh) { formValues.key = generateId() - formValues.lastedit_changed = '' + formValues.lastedit_changed = {} formValues.audit_state_id = -1 // 新增, formValues.fresh = false // 添加到列表后就不是新纪录,保存要修改原来记录 mergedList = [...quotationList,...[formValues]] @@ -369,7 +369,7 @@ export const useProductsStore = create( if (prevQuotation.key === formValues.key) { const changedObject = {} for (const [key, value] of Object.entries(formValues)) { - if (key === 'use_dates' || key === 'id' || key === 'key') continue + if (key === 'use_dates' || key === 'id' || key === 'key' || key === 'weekdayList') continue const preValue = prevQuotation[key] const hasChanged = preValue !== value diff --git a/src/views/products/Detail/ProductInfoForm.jsx b/src/views/products/Detail/ProductInfoForm.jsx index a6daa43..1df2fd8 100644 --- a/src/views/products/Detail/ProductInfoForm.jsx +++ b/src/views/products/Detail/ProductInfoForm.jsx @@ -223,6 +223,14 @@ function getFields(props) { , fieldProps?.city?.col || midCol ), + item( + 'city_list', + 99, + + + , + fieldProps?.city_list?.col || midCol + ), item( 'dept', 99, diff --git a/src/views/products/Detail/ProductInfoQuotation.jsx b/src/views/products/Detail/ProductInfoQuotation.jsx index db79f31..c016fd8 100644 --- a/src/views/products/Detail/ProductInfoQuotation.jsx +++ b/src/views/products/Detail/ProductInfoQuotation.jsx @@ -173,6 +173,7 @@ const ProductInfoQuotation = ({ editable, ...props }) => { const onQuotationFinish = (values) => { const newList = saveOrUpdateQuotation(values) + console.info('newList', newList) triggerChange(newList) setQuotationModalOpen(false) } From a95992cb8ed7504403b19ff2e0f5b45d964814d4 Mon Sep 17 00:00:00 2001 From: Lei OT Date: Thu, 24 Jul 2025 14:33:11 +0800 Subject: [PATCH 15/56] =?UTF-8?q?#=20=E5=A4=9A=E8=AF=AD=E7=A7=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Conflicts: # public/locales/en/products.json --- public/locales/en/products.json | 7 ++++++- public/locales/zh/products.json | 2 ++ src/views/products/Audit.jsx | 4 ++-- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/public/locales/en/products.json b/public/locales/en/products.json index 529a790..20507cb 100644 --- a/public/locales/en/products.json +++ b/public/locales/en/products.json @@ -1,5 +1,9 @@ { "ProductType": "Product Type", + "ProductName": "Product Name", + "ContractRemarks": "合同备注", + "versionHistory": "Version History", + "versionPublished": "Published", "type": { "Experience": "Experience", "Car": "Transport Services", @@ -81,7 +85,8 @@ "withQuote": "Whether to copy the quotation", "requiredVendor": "Please pick a target vendor", "requiredTypes": "Please select product types", - "requiredDept": "Please pick a owner department" + "requiredDept": "Please pick a owner department", + "copyTo": "Copy to" }, "Validation": { "adultPrice": "请输入成人价", diff --git a/public/locales/zh/products.json b/public/locales/zh/products.json index dc7ff30..7bfe0e1 100644 --- a/public/locales/zh/products.json +++ b/public/locales/zh/products.json @@ -1,6 +1,8 @@ { "ProductType": "项目类型", "ContractRemarks": "合同备注", + "versionHistory": "查看历史", + "versionPublished": "已发布的", "type": { "Experience": "综费", "Car": "车费", diff --git a/src/views/products/Audit.jsx b/src/views/products/Audit.jsx index 873942c..c317af1 100644 --- a/src/views/products/Audit.jsx +++ b/src/views/products/Audit.jsx @@ -255,7 +255,7 @@ const PriceTable = ({ productType, dataSource, refresh }) => { - getLog({ travel_agency_id, product_id: r.info.id, price_id: r.id })} {...{ travel_agency_id, product_id: r.info.id, price_id: r.id }} /> + getLog({ travel_agency_id, product_id: r.info.id, price_id: r.id })} {...{ travel_agency_id, product_id: r.info.id, price_id: r.id }} /> ) : null, @@ -270,7 +270,7 @@ const PriceTable = ({ productType, dataSource, refresh }) => { getRunning({ travel_agency_id, product_id: r.info.id, price_id: r.id })} {...{ travel_agency_id, product_id: r.info.id, price_id: r.id }} From 7cce92adead83c279ea918d093e476493e0822f2 Mon Sep 17 00:00:00 2001 From: LiaoYijun Date: Thu, 24 Jul 2025 16:16:44 +0800 Subject: [PATCH 16/56] =?UTF-8?q?perf:=20=E4=BB=B7=E6=A0=BC=E5=BF=BD?= =?UTF-8?q?=E7=95=A5=E5=AF=B9=E6=AF=94=EF=BC=9A'WPI=5FSN=20'WPP=5FVEI=5FSN?= =?UTF-8?q?'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit feat: 增加多城市 FormItem --- src/hooks/useProductsSets.js | 2 +- src/stores/Products/Index.js | 5 +++-- src/views/products/Detail/ProductInfoForm.jsx | 16 ++++++++-------- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/hooks/useProductsSets.js b/src/hooks/useProductsSets.js index c291cbf..c063c58 100644 --- a/src/hooks/useProductsSets.js +++ b/src/hooks/useProductsSets.js @@ -100,7 +100,7 @@ export const useProductsAuditStatesMapVal = (value) => { */ export const useProductsTypesFieldsets = (type) => { const [isPermitted] = useAuthStore((state) => [state.isPermitted]); - const infoDefault = [['city'], ['title']]; + const infoDefault = [['city', 'city_list'], ['title']]; const infoAdmin = ['title', 'product_title', 'code', 'remarks', 'dept']; // 'display_to_c' const infoDisplay = isPermitted(PERM_PRODUCTS_MANAGEMENT) ? ['display_to_c', 'sort_order'] : []; const infoRecDisplay = isPermitted(PERM_PRODUCTS_MANAGEMENT) ? ['recommends_rate'] : []; diff --git a/src/stores/Products/Index.js b/src/stores/Products/Index.js index 64ef53c..294e4fe 100644 --- a/src/stores/Products/Index.js +++ b/src/stores/Products/Index.js @@ -329,7 +329,7 @@ export const useProductsStore = create( weekdays: definition.weekend.join(','), WPI_SN: editingProduct.info.id, WPP_VEI_SN: activeAgency.travel_agency_id, - lastedit_changed: '', + lastedit_changed: {}, audit_state_id: -1, key: generateId(), fresh: false @@ -369,7 +369,8 @@ export const useProductsStore = create( if (prevQuotation.key === formValues.key) { const changedObject = {} for (const [key, value] of Object.entries(formValues)) { - if (key === 'use_dates' || key === 'id' || key === 'key' || key === 'weekdayList') continue + if (key === 'use_dates' || key === 'id' || key === 'key' || key === 'weekdayList' + || key === 'WPI_SN' || key === 'WPP_VEI_SN') continue const preValue = prevQuotation[key] const hasChanged = preValue !== value diff --git a/src/views/products/Detail/ProductInfoForm.jsx b/src/views/products/Detail/ProductInfoForm.jsx index 1df2fd8..3c10dba 100644 --- a/src/views/products/Detail/ProductInfoForm.jsx +++ b/src/views/products/Detail/ProductInfoForm.jsx @@ -223,14 +223,6 @@ function getFields(props) { , fieldProps?.city?.col || midCol ), - item( - 'city_list', - 99, - - - , - fieldProps?.city_list?.col || midCol - ), item( 'dept', 99, @@ -248,6 +240,14 @@ function getFields(props) { , fieldProps?.duration?.col || midCol ), + item( + 'city_list', + 99, + + + , + fieldProps?.city_list?.col || midCol + ), item( 'km', 99, From 12208202ad18d64e4fc056eb10188105befb3b17 Mon Sep 17 00:00:00 2001 From: LiaoYijun Date: Thu, 24 Jul 2025 16:17:09 +0800 Subject: [PATCH 17/56] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E5=A4=9A?= =?UTF-8?q?=E5=9F=8E=E5=B8=82=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/MultiCitySelector.jsx | 29 ++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 src/components/MultiCitySelector.jsx diff --git a/src/components/MultiCitySelector.jsx b/src/components/MultiCitySelector.jsx new file mode 100644 index 0000000..3851f87 --- /dev/null +++ b/src/components/MultiCitySelector.jsx @@ -0,0 +1,29 @@ +import { createContext, useEffect, useState } from 'react'; +import {} from 'antd'; +import SearchInput from './SearchInput'; +import { fetchJSON } from '@/utils/request'; +import { HT_HOST } from '@/config'; +import { useTranslation } from 'react-i18next'; + +//供应商列表 +export const fetchCityList = async (q) => { + const { errcode, result } = await fetchJSON(`${HT_HOST}/Service_BaseInfoWeb/search_cities`, { q }); + return errcode !== 0 ? [] : result; +}; + +const MultiCitySelector = ({ ...props }) => { + const { t } = useTranslation(); + return ( + <> + + + ); +}; +export default MultiCitySelector; From 6da10d620084d98d03c476c68b6ecc2066e7ad10 Mon Sep 17 00:00:00 2001 From: LiaoYijun Date: Thu, 24 Jul 2025 16:40:58 +0800 Subject: [PATCH 18/56] =?UTF-8?q?perf:=20=E4=BB=B7=E6=A0=BC=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E4=BF=9D=E5=AD=98=E4=B8=8A=E6=AC=A1=E7=9A=84=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/stores/Products/Index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stores/Products/Index.js b/src/stores/Products/Index.js index 294e4fe..8d3fdab 100644 --- a/src/stores/Products/Index.js +++ b/src/stores/Products/Index.js @@ -376,7 +376,7 @@ export const useProductsStore = create( const hasChanged = preValue !== value if (hasChanged) { - changedObject[key] = value + changedObject[key] = preValue } } From d3aba13a080c6df4e2b03a6e69ac763a419ceea0 Mon Sep 17 00:00:00 2001 From: Lei OT Date: Thu, 24 Jul 2025 16:54:02 +0800 Subject: [PATCH 19/56] =?UTF-8?q?perf:=20=E4=BF=9D=E5=AD=98=E4=BA=A7?= =?UTF-8?q?=E5=93=81:=20=E4=BF=A1=E6=81=AF=E5=8F=98=E6=9B=B4=E5=AD=97?= =?UTF-8?q?=E6=AE=B5+=E5=A4=9A=E8=AF=AD=E7=A7=8D=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/products/Detail/ProductInfo.jsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/views/products/Detail/ProductInfo.jsx b/src/views/products/Detail/ProductInfo.jsx index 43f19ab..ece520a 100644 --- a/src/views/products/Detail/ProductInfo.jsx +++ b/src/views/products/Detail/ProductInfo.jsx @@ -61,7 +61,7 @@ const ProductInfo = ({ ...props }) => { const onValuesChange = (changedValues) => { // console.log('onValuesChange', changedValues); - const changedKeys = objectMapper(changedValues, { 'city': 'city_id', 'dept': 'dept_id', 'product_title': 'title'}); + const changedKeys = objectMapper(changedValues, { 'city': 'city_id', 'dept': 'dept_id', 'product_title': 'title', 'lgc_details_mapped': 'lgc_details'}); setEditKeys(prev => unique([...prev, ...Object.keys(changedKeys)])); // const preValues = pick(editingProduct.info, editKeys); if ('product_title' in changedValues) { @@ -79,7 +79,8 @@ const ProductInfo = ({ ...props }) => { const onSave = async (err, values, forms) => { values.travel_agency_id = activeAgency.travel_agency_id; const editChanged = pick(editingProduct.info, editKeys); - // console.log("editKeys pre values", editKeys, editChanged); + (editKeys.includes('lgc_details') ? editChanged.lgc_details = editingProduct.lgc_details.map(l => l.lgc) : false); + // console.log("editKeys pre values", editKeys, editChanged, '\neditingProduct', ); const copyNewProduct = structuredClone(newProductRecord); const poster = { From d4ab034c1572fd1ffe12fda400c6369283dbd143 Mon Sep 17 00:00:00 2001 From: LiaoYijun Date: Fri, 25 Jul 2025 08:49:30 +0800 Subject: [PATCH 20/56] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E4=BA=A7?= =?UTF-8?q?=E5=93=81=E7=BB=91=E5=AE=9A=E5=A4=9A=E5=9F=8E=E5=B8=82=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/MultiCitySelector.jsx | 29 ------------------- src/views/products/Detail/ProductInfoForm.jsx | 2 +- 2 files changed, 1 insertion(+), 30 deletions(-) delete mode 100644 src/components/MultiCitySelector.jsx diff --git a/src/components/MultiCitySelector.jsx b/src/components/MultiCitySelector.jsx deleted file mode 100644 index 3851f87..0000000 --- a/src/components/MultiCitySelector.jsx +++ /dev/null @@ -1,29 +0,0 @@ -import { createContext, useEffect, useState } from 'react'; -import {} from 'antd'; -import SearchInput from './SearchInput'; -import { fetchJSON } from '@/utils/request'; -import { HT_HOST } from '@/config'; -import { useTranslation } from 'react-i18next'; - -//供应商列表 -export const fetchCityList = async (q) => { - const { errcode, result } = await fetchJSON(`${HT_HOST}/Service_BaseInfoWeb/search_cities`, { q }); - return errcode !== 0 ? [] : result; -}; - -const MultiCitySelector = ({ ...props }) => { - const { t } = useTranslation(); - return ( - <> - - - ); -}; -export default MultiCitySelector; diff --git a/src/views/products/Detail/ProductInfoForm.jsx b/src/views/products/Detail/ProductInfoForm.jsx index 3c10dba..f2c15f3 100644 --- a/src/views/products/Detail/ProductInfoForm.jsx +++ b/src/views/products/Detail/ProductInfoForm.jsx @@ -244,7 +244,7 @@ function getFields(props) { 'city_list', 99, - + , fieldProps?.city_list?.col || midCol ), From 4267014e81e3940b70c0e98de64a421307f4a88a Mon Sep 17 00:00:00 2001 From: LiaoYijun Date: Fri, 25 Jul 2025 10:42:45 +0800 Subject: [PATCH 21/56] =?UTF-8?q?perf:=20map=20=E5=9F=8E=E5=B8=82=20to=20[?= =?UTF-8?q?{id:=201,=20name:=20''}]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/products/Detail/ProductInfoForm.jsx | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/views/products/Detail/ProductInfoForm.jsx b/src/views/products/Detail/ProductInfoForm.jsx index f2c15f3..143762a 100644 --- a/src/views/products/Detail/ProductInfoForm.jsx +++ b/src/views/products/Detail/ProductInfoForm.jsx @@ -413,6 +413,16 @@ const formValuesMapper = (values) => { { key: 'city_id', transform: (value) => value?.value || value?.key || '' }, { key: 'city_name', transform: (value) => value?.label || '' }, ], + 'city_list': [ + { key: 'city_list', transform: (value) => { + return value.map(option => { + return { + id: option?.value || option?.key || '', + name: option?.label || '' + } + }) + }}, + ], 'dept': { key: 'dept_id', transform: (value) => (typeof value === 'string' ? value : value?.value || value?.key || '') }, 'open_weekdays': { key: 'open_weekdays', transform: (value) => (Array.isArray(value) ? value.join(',') : value) }, // 'recommends_rate': { key: 'recommends_rate', transform: (value) => ((typeof value === 'string' || typeof value === 'number') ? value : value?.value || value?.key || '') }, From ef997cb5c05cdabe97fe8b68d7a2e9f45d27cd43 Mon Sep 17 00:00:00 2001 From: Lei OT Date: Fri, 25 Jul 2025 11:19:49 +0800 Subject: [PATCH 22/56] =?UTF-8?q?feat:=20=E4=BA=A7=E5=93=81=E7=AE=A1?= =?UTF-8?q?=E7=90=86:=20=E4=BB=B7=E6=A0=BC=E6=97=A5=E5=BF=97=E7=BB=84?= =?UTF-8?q?=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/products/Audit.jsx | 188 +--------------- .../Detail/ProductQuotationLogPopover.jsx | 211 ++++++++++++++++++ 2 files changed, 221 insertions(+), 178 deletions(-) create mode 100644 src/views/products/Detail/ProductQuotationLogPopover.jsx diff --git a/src/views/products/Audit.jsx b/src/views/products/Audit.jsx index c317af1..d0bc1a4 100644 --- a/src/views/products/Audit.jsx +++ b/src/views/products/Audit.jsx @@ -1,10 +1,10 @@ import { useEffect, useState } from 'react'; import { useParams, Link } from 'react-router-dom'; -import { App, Empty, Button, Collapse, Table, Space, Alert, Tooltip, Popover, Typography } from 'antd'; -import { useProductsTypes, useProductsAuditStatesMapVal, formatGroupSize } from '@/hooks/useProductsSets'; +import { App, Empty, Button, Collapse, Table, Space, Alert } from 'antd'; +import { useProductsTypes, useProductsAuditStatesMapVal } from '@/hooks/useProductsSets'; import SecondHeaderWrapper from '@/components/SecondHeaderWrapper'; import { useTranslation } from 'react-i18next'; -import useProductsStore, { getPPLogAction, getPPRunningAction, postProductsQuoteAuditAction, } from '@/stores/Products/Index'; +import useProductsStore, { postProductsQuoteAuditAction, } from '@/stores/Products/Index'; import { cloneDeep, groupBy, isEmpty, isNotEmpty } from '@/utils/commons'; import useAuthStore from '@/stores/Auth'; import RequireAuth from '@/components/RequireAuth'; @@ -12,165 +12,8 @@ import { PERM_PRODUCTS_MANAGEMENT, PERM_PRODUCTS_OFFER_AUDIT, PERM_PRODUCTS_OFFE import Header from './Detail/Header'; import dayjs from 'dayjs'; import { usingStorage } from '@/hooks/usingStorage'; -import { ClockCircleFilled, ClockCircleOutlined, PlusCircleFilled, PlusCircleOutlined } from '@ant-design/icons'; - -const parseJson = (str) => { - let result; - if (str === null || str === undefined || str === '') { - return {}; - } - try { - result = JSON.parse(str); - return Array.isArray(result) ? result.reduce((acc, cur) => ({ ...acc, ...cur }), {}) : result; - } catch (e) { - return {}; - } -}; - - const columnsSets = (t, colorize = true) => [ - { - key: 'adult', - title: t('AgeType.Adult'), - width: '12rem', - render: (_, { adult_cost, currency, unit_id, unit_name, audit_state_id, lastedit_changed }) => { - const _changed = parseJson(lastedit_changed); - const ifCompare = colorize && ![-1, 1, 2].includes(audit_state_id); - const ifData = isNotEmpty(_changed.adult_cost) || isNotEmpty(_changed.unit_id) || isNotEmpty(_changed.currency); - const preValue = - ifCompare && ifData ? ( -
{`${_changed.adult_cost} ${_changed.currency || currency} / ${t(`PriceUnit.${_changed.unit_id || unit_id}`)}`}
- ) : null; - const editCls = ifCompare && ifData ? 'text-danger' : ''; - return ( -
- {preValue} - {`${adult_cost} ${currency} / ${t(`PriceUnit.${unit_id}`)}`} -
- ); - }, - }, - { - key: 'child', - title: t('AgeType.Child'), - width: '12rem', - render: (_, { child_cost, currency, unit_id, unit_name, audit_state_id, lastedit_changed }) => { - const _changed = parseJson(lastedit_changed); - const ifCompare = colorize && ![-1, 1, 2].includes(audit_state_id); - const ifData = isNotEmpty(_changed.child_cost) || isNotEmpty(_changed.unit_id) || isNotEmpty(_changed.currency); - const preValue = - ifCompare && ifData ? ( -
{`${_changed.child_cost} ${_changed.currency || currency} / ${t(`PriceUnit.${_changed.unit_id || unit_id}`)}`}
- ) : null; - const editCls = ifCompare && ifData ? 'text-danger' : ''; - return ( -
- {preValue} - {`${child_cost} ${currency} / ${t(`PriceUnit.${unit_id}`)}`} -
- ); - }, - }, - // {key: 'unit', title: t('Unit'), }, - { - key: 'groupSize', - dataIndex: ['group_size_min'], - title: t('group_size'), - width: '6rem', - render: (_, { audit_state_id, group_size_min, group_size_max, lastedit_changed }) => { - const _changed = parseJson(lastedit_changed); - const preValue = - colorize && ![-1, 1, 2].includes(audit_state_id) && (isNotEmpty(_changed.group_size_min) || isNotEmpty(_changed.group_size_max)) ? ( -
{`${_changed.group_size_min ?? group_size_min} - ${_changed.group_size_max ?? group_size_max}`}
- ) : null; - const editCls = colorize && ![-1, 1, 2].includes(audit_state_id) && (isNotEmpty(_changed.group_size_min) || isNotEmpty(_changed.group_size_max)) ? 'text-danger' : ''; - return ( -
- {preValue} - {formatGroupSize(group_size_min, group_size_max)} -
- ); - }, - }, - { - key: 'useDates', - dataIndex: ['use_dates_start'], - title: t('use_dates'), - width: '12rem', - render: (_, { use_dates_start, use_dates_end, weekdays, audit_state_id, lastedit_changed }) => { - const _changed = parseJson(lastedit_changed); - const preValue = - colorize && ![-1, 1, 2].includes(audit_state_id) && (isNotEmpty(_changed.use_dates_start) || isNotEmpty(_changed.use_dates_end)) ? ( -
- {isNotEmpty(_changed.use_dates_start) ? {_changed.use_dates_start} : use_dates_start} ~{' '} - {isNotEmpty(_changed.use_dates_end) ? {_changed.use_dates_end} : use_dates_end} -
- ) : null; - const editCls = colorize && ![-1, 1, 2].includes(audit_state_id) && (isNotEmpty(_changed.use_dates_start) || isNotEmpty(_changed.use_dates_end)) ? 'text-danger' : ''; - return ( -
- {preValue} - {`${use_dates_start} ~ ${use_dates_end}`} -
- ); - }, - }, - { - key: 'weekdays', - dataIndex: ['weekdays'], - title: t('Weekdays'), - width: '6rem', - render: (text, { weekdays, audit_state_id, lastedit_changed }) => { - const _changed = parseJson(lastedit_changed); - const ifCompare = colorize && ![-1, 1, 2].includes(audit_state_id); - const ifData = !isEmpty((_changed.weekdayList || []).filter(s => s)); - const preValue = - ifCompare && ifData ? ( -
{_changed.weekdayList}
- ) : null; - const editCls = ifCompare && ifData ? 'text-danger' : ''; - return
{preValue}{text || t('Unlimited')}
; - }, - }, - ]; - -const PriceLogPopover = ({ title, fetchData, triggerProps={}, ...props}) => { - const { t } = useTranslation('products'); - const [open, setOpen] = useState(false); - const [logData, setLogData] = useState([]); - const getData = async () => { - const data = await fetchData(); - setLogData(data); - }; - const columns = [...columnsSets(t, false), { title: '时间', dataIndex: 'updatetime', key: 'updatetime'}]; - return ( - - {title} - - - } - content={ - <> -
- - } - trigger={['click']} - placement='bottom' - className='' - rootClassName='w-5/6' - open={open} - onOpenChange={(v) => { - setOpen(v); - }}> - - - ); -}; +import { ClockCircleOutlined, PlusCircleFilled } from '@ant-design/icons'; +import ProductQuotationLogPopover, { columnsSets } from './Detail/ProductQuotationLogPopover'; const PriceTable = ({ productType, dataSource, refresh }) => { const { t } = useTranslation('products'); @@ -210,16 +53,6 @@ const PriceTable = ({ productType, dataSource, refresh }) => { }); }; - const getLog = async ({ product_id, price_id }) => { - const data = await getPPLogAction({ travel_agency_id, product_id, price_id }); - return data; - }; - - const getRunning = async ({ product_id }) => { - const data = await getPPRunningAction({ travel_agency_id, product_id_list: product_id }); - return data?.[0]?.quotation || []; - }; - const rowStyle = (r, tri) => { const trCls = tri%2 !== 0 ? ' bg-stone-50' : ''; // 奇偶行 const [infoI, quoteI] = r.rowSpanI; @@ -255,7 +88,7 @@ const PriceTable = ({ productType, dataSource, refresh }) => { - getLog({ travel_agency_id, product_id: r.info.id, price_id: r.id })} {...{ travel_agency_id, product_id: r.info.id, price_id: r.id }} /> + ) : null, @@ -267,13 +100,12 @@ const PriceTable = ({ productType, dataSource, refresh }) => { render: (_, r) => { const showPublicBtn = null; // r.pendingQuotation ? : null; const btn2 = r.pendingQuotation ? ( - getRunning({ travel_agency_id, product_id: r.info.id, price_id: r.id })} - {...{ travel_agency_id, product_id: r.info.id, price_id: r.id }} /> ) : null; return
{btn2}
; diff --git a/src/views/products/Detail/ProductQuotationLogPopover.jsx b/src/views/products/Detail/ProductQuotationLogPopover.jsx new file mode 100644 index 0000000..26aed6b --- /dev/null +++ b/src/views/products/Detail/ProductQuotationLogPopover.jsx @@ -0,0 +1,211 @@ +import { useState } from 'react'; +import { Button, Table, Popover, Typography } from 'antd'; +import { useTranslation } from 'react-i18next'; +import { getPPLogAction, getPPRunningAction } from '@/stores/Products/Index'; +import { formatGroupSize } from '@/hooks/useProductsSets'; +import { isEmpty, isNotEmpty } from '@/utils/commons'; + +const parseJson = (str) => { + let result; + if (str === null || str === undefined || str === '') { + return {}; + } + try { + result = JSON.parse(str); + return Array.isArray(result) ? result.reduce((acc, cur) => ({ ...acc, ...cur }), {}) : result; + } catch (e) { + return {}; + } +}; + +export const columnsSets = (t, colorize = true) => [ + { + key: 'adult', + title: t('AgeType.Adult'), + width: '12rem', + render: (_, { adult_cost, currency, unit_id, unit_name, audit_state_id, lastedit_changed }) => { + const _changed = parseJson(lastedit_changed); + const ifCompare = colorize && ![-1, 1, 2].includes(audit_state_id); + const ifData = isNotEmpty(_changed.adult_cost) || isNotEmpty(_changed.unit_id) || isNotEmpty(_changed.currency); + const preValue = + ifCompare && ifData ? ( +
{`${_changed.adult_cost} ${_changed.currency || currency} / ${t(`PriceUnit.${_changed.unit_id || unit_id}`)}`}
+ ) : null; + const editCls = ifCompare && ifData ? 'text-danger' : ''; + return ( +
+ {preValue} + {`${adult_cost} ${currency} / ${t(`PriceUnit.${unit_id}`)}`} +
+ ); + }, + }, + { + key: 'child', + title: t('AgeType.Child'), + width: '12rem', + render: (_, { child_cost, currency, unit_id, unit_name, audit_state_id, lastedit_changed }) => { + const _changed = parseJson(lastedit_changed); + const ifCompare = colorize && ![-1, 1, 2].includes(audit_state_id); + const ifData = isNotEmpty(_changed.child_cost) || isNotEmpty(_changed.unit_id) || isNotEmpty(_changed.currency); + const preValue = + ifCompare && ifData ? ( +
{`${_changed.child_cost} ${_changed.currency || currency} / ${t(`PriceUnit.${_changed.unit_id || unit_id}`)}`}
+ ) : null; + const editCls = ifCompare && ifData ? 'text-danger' : ''; + return ( +
+ {preValue} + {`${child_cost} ${currency} / ${t(`PriceUnit.${unit_id}`)}`} +
+ ); + }, + }, + // {key: 'unit', title: t('Unit'), }, + { + key: 'groupSize', + dataIndex: ['group_size_min'], + title: t('group_size'), + width: '6rem', + render: (_, { audit_state_id, group_size_min, group_size_max, lastedit_changed }) => { + const _changed = parseJson(lastedit_changed); + const preValue = + colorize && ![-1, 1, 2].includes(audit_state_id) && (isNotEmpty(_changed.group_size_min) || isNotEmpty(_changed.group_size_max)) ? ( +
{`${_changed.group_size_min ?? group_size_min} - ${_changed.group_size_max ?? group_size_max}`}
+ ) : null; + const editCls = colorize && ![-1, 1, 2].includes(audit_state_id) && (isNotEmpty(_changed.group_size_min) || isNotEmpty(_changed.group_size_max)) ? 'text-danger' : ''; + return ( +
+ {preValue} + {formatGroupSize(group_size_min, group_size_max)} +
+ ); + }, + }, + { + key: 'useDates', + dataIndex: ['use_dates_start'], + title: t('use_dates'), + width: '12rem', + render: (_, { use_dates_start, use_dates_end, weekdays, audit_state_id, lastedit_changed }) => { + const _changed = parseJson(lastedit_changed); + const preValue = + colorize && ![-1, 1, 2].includes(audit_state_id) && (isNotEmpty(_changed.use_dates_start) || isNotEmpty(_changed.use_dates_end)) ? ( +
+ {isNotEmpty(_changed.use_dates_start) ? {_changed.use_dates_start} : use_dates_start} ~{' '} + {isNotEmpty(_changed.use_dates_end) ? {_changed.use_dates_end} : use_dates_end} +
+ ) : null; + const editCls = colorize && ![-1, 1, 2].includes(audit_state_id) && (isNotEmpty(_changed.use_dates_start) || isNotEmpty(_changed.use_dates_end)) ? 'text-danger' : ''; + return ( +
+ {preValue} + {`${use_dates_start} ~ ${use_dates_end}`} +
+ ); + }, + }, + { + key: 'weekdays', + dataIndex: ['weekdays'], + title: t('Weekdays'), + width: '6rem', + render: (text, { weekdays, audit_state_id, lastedit_changed }) => { + const _changed = parseJson(lastedit_changed); + const ifCompare = colorize && ![-1, 1, 2].includes(audit_state_id); + const ifData = !isEmpty((_changed.weekdayList || []).filter((s) => s)); + const preValue = ifCompare && ifData ?
{_changed.weekdayList}
: null; + const editCls = ifCompare && ifData ? 'text-danger' : ''; + return ( +
+ {preValue} + {text || t('Unlimited')} +
+ ); + }, + }, +]; + +const useLogMethod = (method) => { + const { t } = useTranslation('products'); + const methodMap = { + 'history': { + title: t('versionHistory'), + fetchData: async (params) => { + const data = await getPPLogAction(params); + return data; + }, + }, + 'published': { + title: t('versionPublished'), + fetchData: async (params) => { + const { travel_agency_id, product_id, price_id } = params; + const data = await getPPRunningAction({ travel_agency_id, product_id_list: product_id }); + return data?.[0]?.quotation || []; + }, + }, + }; + return methodMap[method]; +}; + +/** + * ProductQuotationLogPopover - A popover component that displays product quotation change logs or published data + * + * This component shows a history of price changes for a specific product quotation in a popover table. + * It supports displaying different data sources (history logs or published data) and shows + * comparison between previous and current values with visual indicators. + * + * @param {Object} props - Component props + * @param {string} props.btnText - The text to display on the trigger button and in the popover header + * @param {'history' | 'published'} props.method - Determines data source - "history" for change logs or "published" for published quotations + * @param {Object} props.triggerProps - Additional props to pass to the trigger button + * @param {number} props.travel_agency_id - ID of the travel agency (used in data fetching) + * @param {number} props.product_id - ID of the product (used in data fetching) + * @param {number} props.price_id - ID of the price entry (used in data fetching) + */ +const ProductQuotationLogPopover = ({ method, triggerProps = {}, ...props }) => { + const { travel_agency_id, product_id, price_id } = props; + + const { t } = useTranslation('products'); + const [open, setOpen] = useState(false); + const [logData, setLogData] = useState([]); + + const { title, fetchData } = useLogMethod(method); + + const getData = async () => { + const data = await fetchData({ travel_agency_id, product_id, price_id }); + setLogData(data); + }; + + const columns = [...columnsSets(t, false), { title: '时间', dataIndex: 'updatetime', key: 'updatetime' }]; + return ( + + {title} + + + } + content={ + <> +
+ + } + trigger={['click']} + placement='bottom' + className='' + rootClassName='w-5/6' + open={open} + onOpenChange={(v) => { + setOpen(v); + }}> + + + ); +}; +export default ProductQuotationLogPopover; From c49682bb8472a6a665416c06be5970fac09f7b8d Mon Sep 17 00:00:00 2001 From: Lei OT Date: Mon, 28 Jul 2025 09:32:38 +0800 Subject: [PATCH 23/56] =?UTF-8?q?perf:=20=E4=BF=9D=E5=AD=98=E4=BA=A7?= =?UTF-8?q?=E5=93=81:=20=E8=BF=94=E5=9B=9E=E6=96=B0=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/products/Detail/ProductInfoForm.jsx | 32 ++++++++++++------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/src/views/products/Detail/ProductInfoForm.jsx b/src/views/products/Detail/ProductInfoForm.jsx index 143762a..d1d460c 100644 --- a/src/views/products/Detail/ProductInfoForm.jsx +++ b/src/views/products/Detail/ProductInfoForm.jsx @@ -36,12 +36,8 @@ const InfoForm = ({ onSubmit, onReset, onValuesChange, editablePerm, infoEditabl const [showSave, setShowSave] = useState(true); useEffect(() => { form.resetFields(); - form.setFieldValue('city', editingProduct?.info?.city_id ? { value: editingProduct?.info?.city_id, label: editingProduct?.info?.city_name } : undefined); - form.setFieldValue('dept', { value: editingProduct?.info?.dept_id, label: editingProduct?.info?.dept_name }); - const lgc_details_mapped = (editingProduct?.lgc_details || []).reduce((r, c) => ({ ...r, [c.lgc]: c }), {}); - form.setFieldValue('lgc_details_mapped', lgc_details_mapped); - form.setFieldValue('quotation', editingProduct?.quotation); - form.setFieldValue('display_to_c', editingProduct.info?.display_to_c || '0'); + + form.setFieldsValue(serverData2Form(editingProduct)); setPickEditedInfo({ ...pickEditedInfo, product_title: editingProduct?.info?.product_title }); setFormEditable(infoEditable || priceEditable); @@ -54,7 +50,7 @@ const InfoForm = ({ onSubmit, onReset, onValuesChange, editablePerm, infoEditabl const onFinish = (values) => { console.log('Received values of form, origin form value: \n', values); - const dest = formValuesMapper(values); + const dest = formValuesMapper2Server(values); console.log('form value send to onSubmit:\n', dest); if (typeof onSubmit === 'function') { onSubmit(null, dest, values); @@ -80,7 +76,7 @@ const InfoForm = ({ onSubmit, onReset, onValuesChange, editablePerm, infoEditabl } }; const onIValuesChange = (changedValues, allValues) => { - const dest = formValuesMapper(allValues); + const dest = formValuesMapper2Server(allValues); // console.log('form onValuesChange', Object.keys(changedValues), changedValues); if ('product_title' in changedValues) { const editTitle = (changedValues.product_title); @@ -339,7 +335,7 @@ function getFields(props) { 'sort_order', 99, - + , fieldProps?.sort_order?.col || midCol ), @@ -407,7 +403,20 @@ function getFields(props) { return children; } -const formValuesMapper = (values) => { +const serverData2Form = (productItem) => { + const infoForRender = { + city: productItem?.info?.city_id ? { value: productItem?.info?.city_id, label: productItem?.info?.city_name } : undefined, + dept: { value: productItem?.info?.dept_id, label: productItem?.info?.dept_name }, + display_to_c: productItem.info?.display_to_c || '0', + city_list: productItem?.info?.city_list ? productItem?.info?.city_list?.map((ele) => ({ value: ele.id, label: ele.name })) : undefined, + sub_type_D: productItem?.info?.item_type || '', + }; + const lgc_details_mapped = (productItem?.lgc_details || []).reduce((r, c) => ({ ...r, [c.lgc]: c }), {}); + const quotation = productItem?.quotation || []; + return { ...productItem, ...(productItem?.info || {}), ...infoForRender, lgc_details_mapped }; +}; + +const formValuesMapper2Server = (values) => { const destinationObject = { 'city': [ { key: 'city_id', transform: (value) => value?.value || value?.key || '' }, @@ -464,13 +473,14 @@ const formValuesMapper = (values) => { ], 'product_title': { key: 'title' }, 'sub_type_D': { key: 'item_type'}, + 'sort_order': { key: 'sort_order'}, }; let dest = {}; const { city, dept, product_title, sub_type_D, ...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]; + dest[key] = typeof dest[key] === 'string' ? (dest[key] || '').trim() : (dest[key] ?? ''); } } // omit empty From 27b6063a1eda89640a3975ce648e974c0b6f3697 Mon Sep 17 00:00:00 2001 From: Lei OT Date: Mon, 28 Jul 2025 10:50:22 +0800 Subject: [PATCH 24/56] =?UTF-8?q?feat:=20=E4=BA=A7=E5=93=81=E6=A0=91:=20?= =?UTF-8?q?=E6=98=BE=E7=A4=BA=E5=A4=9A=E5=9F=8E=E5=B8=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/products/Detail/ProductsTree.jsx | 51 ++++++++++++---------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/src/views/products/Detail/ProductsTree.jsx b/src/views/products/Detail/ProductsTree.jsx index 4378482..a289837 100644 --- a/src/views/products/Detail/ProductsTree.jsx +++ b/src/views/products/Detail/ProductsTree.jsx @@ -53,6 +53,7 @@ const ProductsTree = ({ onNodeSelect, ...props }) => { const [rawTreeData, setRawTreeData] = useState([]); const [flattenTreeData, setFlattenTreeData] = useState([]); const [expandedKeys, setExpandedKeys] = useState([]); + const [selectedKeys, setSelectedKeys] = useState([]); const [autoExpandParent, setAutoExpandParent] = useState(true); useEffect(() => { @@ -74,28 +75,30 @@ const ProductsTree = ({ onNodeSelect, ...props }) => { const _show = productsTypes .filter((kk) => hasDataTypes.includes(kk.value)) .map((ele) => ({ - ...ele, - title: ele.label, - key: ele.value, - children: (agencyProducts[ele.value] || []).map((product) => { - const lgc_map = product.lgc_details.reduce((rlgc, clgc) => ({...rlgc, [clgc.lgc]: clgc}), {}); - return { - // title: product.info.title || lgc_map?.['2']?.title || lgc_map?.['1']?.title || '', - title: `【${product.info.city_name}】` + (product.info.title || lgc_map?.['2']?.title || lgc_map?.['1']?.title || product.info.product_title || ''), - // key: `${ele.value}-${product.info.id}`, - key: product.info.id, - _raw: product, - isLeaf: true, - }}), - // 增加`城市`层级 - // _children: Object.keys(copyAgencyProducts[ele.value] || []).map(city => { - // return { - // title: city, - // key: `${ele.value}-${city}`, - // children: copyAgencyProducts[ele.value][city], - // }; - // }), - })); + ...ele, + title: ele.label, + key: ele.value, + children: (agencyProducts[ele.value] || []).reduce((arr, product) => { + const lgc_map = product.lgc_details.reduce((rlgc, clgc) => ({ ...rlgc, [clgc.lgc]: clgc }), {}); + const combindCityList = product.info.city_list.indexOf(city => city.id === product.info.city_id) !== -1 ? product.info.city_list : [...product.info.city_list, { id: product.info.city_id, name: product.info.city_name }]; + const flatCityP = combindCityList.map(city => ({ + title: `【${city.name}】` + (product.info.title || lgc_map?.['2']?.title || lgc_map?.['1']?.title || product.info.product_title || ''), + // key: `${ele.value}-${product.info.id}`, + key: `${product.info.id}-${city.id}`, + _raw: product, + isLeaf: true, + })); + return arr.concat(flatCityP); + }, []), + // 增加`城市`层级 + // _children: Object.keys(copyAgencyProducts[ele.value] || []).map(city => { + // return { + // title: city, + // key: `${ele.value}-${city}`, + // children: copyAgencyProducts[ele.value][city], + // }; + // }), + })); setTreeData(_show); setRawTreeData(_show); setFlattenTreeData(flattenTreeFun(_show)); @@ -130,6 +133,8 @@ const ProductsTree = ({ onNodeSelect, ...props }) => { const handleNodeSelect = (selectedKeys, { node }) => { if (node._raw) { setEditingProduct(node._raw); + const allKeysWithCity = [...node._raw.info.city_list, { id: node._raw.info.city_id, name: node._raw.info.city_name }].map((city) => `${node._raw.info.id}-${city.id}`); + setSelectedKeys(allKeysWithCity); } else { // 单击: 折叠/展开 // const isExpand = expandedKeys.includes(selectedKeys[0]); @@ -174,7 +179,7 @@ const ProductsTree = ({ onNodeSelect, ...props }) => { } onSelect={handleNodeSelect} treeData={treeData} From e6832cfd7f1c448791b1bd01ad388b2ea2005677 Mon Sep 17 00:00:00 2001 From: LiaoYijun Date: Mon, 28 Jul 2025 15:03:04 +0800 Subject: [PATCH 25/56] =?UTF-8?q?feat:=20=E5=9C=B0=E6=8E=A5=E9=80=89?= =?UTF-8?q?=E6=8B=A9=E9=87=87=E8=B4=AD=E5=B9=B4=E4=BB=BD=E9=A1=B5=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main.jsx | 3 +++ src/views/products/PickYear.jsx | 40 +++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 src/views/products/PickYear.jsx diff --git a/src/main.jsx b/src/main.jsx index 7a3310c..51170af 100644 --- a/src/main.jsx +++ b/src/main.jsx @@ -45,6 +45,8 @@ import { isNotEmpty } from '@/utils/commons' import ProductsManage from '@/views/products/Manage'; import ProductsDetail from '@/views/products/Detail'; import ProductsAudit from '@/views/products/Audit'; +import PickYear from './views/products/PickYear' + import { PERM_ACCOUNT_MANAGEMENT, PERM_ROLE_NEW, PERM_OVERSEA,PERM_TRAIN_TICKET, PERM_AIR_TICKET, PERM_PRODUCTS_MANAGEMENT, PERM_PRODUCTS_OFFER_PUT } from '@/config' import './i18n' @@ -94,6 +96,7 @@ const initRouter = async () => { { path: "products/:travel_agency_id/:use_year/:audit_state/edit",element:}, { path: "products/audit",element:}, { path: "products/edit",element:}, + { path: "products/pick-year",element: }, // ] }, diff --git a/src/views/products/PickYear.jsx b/src/views/products/PickYear.jsx new file mode 100644 index 0000000..6329175 --- /dev/null +++ b/src/views/products/PickYear.jsx @@ -0,0 +1,40 @@ +import { useNavigate } from "react-router-dom"; +import { Row, DatePicker, Flex, Col, Typography } from "antd"; +import dayjs from "dayjs"; +import { usingStorage } from "@/hooks/usingStorage"; + +function PickYear() { + const navigate = useNavigate(); + const { travelAgencyId } = usingStorage(); + + return ( + <> + + + + + 请选择采购年份 + + { + const useYear = date.year(); + navigate(`/products/${travelAgencyId}/${useYear}/all/edit`); + }} + /> + + + + + ); +} +export default PickYear; From 1f3f4cd853ad7c2d6a705827d72fe55838961ec3 Mon Sep 17 00:00:00 2001 From: Lei OT Date: Mon, 28 Jul 2025 10:50:22 +0800 Subject: [PATCH 26/56] =?UTF-8?q?feat:=20=E4=BA=A7=E5=93=81=E6=A0=91:=20?= =?UTF-8?q?=E6=98=BE=E7=A4=BA=E5=A4=9A=E5=9F=8E=E5=B8=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Detail/ProductQuotationLogPopover.jsx | 6 +- src/views/products/Detail/ProductsTree.jsx | 61 ++++++++++++------- 2 files changed, 41 insertions(+), 26 deletions(-) diff --git a/src/views/products/Detail/ProductQuotationLogPopover.jsx b/src/views/products/Detail/ProductQuotationLogPopover.jsx index 26aed6b..9bc011e 100644 --- a/src/views/products/Detail/ProductQuotationLogPopover.jsx +++ b/src/views/products/Detail/ProductQuotationLogPopover.jsx @@ -180,6 +180,9 @@ const ProductQuotationLogPopover = ({ method, triggerProps = {}, ...props }) => const columns = [...columnsSets(t, false), { title: '时间', dataIndex: 'updatetime', key: 'updatetime' }]; return ( @@ -195,9 +198,6 @@ const ProductQuotationLogPopover = ({ method, triggerProps = {}, ...props }) => } trigger={['click']} - placement='bottom' - className='' - rootClassName='w-5/6' open={open} onOpenChange={(v) => { setOpen(v); diff --git a/src/views/products/Detail/ProductsTree.jsx b/src/views/products/Detail/ProductsTree.jsx index 4378482..bcb12b3 100644 --- a/src/views/products/Detail/ProductsTree.jsx +++ b/src/views/products/Detail/ProductsTree.jsx @@ -53,6 +53,7 @@ const ProductsTree = ({ onNodeSelect, ...props }) => { const [rawTreeData, setRawTreeData] = useState([]); const [flattenTreeData, setFlattenTreeData] = useState([]); const [expandedKeys, setExpandedKeys] = useState([]); + const [selectedKeys, setSelectedKeys] = useState([]); const [autoExpandParent, setAutoExpandParent] = useState(true); useEffect(() => { @@ -74,28 +75,30 @@ const ProductsTree = ({ onNodeSelect, ...props }) => { const _show = productsTypes .filter((kk) => hasDataTypes.includes(kk.value)) .map((ele) => ({ - ...ele, - title: ele.label, - key: ele.value, - children: (agencyProducts[ele.value] || []).map((product) => { - const lgc_map = product.lgc_details.reduce((rlgc, clgc) => ({...rlgc, [clgc.lgc]: clgc}), {}); - return { - // title: product.info.title || lgc_map?.['2']?.title || lgc_map?.['1']?.title || '', - title: `【${product.info.city_name}】` + (product.info.title || lgc_map?.['2']?.title || lgc_map?.['1']?.title || product.info.product_title || ''), - // key: `${ele.value}-${product.info.id}`, - key: product.info.id, - _raw: product, - isLeaf: true, - }}), - // 增加`城市`层级 - // _children: Object.keys(copyAgencyProducts[ele.value] || []).map(city => { - // return { - // title: city, - // key: `${ele.value}-${city}`, - // children: copyAgencyProducts[ele.value][city], - // }; - // }), - })); + ...ele, + title: ele.label, + key: ele.value, + children: (agencyProducts[ele.value] || []).reduce((arr, product) => { + const lgc_map = product.lgc_details.reduce((rlgc, clgc) => ({ ...rlgc, [clgc.lgc]: clgc }), {}); + const combindCityList = product.info.city_list.indexOf(city => city.id === product.info.city_id) !== -1 ? product.info.city_list : [...product.info.city_list, { id: product.info.city_id, name: product.info.city_name }]; + const flatCityP = combindCityList.map(city => ({ + title: `【${city.name}】` + (product.info.title || lgc_map?.['2']?.title || lgc_map?.['1']?.title || product.info.product_title || ''), + // key: `${ele.value}-${product.info.id}`, + key: `${product.info.id}-${city.id}`, + _raw: product, + isLeaf: true, + })); + return arr.concat(flatCityP); + }, []), + // 增加`城市`层级 + // _children: Object.keys(copyAgencyProducts[ele.value] || []).map(city => { + // return { + // title: city, + // key: `${ele.value}-${city}`, + // children: copyAgencyProducts[ele.value][city], + // }; + // }), + })); setTreeData(_show); setRawTreeData(_show); setFlattenTreeData(flattenTreeFun(_show)); @@ -106,6 +109,16 @@ const ProductsTree = ({ onNodeSelect, ...props }) => { return () => {}; }, [productsTypes, agencyProducts]); + useEffect(() => { + const allKeysWithCity = [...editingProduct.info.city_list, { id: editingProduct.info.city_id, name: editingProduct.info.city_name }].map( + (city) => `${editingProduct.info.id}-${city.id}` + ); + setSelectedKeys(allKeysWithCity); + + return () => {}; + }, [editingProduct?.info?.id]); + + const [searchValue, setSearchValue] = useState(''); const onSearch = ({ target: { value } }) => { // const { value } = e.target; @@ -130,6 +143,8 @@ const ProductsTree = ({ onNodeSelect, ...props }) => { const handleNodeSelect = (selectedKeys, { node }) => { if (node._raw) { setEditingProduct(node._raw); + const allKeysWithCity = [...node._raw.info.city_list, { id: node._raw.info.city_id, name: node._raw.info.city_name }].map((city) => `${node._raw.info.id}-${city.id}`); + setSelectedKeys(allKeysWithCity); } else { // 单击: 折叠/展开 // const isExpand = expandedKeys.includes(selectedKeys[0]); @@ -174,7 +189,7 @@ const ProductsTree = ({ onNodeSelect, ...props }) => { } onSelect={handleNodeSelect} treeData={treeData} From 12e472923eac46dbf45eb106d18c38fb6e058d63 Mon Sep 17 00:00:00 2001 From: Lei OT Date: Mon, 28 Jul 2025 15:18:25 +0800 Subject: [PATCH 27/56] =?UTF-8?q?feat:=20=E4=BA=A7=E5=93=81=E6=A0=91:=20?= =?UTF-8?q?=E6=98=BE=E7=A4=BA=E5=A4=9A=E5=9F=8E=E5=B8=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/products/Detail/ProductsTree.jsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/views/products/Detail/ProductsTree.jsx b/src/views/products/Detail/ProductsTree.jsx index bcb12b3..fbd44fc 100644 --- a/src/views/products/Detail/ProductsTree.jsx +++ b/src/views/products/Detail/ProductsTree.jsx @@ -110,6 +110,9 @@ const ProductsTree = ({ onNodeSelect, ...props }) => { }, [productsTypes, agencyProducts]); useEffect(() => { + if (isEmpty(editingProduct)) { + return () => {}; + } const allKeysWithCity = [...editingProduct.info.city_list, { id: editingProduct.info.city_id, name: editingProduct.info.city_name }].map( (city) => `${editingProduct.info.id}-${city.id}` ); From f0eb6ca887bf11c1ccf0417b55cd01acc35d315a Mon Sep 17 00:00:00 2001 From: Lei OT Date: Mon, 28 Jul 2025 15:50:21 +0800 Subject: [PATCH 28/56] style: --- src/views/products/Audit.jsx | 2 +- src/views/products/Detail/ProductInfoForm.jsx | 20 +++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/views/products/Audit.jsx b/src/views/products/Audit.jsx index d0bc1a4..357ce1b 100644 --- a/src/views/products/Audit.jsx +++ b/src/views/products/Audit.jsx @@ -85,7 +85,7 @@ const PriceTable = ({ productType, dataSource, refresh }) => { render: (_, r, ri) => (Number(r.audit_state_id)) === 0 ? ( - + diff --git a/src/views/products/Detail/ProductInfoForm.jsx b/src/views/products/Detail/ProductInfoForm.jsx index d1d460c..13ac195 100644 --- a/src/views/products/Detail/ProductInfoForm.jsx +++ b/src/views/products/Detail/ProductInfoForm.jsx @@ -257,7 +257,7 @@ function getFields(props) { 99, {/* */} - + {/*
+
} trigger={['click']} open={open} onOpenChange={(v) => { setOpen(v); + invokeOpenChange(v); }}> : null; - const btn2 = r.pendingQuotation ? ( + const btn2 = r.showPublicBtn ? ( { lgc_details: c.lgc_details.reduce((rlgc, clgc) => ({...rlgc, [clgc.lgc]: clgc}), {}), rowSpan: i === 0 ? c.quotation.length : 0, rowSpanI: [ri, i], - pendingQuotation: c.quotation.findIndex(q2 => q2.audit_state_id===0) !== -1 , + showPublicBtn: c.quotation.some(q2 => [0, 3].includes(q2.audit_state_id)), })) ), [] diff --git a/src/views/products/Detail/ProductQuotationLogPopover.jsx b/src/views/products/Detail/ProductQuotationLogPopover.jsx index 8e24801..c1ed6be 100644 --- a/src/views/products/Detail/ProductQuotationLogPopover.jsx +++ b/src/views/products/Detail/ProductQuotationLogPopover.jsx @@ -147,14 +147,16 @@ const useLogMethod = (method) => { const { t } = useTranslation('products'); const methodMap = { 'history': { - title: t('versionHistory'), + title: '📑' + t('versionHistory'), + btnText: t('versionHistory'), fetchData: async (params) => { const data = await getPPLogAction(params); return data; }, }, 'published': { - title: t('versionPublished'), + title: '✅' + t('versionPublished'), + btnText: t('versionPublished'), fetchData: async (params) => { const { travel_agency_id, product_id, price_id, use_year } = params; const data = await getPPRunningAction({ travel_agency_id, product_id_list: product_id, use_year }); @@ -189,13 +191,17 @@ const ProductQuotationLogPopover = ({ method, triggerProps = {}, onOpenChange, . const [open, setOpen] = useState(false); const [logData, setLogData] = useState([]); - const { title, fetchData } = useLogMethod(method); + const { title, btnText: methodBtnText, fetchData } = useLogMethod(method); const tablePagination = useMemo(() => method === 'history' ? { pageSize: 5, position: ['bottomLeft']} : { pageSize: 10, position: ['bottomLeft']}, [method]); + + const [loading, setLoading] = useState(false); const getData = async () => { + setLoading(true); const data = await fetchData({ travel_agency_id, product_id, price_id, use_year }); setLogData(data); invokeOpenChange(true); + setLoading(false); }; const invokeOpenChange = (_open) => { @@ -226,7 +232,7 @@ const ProductQuotationLogPopover = ({ method, triggerProps = {}, onOpenChange, . } content={ <> -
+
} trigger={['click']} @@ -236,7 +242,7 @@ const ProductQuotationLogPopover = ({ method, triggerProps = {}, onOpenChange, . invokeOpenChange(v); }}> ); From 7b7d5faa0d1dc20a83fbdcfa58819ff2edf592bd Mon Sep 17 00:00:00 2001 From: Lei OT Date: Tue, 29 Jul 2025 16:32:06 +0800 Subject: [PATCH 35/56] =?UTF-8?q?feat:=20=E4=BA=A7=E5=93=81=E5=AE=A1?= =?UTF-8?q?=E6=A0=B8:=20=E6=8B=92=E7=BB=9D=E7=9A=84=E4=BB=B7=E6=A0=BC:=20?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2=20=E4=BB=B7=E6=A0=BC=E5=8E=86=E5=8F=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/products/Audit.jsx | 58 ++++++++++++++++++++++++++++-------- 1 file changed, 45 insertions(+), 13 deletions(-) diff --git a/src/views/products/Audit.jsx b/src/views/products/Audit.jsx index 15988f2..cb8a113 100644 --- a/src/views/products/Audit.jsx +++ b/src/views/products/Audit.jsx @@ -68,11 +68,33 @@ const PriceTable = ({ productType, dataSource, refresh }) => { }; const columns = [ - { key: 'title', dataIndex: ['info', 'title'], width: '16rem', title: t('Title'), onCell: (r, index) => ({ rowSpan: r.rowSpan, }), className: 'bg-white', render: (text, r) => { - const title = text || r.lgc_details?.['2']?.title || r.lgc_details?.['1']?.title || ''; - const itemLink = isPermitted(PERM_PRODUCTS_OFFER_AUDIT) ? `/products/${travel_agency_id}/${use_year}/${audit_state}/edit` : isPermitted(PERM_PRODUCTS_OFFER_PUT) ? `/products/edit` : ''; - return
{isNotEmpty(itemLink) ?
setEditingProduct({info: r.info})}>{title}
: title}
; - } }, + { + key: 'title', + dataIndex: ['info', 'title'], + width: '16rem', + title: t('Title'), + onCell: (r, index) => ({ rowSpan: r.rowSpan }), + className: 'bg-white', + render: (text, r) => { + const title = text || r.lgc_details?.['2']?.title || r.lgc_details?.['1']?.title || ''; + const itemLink = isPermitted(PERM_PRODUCTS_OFFER_AUDIT) + ? `/products/${travel_agency_id}/${use_year}/${audit_state}/edit` + : isPermitted(PERM_PRODUCTS_OFFER_PUT) + ? `/products/edit` + : ''; + return ( +
+ {isNotEmpty(itemLink) ? ( +
setEditingProduct({ info: r.info })}> + {title} +
+ ) : ( + title + )} +
+ ); + }, + }, ...columnsSets(t), { key: 'state', @@ -86,20 +108,30 @@ const PriceTable = ({ productType, dataSource, refresh }) => { title: '', key: 'action', render: (_, r, ri) => - (Number(r.audit_state_id)) === 0 ? ( + [0, 3].includes(Number(r.audit_state_id)) ? ( - - - - setLogOpenPriceRow(open ? r.id : null)} /> + + {Number(r.audit_state_id) === 0 && ( + <> + + + + )} + setLogOpenPriceRow(open ? r.id : null)} + /> ) : null, }, { title: '', - key: 'action2', width: '6rem', className: 'bg-white', - onCell: (r, index) => ({ rowSpan: r.rowSpan, }), + key: 'action2', + width: '6rem', + className: 'bg-white', + onCell: (r, index) => ({ rowSpan: r.rowSpan }), render: (_, r) => { const showPublicBtn = null; // r.pendingQuotation ? : null; const btn2 = r.showPublicBtn ? ( @@ -113,7 +145,7 @@ const PriceTable = ({ productType, dataSource, refresh }) => { ) : null; return
{btn2}
; }, - } + }, ]; return (
Date: Tue, 29 Jul 2025 17:01:14 +0800 Subject: [PATCH 36/56] =?UTF-8?q?fix=EF=BC=9A=E4=B8=8A=E4=BC=A0=E6=97=A5?= =?UTF-8?q?=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/LogUploader.jsx | 27 +++++++++++++-------------- src/pageSpy/index.jsx | 2 +- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/components/LogUploader.jsx b/src/components/LogUploader.jsx index b32ad4f..09c096b 100644 --- a/src/components/LogUploader.jsx +++ b/src/components/LogUploader.jsx @@ -1,7 +1,5 @@ import { useState } from "react"; import { Popover, message, FloatButton, Button, Form, Input } from "antd"; -import "antd/dist/reset.css"; -import "dayjs/locale/zh-cn"; import { BugOutlined } from "@ant-design/icons"; import useAuthStore from "@/stores/Auth"; import { uploadPageSpyLog, sendNotify } from "@/pageSpy"; @@ -58,18 +56,19 @@ function LogUploader() { ); return ( - <>{contextHolder} - - } /> - + <> + {contextHolder} + + } /> + ); } diff --git a/src/pageSpy/index.jsx b/src/pageSpy/index.jsx index a31a301..0bf2433 100644 --- a/src/pageSpy/index.jsx +++ b/src/pageSpy/index.jsx @@ -57,7 +57,7 @@ export const loadPageSpy = (title) => { export const uploadPageSpyLog = async () => { - if (import.meta.env.DEV || window.$pageSpy) return true; + if (import.meta.env.DEV) return true; if (window.$pageSpy) { try { From ab8f133192cf88083f5387c941ec9817bbf5425a Mon Sep 17 00:00:00 2001 From: LiaoYijun Date: Wed, 30 Jul 2025 10:57:02 +0800 Subject: [PATCH 37/56] =?UTF-8?q?perf:=20=E7=B2=BE=E7=AE=80=E6=8F=90?= =?UTF-8?q?=E7=A4=BA=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/LogUploader.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/LogUploader.jsx b/src/components/LogUploader.jsx index 09c096b..b9a40e0 100644 --- a/src/components/LogUploader.jsx +++ b/src/components/LogUploader.jsx @@ -39,7 +39,7 @@ function LogUploader() { From 134bd3ce799e77395eb0a329b6ba70d07208c434 Mon Sep 17 00:00:00 2001 From: LiaoYijun Date: Wed, 30 Jul 2025 16:38:31 +0800 Subject: [PATCH 38/56] =?UTF-8?q?feat=EF=BC=9A=E6=96=B0=E5=A2=9E=E4=BB=B7?= =?UTF-8?q?=E6=A0=BC=E4=BD=BF=E7=94=A8=E5=9C=B0=E6=8E=A5=E5=BD=93=E5=89=8D?= =?UTF-8?q?=E5=B9=B4=E4=BB=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/stores/Products/Index.js | 7 ++----- .../products/Detail/ProductInfoQuotation.jsx | 21 +++++++++++-------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/stores/Products/Index.js b/src/stores/Products/Index.js index cfbffdd..7f173c6 100644 --- a/src/stores/Products/Index.js +++ b/src/stores/Products/Index.js @@ -275,7 +275,7 @@ export const useProductsStore = create( } }, - newEmptyQuotation: () => ({ + newEmptyQuotation: (useDates) => ({ id: null, adult_cost: 0, child_cost: 0, @@ -283,10 +283,7 @@ export const useProductsStore = create( unit_id: '0', group_size_min: 1, group_size_max: 10, - use_dates: [ - dayjs().startOf('M'), - dayjs().endOf('M') - ], + use_dates: useDates, weekdayList: [], fresh: true // 标识是否是新记录,新记录才用添加列表 }), diff --git a/src/views/products/Detail/ProductInfoQuotation.jsx b/src/views/products/Detail/ProductInfoQuotation.jsx index b76936c..5fe6a89 100644 --- a/src/views/products/Detail/ProductInfoQuotation.jsx +++ b/src/views/products/Detail/ProductInfoQuotation.jsx @@ -133,12 +133,21 @@ const defaultDefinitionValue = { 'priceList': [defaultPriceValue] } +const getYearRange = (year) => [dayjs().year(year).startOf('y'), dayjs().year(year).endOf('y')] + const ProductInfoQuotation = ({ editable, ...props }) => { const { onChange } = props const { t } = useTranslation() + const [quotationList, newEmptyQuotation, appendQuotationList, saveOrUpdateQuotation, deleteQuotation, switchParams] = + useProductsStore((state) => [ + state.quotationList, state.newEmptyQuotation, state.appendQuotationList, state.saveOrUpdateQuotation, state.deleteQuotation, + state.switchParams + ]) + + const [defaultUseDates, setDefaultUseDates] = useState(getYearRange(switchParams.use_year)) const [isQuotationModalOpen, setQuotationModalOpen] = useState(false) const [isBatchSetupModalOpen, setBatchSetupModalOpen] = useState(false) const [groupSizeUnlimit, setGroupSizeUnlimit] = useState(false) @@ -149,16 +158,11 @@ const ProductInfoQuotation = ({ editable, ...props }) => { const datePresets = useDatePresets() - const [quotationList, newEmptyQuotation, appendQuotationList, saveOrUpdateQuotation, deleteQuotation, switchParams] = - useProductsStore((state) => [ - state.quotationList, state.newEmptyQuotation, state.appendQuotationList, state.saveOrUpdateQuotation, state.deleteQuotation, - state.switchParams - ]) - useEffect(() => { - console.info('switchParams: ', switchParams) + setDefaultUseDates(getYearRange(switchParams.use_year)) }, [switchParams]) + const triggerChange = (changedValue) => { onChange?.( changedValue @@ -174,14 +178,13 @@ const ProductInfoQuotation = ({ editable, ...props }) => { } const onNewQuotation = () => { - const emptyQuotation = newEmptyQuotation() + const emptyQuotation = newEmptyQuotation(defaultUseDates) quotationForm.setFieldsValue(emptyQuotation) setQuotationModalOpen(true) } const onQuotationFinish = (values) => { const newList = saveOrUpdateQuotation(values) - console.info('newList', newList) triggerChange(newList) setQuotationModalOpen(false) } From 9fc8057b03a1c6bd7a920d2f046065d563746408 Mon Sep 17 00:00:00 2001 From: LiaoYijun Date: Thu, 31 Jul 2025 09:43:10 +0800 Subject: [PATCH 39/56] =?UTF-8?q?feat:=20=E6=89=B9=E9=87=8F=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE=E4=BB=B7=E6=A0=BC=E6=A0=B9=E6=8D=AE=E9=80=89=E6=8B=A9?= =?UTF-8?q?=E5=B9=B4=E4=BB=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../products/Detail/ProductInfoQuotation.jsx | 218 +++++++++--------- 1 file changed, 104 insertions(+), 114 deletions(-) diff --git a/src/views/products/Detail/ProductInfoQuotation.jsx b/src/views/products/Detail/ProductInfoQuotation.jsx index 5fe6a89..ceb0054 100644 --- a/src/views/products/Detail/ProductInfoQuotation.jsx +++ b/src/views/products/Detail/ProductInfoQuotation.jsx @@ -11,107 +11,6 @@ import { formatGroupSize } from '@/hooks/useProductsSets' const { RangePicker } = DatePicker -const batchSetupInitialValues = { - 'defList': [ - // 旺季 - { - 'useDateList': [ - { - 'useDate': [ - dayjs().add(1, 'year').startOf('y'), dayjs().add(1, 'year').endOf('y') - ] - } - ], - 'unitId': '0', - 'currency': 'RMB', - 'weekend': [ - ], - 'priceList': [ - { - '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 - } - } - ] - }, - // 淡季 - { - 'useDateList': [ - { - 'useDate': [ - dayjs().add(1, 'year').subtract(2, 'M').startOf('M'), dayjs().add(1, 'year').endOf('M') - ] - } - ], - 'unitId': '0', - 'currency': 'RMB', - 'weekend': [ - ], - 'priceList': [ - { - '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 - } - } - ] - } - ] -} - const defaultPriceValue = { 'priceInput': { 'numberStart': 1, @@ -121,20 +20,16 @@ const defaultPriceValue = { } } -const defaultUseDate = { - 'useDate': [dayjs().add(1, 'year').startOf('y'), dayjs().add(1, 'year').endOf('y')] -} - -const defaultDefinitionValue = { - 'useDateList': [defaultUseDate], - 'unitId': '0', - 'currency': 'RMB', - 'weekend': [], - 'priceList': [defaultPriceValue] -} - const getYearRange = (year) => [dayjs().year(year).startOf('y'), dayjs().year(year).endOf('y')] +const generateDefinitionValue = (year) => ({ + 'useDateList': [{'useDate': getYearRange(year)}], + 'unitId': '0', + 'currency': 'RMB', + 'weekend': [], + 'priceList': [defaultPriceValue] + }) + const ProductInfoQuotation = ({ editable, ...props }) => { const { onChange } = props @@ -147,7 +42,101 @@ const ProductInfoQuotation = ({ editable, ...props }) => { state.switchParams ]) + const batchSetupInitialValues = { + 'defList': [ + // 旺季 + { + 'useDateList': [{'useDate': getYearRange(switchParams.use_year)}], + 'unitId': '0', + 'currency': 'RMB', + 'weekend': [], + 'priceList': [ + { + '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 + } + } + ] + }, + // 淡季 + { + 'useDateList': [ + { + 'useDate': [ + dayjs().year(switchParams.use_year).subtract(2, 'M').startOf('M'), dayjs().year(switchParams.use_year).endOf('M') + ] + } + ], + 'unitId': '0', + 'currency': 'RMB', + 'weekend': [], + 'priceList': [ + { + '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 + } + } + ] + } + ] + } + const [defaultUseDates, setDefaultUseDates] = useState(getYearRange(switchParams.use_year)) + const [defaultDefinitionValue, setDefaultDefinitionValue] = useState(generateDefinitionValue(switchParams.use_year)) const [isQuotationModalOpen, setQuotationModalOpen] = useState(false) const [isBatchSetupModalOpen, setBatchSetupModalOpen] = useState(false) const [groupSizeUnlimit, setGroupSizeUnlimit] = useState(false) @@ -160,6 +149,7 @@ const ProductInfoQuotation = ({ editable, ...props }) => { useEffect(() => { setDefaultUseDates(getYearRange(switchParams.use_year)) + setDefaultDefinitionValue(generateDefinitionValue(switchParams.use_year)) }, [switchParams]) @@ -340,7 +330,7 @@ const ProductInfoQuotation = ({ editable, ...props }) => { {index == 0 ? : useDateOptList.remove(useDateField.name)} />} ))} - From f94e46bcc1d1bff53f739e9a6449f5f6d4d53825 Mon Sep 17 00:00:00 2001 From: Lei OT Date: Thu, 31 Jul 2025 11:07:41 +0800 Subject: [PATCH 40/56] =?UTF-8?q?perf:=20=E4=BA=A7=E5=93=81=E5=AE=A1?= =?UTF-8?q?=E6=A0=B8:=20=E4=BB=B7=E6=A0=BC=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/locales/en/common.json | 4 +++- public/locales/zh/common.json | 4 +++- src/views/products/Detail/ProductQuotationLogPopover.jsx | 7 +++++-- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/public/locales/en/common.json b/public/locales/en/common.json index 5fc92b0..4e8321a 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -36,6 +36,8 @@ "Table": { "Total": "Total {{total}} items" }, + "operator": "Operator", + "time": "Time", "Login": "Login", "Username": "Username", "Realname": "Realname", @@ -105,4 +107,4 @@ "Finance_Dept_arrproved": "Finance Dept arrproved", "Paid": "Paid" } -} \ No newline at end of file +} diff --git a/public/locales/zh/common.json b/public/locales/zh/common.json index d749ecd..0a57df9 100644 --- a/public/locales/zh/common.json +++ b/public/locales/zh/common.json @@ -36,6 +36,8 @@ "Table": { "Total": "共 {{total}} 条" }, + "operator": "操作", + "time": "时间", "Login": "登录", "Username": "账号", "Realname": "姓名", @@ -105,4 +107,4 @@ "Finance_Dept_arrproved": "财务已审核", "Paid": "已打款" } -} \ No newline at end of file +} diff --git a/src/views/products/Detail/ProductQuotationLogPopover.jsx b/src/views/products/Detail/ProductQuotationLogPopover.jsx index c1ed6be..e1f59fb 100644 --- a/src/views/products/Detail/ProductQuotationLogPopover.jsx +++ b/src/views/products/Detail/ProductQuotationLogPopover.jsx @@ -28,7 +28,7 @@ const parseJson = (str) => { return {}; } try { - result = JSON.parse(str); + result = typeof str === 'string' ? JSON.parse(str) : str; return Array.isArray(result) ? result.reduce((acc, cur) => ({ ...acc, ...cur }), {}) : result; } catch (e) { return {}; @@ -210,7 +210,10 @@ const ProductQuotationLogPopover = ({ method, triggerProps = {}, onOpenChange, . } }; - const columns = [...columnsSets(t, false), { title: '时间', dataIndex: 'updatetime', key: 'updatetime' }]; + const columns = [...columnsSets(t, false), + { title: t('common:time'), dataIndex: 'updatetime', key: 'updatetime', width: '10rem', }, + { title: t('common:operator'), dataIndex: 'update_by', key: 'update_by' } + ]; return ( Date: Thu, 31 Jul 2025 12:05:38 +0800 Subject: [PATCH 41/56] =?UTF-8?q?=E2=9B=94=20=E4=BA=A7=E5=93=81=E5=AE=A1?= =?UTF-8?q?=E6=A0=B8:=20=E5=B7=B2=E5=8F=91=E5=B8=83=E7=9A=84=E4=BB=B7?= =?UTF-8?q?=E6=A0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/products/Audit.jsx | 40 +++++++++---------- .../Detail/ProductQuotationLogPopover.jsx | 6 +-- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/views/products/Audit.jsx b/src/views/products/Audit.jsx index cb8a113..a55db7e 100644 --- a/src/views/products/Audit.jsx +++ b/src/views/products/Audit.jsx @@ -126,26 +126,26 @@ const PriceTable = ({ productType, dataSource, refresh }) => { ) : null, }, - { - title: '', - key: 'action2', - width: '6rem', - className: 'bg-white', - onCell: (r, index) => ({ rowSpan: r.rowSpan }), - render: (_, r) => { - const showPublicBtn = null; // r.pendingQuotation ? : null; - const btn2 = r.showPublicBtn ? ( - - ) : null; - return
{btn2}
; - }, - }, + // { + // title: '', + // key: 'action2', + // width: '6rem', + // className: 'bg-white', + // onCell: (r, index) => ({ rowSpan: r.rowSpan }), + // render: (_, r) => { + // const showPublicBtn = null; // r.pendingQuotation ? : null; + // const btn2 = r.showPublicBtn ? ( + // + // ) : null; + // return
{btn2}
; + // }, + // }, ]; return (
{ btnText: t('versionHistory'), fetchData: async (params) => { const data = await getPPLogAction(params); - return data; + return { data }; }, }, 'published': { @@ -160,7 +160,7 @@ const useLogMethod = (method) => { fetchData: async (params) => { const { travel_agency_id, product_id, price_id, use_year } = params; const data = await getPPRunningAction({ travel_agency_id, product_id_list: product_id, use_year }); - return data?.[0]?.quotation || []; + return { data: data?.[0]?.quotation || [] }; }, }, }; @@ -198,7 +198,7 @@ const ProductQuotationLogPopover = ({ method, triggerProps = {}, onOpenChange, . const [loading, setLoading] = useState(false); const getData = async () => { setLoading(true); - const data = await fetchData({ travel_agency_id, product_id, price_id, use_year }); + const { data } = await fetchData({ travel_agency_id, product_id, price_id, use_year }); setLogData(data); invokeOpenChange(true); setLoading(false); From dedc3ee7f0f8b9839bb7a0bb57ad2dbc14e27250 Mon Sep 17 00:00:00 2001 From: Lei OT Date: Thu, 31 Jul 2025 12:06:10 +0800 Subject: [PATCH 42/56] =?UTF-8?q?perf:=20=E4=BA=A7=E5=93=81=E7=AE=A1?= =?UTF-8?q?=E7=90=86:=20=E5=A4=9A=E5=9F=8E=E5=B8=82=20=E5=8F=AA=E6=98=BE?= =?UTF-8?q?=E7=A4=BA=E4=B8=BB=E5=9F=8E=E5=B8=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/products/Detail/ProductsTree.jsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/views/products/Detail/ProductsTree.jsx b/src/views/products/Detail/ProductsTree.jsx index fbd44fc..1ddc24d 100644 --- a/src/views/products/Detail/ProductsTree.jsx +++ b/src/views/products/Detail/ProductsTree.jsx @@ -80,9 +80,14 @@ const ProductsTree = ({ onNodeSelect, ...props }) => { key: ele.value, children: (agencyProducts[ele.value] || []).reduce((arr, product) => { const lgc_map = product.lgc_details.reduce((rlgc, clgc) => ({ ...rlgc, [clgc.lgc]: clgc }), {}); - const combindCityList = product.info.city_list.indexOf(city => city.id === product.info.city_id) !== -1 ? product.info.city_list : [...product.info.city_list, { id: product.info.city_id, name: product.info.city_name }]; + // const combindCityList = product.info.city_list.indexOf(city => city.id === product.info.city_id) !== -1 ? product.info.city_list : [...product.info.city_list, { id: product.info.city_id, name: product.info.city_name }]; + // const cityListName = product.info.city_list.reduce((acc, city) => { + // return acc.concat([city.name]); + // }, []).join(','); + const hasCityList = !isEmpty(product.info.city_list) && product.info.city_list.some(cc => cc.id !== product.info.city_id) ? ` (含多城市)` : ``; + const combindCityList = [{ id: product.info.city_id, name: product.info.city_name }]; const flatCityP = combindCityList.map(city => ({ - title: `【${city.name}】` + (product.info.title || lgc_map?.['2']?.title || lgc_map?.['1']?.title || product.info.product_title || ''), + title: `【${city.name}${hasCityList}】` + (product.info.title || lgc_map?.['2']?.title || lgc_map?.['1']?.title || product.info.product_title || ''), // key: `${ele.value}-${product.info.id}`, key: `${product.info.id}-${city.id}`, _raw: product, From a113d48e5154c7d9676ff9bbd71b874bd3d03b62 Mon Sep 17 00:00:00 2001 From: Lei OT Date: Mon, 4 Aug 2025 16:42:20 +0800 Subject: [PATCH 43/56] =?UTF-8?q?perf:=20=E4=BA=A7=E5=93=81=E5=AE=A1?= =?UTF-8?q?=E6=A0=B8:=20=E6=96=B0=E5=A2=9E/=E4=BF=AE=E6=94=B9=E4=B8=AD,=20?= =?UTF-8?q?=E4=B9=9F=E6=98=BE=E7=A4=BA=E5=8E=86=E5=8F=B2=E5=92=8C=E4=B8=8A?= =?UTF-8?q?=E6=AC=A1=E7=BC=96=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/products/Audit.jsx | 2 +- .../Detail/ProductQuotationLogPopover.jsx | 15 ++++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/views/products/Audit.jsx b/src/views/products/Audit.jsx index a55db7e..3df9410 100644 --- a/src/views/products/Audit.jsx +++ b/src/views/products/Audit.jsx @@ -108,7 +108,7 @@ const PriceTable = ({ productType, dataSource, refresh }) => { title: '', key: 'action', render: (_, r, ri) => - [0, 3].includes(Number(r.audit_state_id)) ? ( + [-1, 0, 3].includes(Number(r.audit_state_id)) ? ( {Number(r.audit_state_id) === 0 && ( diff --git a/src/views/products/Detail/ProductQuotationLogPopover.jsx b/src/views/products/Detail/ProductQuotationLogPopover.jsx index 155ea8c..36d5573 100644 --- a/src/views/products/Detail/ProductQuotationLogPopover.jsx +++ b/src/views/products/Detail/ProductQuotationLogPopover.jsx @@ -35,6 +35,7 @@ const parseJson = (str) => { } }; +const statesForHideEdited = [1, 2]; export const columnsSets = (t, colorize = true) => [ { key: 'adult', @@ -42,7 +43,7 @@ export const columnsSets = (t, colorize = true) => [ width: '12rem', render: (_, { adult_cost, currency, unit_id, unit_name, audit_state_id, lastedit_changed }) => { const _changed = parseJson(lastedit_changed); - const ifCompare = colorize && ![-1, 1, 2].includes(audit_state_id); + const ifCompare = colorize && !statesForHideEdited.includes(audit_state_id); const ifData = isNotEmpty(_changed.adult_cost) || isNotEmpty(_changed.unit_id) || isNotEmpty(_changed.currency); const preValue = ifCompare && ifData ? ( @@ -63,7 +64,7 @@ export const columnsSets = (t, colorize = true) => [ width: '12rem', render: (_, { child_cost, currency, unit_id, unit_name, audit_state_id, lastedit_changed }) => { const _changed = parseJson(lastedit_changed); - const ifCompare = colorize && ![-1, 1, 2].includes(audit_state_id); + const ifCompare = colorize && !statesForHideEdited.includes(audit_state_id); const ifData = isNotEmpty(_changed.child_cost) || isNotEmpty(_changed.unit_id) || isNotEmpty(_changed.currency); const preValue = ifCompare && ifData ? ( @@ -87,10 +88,10 @@ export const columnsSets = (t, colorize = true) => [ render: (_, { audit_state_id, group_size_min, group_size_max, lastedit_changed }) => { const _changed = parseJson(lastedit_changed); const preValue = - colorize && ![-1, 1, 2].includes(audit_state_id) && (isNotEmpty(_changed.group_size_min) || isNotEmpty(_changed.group_size_max)) ? ( + colorize && !statesForHideEdited.includes(audit_state_id) && (isNotEmpty(_changed.group_size_min) || isNotEmpty(_changed.group_size_max)) ? (
{`${_changed.group_size_min ?? group_size_min} - ${_changed.group_size_max ?? group_size_max}`}
) : null; - const editCls = colorize && ![-1, 1, 2].includes(audit_state_id) && (isNotEmpty(_changed.group_size_min) || isNotEmpty(_changed.group_size_max)) ? 'text-danger' : ''; + const editCls = colorize && !statesForHideEdited.includes(audit_state_id) && (isNotEmpty(_changed.group_size_min) || isNotEmpty(_changed.group_size_max)) ? 'text-danger' : ''; return (
{preValue} @@ -107,13 +108,13 @@ export const columnsSets = (t, colorize = true) => [ render: (_, { use_dates_start, use_dates_end, weekdays, audit_state_id, lastedit_changed }) => { const _changed = parseJson(lastedit_changed); const preValue = - colorize && ![-1, 1, 2].includes(audit_state_id) && (isNotEmpty(_changed.use_dates_start) || isNotEmpty(_changed.use_dates_end)) ? ( + colorize && !statesForHideEdited.includes(audit_state_id) && (isNotEmpty(_changed.use_dates_start) || isNotEmpty(_changed.use_dates_end)) ? (
{isNotEmpty(_changed.use_dates_start) ? {_changed.use_dates_start} : use_dates_start} ~{' '} {isNotEmpty(_changed.use_dates_end) ? {_changed.use_dates_end} : use_dates_end}
) : null; - const editCls = colorize && ![-1, 1, 2].includes(audit_state_id) && (isNotEmpty(_changed.use_dates_start) || isNotEmpty(_changed.use_dates_end)) ? 'text-danger' : ''; + const editCls = colorize && !statesForHideEdited.includes(audit_state_id) && (isNotEmpty(_changed.use_dates_start) || isNotEmpty(_changed.use_dates_end)) ? 'text-danger' : ''; return (
{preValue} @@ -129,7 +130,7 @@ export const columnsSets = (t, colorize = true) => [ width: '6rem', render: (text, { weekdays, audit_state_id, lastedit_changed }) => { const _changed = parseJson(lastedit_changed); - const ifCompare = colorize && ![-1, 1, 2].includes(audit_state_id); + const ifCompare = colorize && !statesForHideEdited.includes(audit_state_id); const ifData = !isEmpty((_changed.weekdayList || []).filter((s) => s)); const preValue = ifCompare && ifData ?
{_changed.weekdayList}
: null; const editCls = ifCompare && ifData ? 'text-danger' : ''; From 646744abbf59e3e5bddb1c671701f4f7814e5a61 Mon Sep 17 00:00:00 2001 From: LiaoYijun Date: Tue, 5 Aug 2025 14:46:42 +0800 Subject: [PATCH 44/56] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E6=9D=83=E9=99=90=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- src/stores/Auth.js | 16 ++++++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index b9e0626..a4bbcad 100644 --- a/package.json +++ b/package.json @@ -22,8 +22,8 @@ "i18next-http-backend": "^2.5.2", "react": "^18.3.1", "react-dom": "^18.3.1", - "react-router-dom": "^6.30.1", "react-i18next": "^14.1.2", + "react-router-dom": "^6.30.1", "react-to-pdf": "^1.0.1", "xlsx": "https://cdn.sheetjs.com/xlsx-0.18.11/xlsx-0.18.11.tgz", "zustand": "^4.5.7" diff --git a/src/stores/Auth.js b/src/stores/Auth.js index 8828884..dcd9e65 100644 --- a/src/stores/Auth.js +++ b/src/stores/Auth.js @@ -37,12 +37,6 @@ export const fetchPermissionListByUserId = async (userId) => { return errcode !== 0 ? {} : result } -// 取消令牌时间过期检测,待删除 -async function fetchLastRequet() { - const { errcode, result } = await fetchJSON(`${HT_HOST}/service-CooperateSOA/GetLastReqDate`) - return errcode !== 0 ? {} : result -} - const initialState = { tokenInterval: null, loginStatus: 0, @@ -175,6 +169,16 @@ const useAuthStore = create(devtools((set, get) => ({ }) }, + // 根据某项数据来判断是否有权限 + // + // INSERT INTO [dbo].[auth_resource] ([res_name] ,[res_pattern], [res_category]) + // VALUES ('审核CH直销产品', '[125, 375]', 'data') + // + // const PERM_PRODUCTS_AUDIT_CH = '[125, 375]' + isAllowed: (perm, data) => { + return true + }, + }), { name: 'authStore' })) export default useAuthStore From 80215b3e33a7b884ec1637096629e4dd3bce491c Mon Sep 17 00:00:00 2001 From: LiaoYijun Date: Wed, 6 Aug 2025 13:43:11 +0800 Subject: [PATCH 45/56] =?UTF-8?q?perf:=20=E5=88=A0=E9=99=A4=E5=AE=9A?= =?UTF-8?q?=E6=97=B6=E8=AF=B7=E6=B1=82=E4=BB=A4=E7=89=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/stores/Auth.js | 4 +--- src/views/products/PickYear.jsx | 9 ++++++++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/stores/Auth.js b/src/stores/Auth.js index dcd9e65..34768fe 100644 --- a/src/stores/Auth.js +++ b/src/stores/Auth.js @@ -38,7 +38,6 @@ export const fetchPermissionListByUserId = async (userId) => { } const initialState = { - tokenInterval: null, loginStatus: 0, defaltRoute: '', currentUser: { @@ -119,10 +118,9 @@ const useAuthStore = create(devtools((set, get) => ({ }, logout: () => { - const { tokenInterval, currentUser } = get() + const { currentUser } = get() const { clearStorage } = usingStorage() clearStorage() - clearInterval(tokenInterval) set(() => ({ ...initialState, currentUser: { diff --git a/src/views/products/PickYear.jsx b/src/views/products/PickYear.jsx index 6329175..ccef783 100644 --- a/src/views/products/PickYear.jsx +++ b/src/views/products/PickYear.jsx @@ -13,7 +13,7 @@ function PickYear() {
- 请选择采购年份 + 请选择产品年份 { const useYear = date.year(); From 0d7d3be8b9ddb315492892508dd46b141efd5b74 Mon Sep 17 00:00:00 2001 From: Lei OT Date: Wed, 6 Aug 2025 16:05:12 +0800 Subject: [PATCH 46/56] =?UTF-8?q?fix:=20=E4=BA=A7=E5=93=81=E5=AE=A1?= =?UTF-8?q?=E6=A0=B8:=20=E7=BC=96=E8=BE=91=E5=8F=98=E6=9B=B4,=20undefined?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/products/Detail/ProductQuotationLogPopover.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/views/products/Detail/ProductQuotationLogPopover.jsx b/src/views/products/Detail/ProductQuotationLogPopover.jsx index 36d5573..9623655 100644 --- a/src/views/products/Detail/ProductQuotationLogPopover.jsx +++ b/src/views/products/Detail/ProductQuotationLogPopover.jsx @@ -47,7 +47,7 @@ export const columnsSets = (t, colorize = true) => [ const ifData = isNotEmpty(_changed.adult_cost) || isNotEmpty(_changed.unit_id) || isNotEmpty(_changed.currency); const preValue = ifCompare && ifData ? ( -
{`${_changed.adult_cost} ${_changed.currency || currency} / ${t(`PriceUnit.${_changed.unit_id || unit_id}`)}`}
+
{`${_changed.adult_cost || adult_cost} ${_changed.currency || currency} / ${t(`PriceUnit.${_changed.unit_id || unit_id}`)}`}
) : null; const editCls = ifCompare && ifData ? 'text-danger' : ''; return ( @@ -68,7 +68,7 @@ export const columnsSets = (t, colorize = true) => [ const ifData = isNotEmpty(_changed.child_cost) || isNotEmpty(_changed.unit_id) || isNotEmpty(_changed.currency); const preValue = ifCompare && ifData ? ( -
{`${_changed.child_cost} ${_changed.currency || currency} / ${t(`PriceUnit.${_changed.unit_id || unit_id}`)}`}
+
{`${_changed.child_cost || child_cost} ${_changed.currency || currency} / ${t(`PriceUnit.${_changed.unit_id || unit_id}`)}`}
) : null; const editCls = ifCompare && ifData ? 'text-danger' : ''; return ( From aea6b4ee5565c1f17f2e3d141f0d2145530667fd Mon Sep 17 00:00:00 2001 From: Lei OT Date: Wed, 6 Aug 2025 16:43:58 +0800 Subject: [PATCH 47/56] =?UTF-8?q?perf:=20=E4=BA=A7=E5=93=81=E5=AE=A1?= =?UTF-8?q?=E6=A0=B8:=20=E7=BC=96=E8=BE=91=E5=8F=98=E6=9B=B4,=20=E5=91=A8?= =?UTF-8?q?=E6=9C=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../products/Detail/ProductQuotationLogPopover.jsx | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/views/products/Detail/ProductQuotationLogPopover.jsx b/src/views/products/Detail/ProductQuotationLogPopover.jsx index 9623655..d5f58cc 100644 --- a/src/views/products/Detail/ProductQuotationLogPopover.jsx +++ b/src/views/products/Detail/ProductQuotationLogPopover.jsx @@ -131,8 +131,15 @@ export const columnsSets = (t, colorize = true) => [ render: (text, { weekdays, audit_state_id, lastedit_changed }) => { const _changed = parseJson(lastedit_changed); const ifCompare = colorize && !statesForHideEdited.includes(audit_state_id); - const ifData = !isEmpty((_changed.weekdayList || []).filter((s) => s)); - const preValue = ifCompare && ifData ?
{_changed.weekdayList}
: null; + const ifData = !isEmpty(_changed.weekdays); + const _weekdays = ifData + ? _changed.weekdays + .split(',') + .filter(Boolean) + .map((w) => t(`common:weekdaysShort.${w}`)) + .join(', ') + : ''; + const preValue = ifCompare && ifData ?
{_weekdays}
: null; const editCls = ifCompare && ifData ? 'text-danger' : ''; return (
From a8fb0bbdeda71e59fc11945efb8d8ab4ac7fa9c8 Mon Sep 17 00:00:00 2001 From: Lei OT Date: Wed, 6 Aug 2025 16:54:27 +0800 Subject: [PATCH 48/56] =?UTF-8?q?perf:=20=E4=BA=A7=E5=93=81=E5=AE=A1?= =?UTF-8?q?=E6=A0=B8:=20=E4=BB=B7=E6=A0=BC=E5=8E=86=E5=8F=B2:=20=E5=9C=B0?= =?UTF-8?q?=E6=8E=A5=E6=9F=A5=E7=9C=8B=20=E6=9D=83=E9=99=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/products/Audit.jsx | 28 ++++++++++--------- .../Detail/ProductQuotationLogPopover.jsx | 7 ++++- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/views/products/Audit.jsx b/src/views/products/Audit.jsx index 3df9410..d93de56 100644 --- a/src/views/products/Audit.jsx +++ b/src/views/products/Audit.jsx @@ -109,21 +109,23 @@ const PriceTable = ({ productType, dataSource, refresh }) => { key: 'action', render: (_, r, ri) => [-1, 0, 3].includes(Number(r.audit_state_id)) ? ( - + <> - {Number(r.audit_state_id) === 0 && ( - <> - - - - )} + + {Number(r.audit_state_id) === 0 && ( +
+ + +
+ )} +
setLogOpenPriceRow(open ? r.id : null)} />
-
+ ) : null, }, // { @@ -183,11 +185,11 @@ const TypesPanels = (props) => { r.concat( c.quotation.map((q, i) => ({ ...q, - weekdays: q.weekdays - .split(',') - .filter(Boolean) - .map((w) => t(`weekdaysShort.${w}`)) - .join(', '), + // weekdays: q.weekdays + // .split(',') + // .filter(Boolean) + // .map((w) => t(`weekdaysShort.${w}`)) + // .join(', '), info: c.info, lgc_details: c.lgc_details.reduce((rlgc, clgc) => ({...rlgc, [clgc.lgc]: clgc}), {}), rowSpan: i === 0 ? c.quotation.length : 0, diff --git a/src/views/products/Detail/ProductQuotationLogPopover.jsx b/src/views/products/Detail/ProductQuotationLogPopover.jsx index d5f58cc..9991f93 100644 --- a/src/views/products/Detail/ProductQuotationLogPopover.jsx +++ b/src/views/products/Detail/ProductQuotationLogPopover.jsx @@ -141,10 +141,15 @@ export const columnsSets = (t, colorize = true) => [ : ''; const preValue = ifCompare && ifData ?
{_weekdays}
: null; const editCls = ifCompare && ifData ? 'text-danger' : ''; + const weekdaysTxt = weekdays + .split(',') + .filter(Boolean) + .map((w) => t(`common:weekdaysShort.${w}`)) + .join(', '); return (
{preValue} - {text || t('Unlimited')} + {weekdaysTxt || t('Unlimited')}
); }, From a68824ca803cb3b065c8b841229770c7c597fdce Mon Sep 17 00:00:00 2001 From: LiaoYijun Date: Wed, 6 Aug 2025 16:58:32 +0800 Subject: [PATCH 49/56] =?UTF-8?q?perf:=20=E4=BF=AE=E6=94=B9=E6=97=BA?= =?UTF-8?q?=E5=AD=A3=E3=80=81=E6=B7=A1=E5=AD=A3=EF=BC=9B=E5=8A=A0=E7=B2=97?= =?UTF-8?q?=E4=B8=8D=E5=88=86=E4=BA=BA=E7=AD=89=E3=80=81=E4=B8=8D=E9=99=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/products/Detail/ProductInfoQuotation.jsx | 10 +++++----- src/views/products/PickYear.jsx | 6 ++---- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/views/products/Detail/ProductInfoQuotation.jsx b/src/views/products/Detail/ProductInfoQuotation.jsx index ceb0054..cd9688f 100644 --- a/src/views/products/Detail/ProductInfoQuotation.jsx +++ b/src/views/products/Detail/ProductInfoQuotation.jsx @@ -44,7 +44,7 @@ const ProductInfoQuotation = ({ editable, ...props }) => { const batchSetupInitialValues = { 'defList': [ - // 旺季 + // 全年 { 'useDateList': [{'useDate': getYearRange(switchParams.use_year)}], 'unitId': '0', @@ -85,7 +85,7 @@ const ProductInfoQuotation = ({ editable, ...props }) => { } ] }, - // 淡季 + // 特殊时间段 { 'useDateList': [ { @@ -293,7 +293,7 @@ const ProductInfoQuotation = ({ editable, ...props }) => { {fields.map((field, index) => ( : { remove(field.name) @@ -461,7 +461,7 @@ const ProductInfoQuotation = ({ editable, ...props }) => { if (!groupMaxUnlimit) quotationForm.setFieldValue('group_size_max', 999) setGroupSizeUnlimit(false) } - }}>不分人等(0~1000) + }}>不分人等(0~1000) { quotationForm.setFieldValue('group_size_max', 999) setGroupMaxUnlimit(false) } - }}>不限(1000) + }}>不限(1000) Date: Thu, 7 Aug 2025 09:35:09 +0800 Subject: [PATCH 50/56] =?UTF-8?q?perf:=20=E4=BA=A7=E5=93=81=E7=AE=A1?= =?UTF-8?q?=E7=90=86:=20=E5=A4=9A=E5=9F=8E=E5=B8=82=20=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/products/Detail/ProductsTree.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/views/products/Detail/ProductsTree.jsx b/src/views/products/Detail/ProductsTree.jsx index 1ddc24d..f44d662 100644 --- a/src/views/products/Detail/ProductsTree.jsx +++ b/src/views/products/Detail/ProductsTree.jsx @@ -84,10 +84,10 @@ const ProductsTree = ({ onNodeSelect, ...props }) => { // const cityListName = product.info.city_list.reduce((acc, city) => { // return acc.concat([city.name]); // }, []).join(','); - const hasCityList = !isEmpty(product.info.city_list) && product.info.city_list.some(cc => cc.id !== product.info.city_id) ? ` (含多城市)` : ``; + const hasCityList = !isEmpty(product.info.city_list) && product.info.city_list.some(cc => cc.id !== product.info.city_id) ? `【含多城市】` : ``; const combindCityList = [{ id: product.info.city_id, name: product.info.city_name }]; const flatCityP = combindCityList.map(city => ({ - title: `【${city.name}${hasCityList}】` + (product.info.title || lgc_map?.['2']?.title || lgc_map?.['1']?.title || product.info.product_title || ''), + title: `【${city.name}】` + (product.info.title || lgc_map?.['2']?.title || lgc_map?.['1']?.title || product.info.product_title || '') + `${hasCityList}`, // key: `${ele.value}-${product.info.id}`, key: `${product.info.id}-${city.id}`, _raw: product, From 478086957ac402967bef4be26a30b3503e60c165 Mon Sep 17 00:00:00 2001 From: Lei OT Date: Thu, 7 Aug 2025 10:59:16 +0800 Subject: [PATCH 51/56] =?UTF-8?q?perf:=20=E4=BA=A7=E5=93=81=E7=AE=A1?= =?UTF-8?q?=E7=90=86:=20`=E6=8E=92=E5=BA=8F`=E4=BB=85=E5=9C=A8`=E5=8C=85?= =?UTF-8?q?=E4=BB=B7`,`=E8=BD=A6=E8=B4=B9`,`=E5=AF=BC=E6=B8=B8`=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E4=B8=8B=E5=A2=9E=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/useProductsSets.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/hooks/useProductsSets.js b/src/hooks/useProductsSets.js index 9caf42c..d960e91 100644 --- a/src/hooks/useProductsSets.js +++ b/src/hooks/useProductsSets.js @@ -102,15 +102,16 @@ export const useProductsTypesFieldsets = (type) => { const [isPermitted] = useAuthStore((state) => [state.isPermitted]); const infoDefault = [['city', 'city_list'], ['title']]; const infoAdmin = ['title', 'product_title', 'code', 'remarks', 'dept']; // 'display_to_c' - const infoDisplay = isPermitted(PERM_PRODUCTS_MANAGEMENT) ? ['display_to_c', 'sort_order'] : []; + const infoDisplay = isPermitted(PERM_PRODUCTS_MANAGEMENT) ? ['display_to_c'] : []; const infoRecDisplay = isPermitted(PERM_PRODUCTS_MANAGEMENT) ? ['recommends_rate'] : []; const subTypeD = isPermitted(PERM_PRODUCTS_MANAGEMENT) ? ['sub_type_D'] : []; + const sortOrder = isPermitted(PERM_PRODUCTS_MANAGEMENT) ? ['sort_order'] : []; const infoTypesMap = { '6': [[...infoDisplay], []], 'B': [['km', ...infoDisplay], []], - 'J': [[...infoRecDisplay, 'duration', ...infoDisplay], ['description']], - 'Q': [[...infoRecDisplay, 'duration', ...infoDisplay], ['description']], - 'D': [[...infoRecDisplay, 'duration', ...infoDisplay, ...subTypeD], ['description']], + 'J': [[...infoRecDisplay, 'duration', ...infoDisplay, ...sortOrder], ['description']], + 'Q': [[...infoRecDisplay, 'duration', ...infoDisplay, ...sortOrder], ['description']], + 'D': [[...infoRecDisplay, 'duration', ...infoDisplay, ...subTypeD, ...sortOrder], ['description']], '7': [[...infoRecDisplay, 'duration', 'open_weekdays', ...infoDisplay], ['description']], 'R': [[...infoDisplay], ['description']], '8': [[...infoDisplay], []], From 174315116c608d4ec28bd2b73f52b5cb9fdb5022 Mon Sep 17 00:00:00 2001 From: Lei OT Date: Thu, 7 Aug 2025 10:59:45 +0800 Subject: [PATCH 52/56] style: --- src/views/products/Detail/ProductInfoForm.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/products/Detail/ProductInfoForm.jsx b/src/views/products/Detail/ProductInfoForm.jsx index 13ac195..1b73208 100644 --- a/src/views/products/Detail/ProductInfoForm.jsx +++ b/src/views/products/Detail/ProductInfoForm.jsx @@ -272,7 +272,7 @@ function getFields(props) { ]} /> */} , - fieldProps?.recommends_rate?.col || midCol/2 + fieldProps?.recommends_rate?.col || (props.shows.includes('sort_order') ? midCol/2 : midCol) ), item( 'sort_order', From 0e71967422fad32412f28b61e68e45b69e57e026 Mon Sep 17 00:00:00 2001 From: Lei OT Date: Thu, 7 Aug 2025 11:03:49 +0800 Subject: [PATCH 53/56] =?UTF-8?q?perf:=20=E4=BA=A7=E5=93=81=E7=AE=A1?= =?UTF-8?q?=E7=90=86:=20=E7=BC=96=E8=BE=91=E9=A1=B5=E9=9D=A2:=20=E4=B8=8D?= =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96`=E5=AE=A1=E6=A0=B8=E7=8A=B6?= =?UTF-8?q?=E6=80=81`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/products/Detail/Header.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/products/Detail/Header.jsx b/src/views/products/Detail/Header.jsx index 799ada5..5d0cce9 100644 --- a/src/views/products/Detail/Header.jsx +++ b/src/views/products/Detail/Header.jsx @@ -264,7 +264,7 @@ const Header = ({ refresh, ...props }) => { className="px-2" to={ isPermitted(PERM_PRODUCTS_OFFER_AUDIT) - ? `/products/${activeAgency.travel_agency_id}/${pickYear}/${audit_state}/edit` + ? `/products/${activeAgency.travel_agency_id}/${pickYear}/all/edit` : `/products/edit` } > From f1ab003667cc2ca48fb1d811cc649ff7e8deb30a Mon Sep 17 00:00:00 2001 From: Lei OT Date: Thu, 7 Aug 2025 17:13:33 +0800 Subject: [PATCH 54/56] =?UTF-8?q?perf:=20=E4=BA=A7=E5=93=81=E5=AE=A1?= =?UTF-8?q?=E6=A0=B8:=20=E4=BB=B7=E6=A0=BC=E5=8E=86=E5=8F=B2:=20=E5=9C=B0?= =?UTF-8?q?=E6=8E=A5=E6=9F=A5=E7=9C=8B=20=E6=9D=83=E9=99=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/products/Detail/ProductQuotationLogPopover.jsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/views/products/Detail/ProductQuotationLogPopover.jsx b/src/views/products/Detail/ProductQuotationLogPopover.jsx index 9991f93..cdbc813 100644 --- a/src/views/products/Detail/ProductQuotationLogPopover.jsx +++ b/src/views/products/Detail/ProductQuotationLogPopover.jsx @@ -5,6 +5,7 @@ import { HT_HOST } from '@/config'; import { fetchJSON } from '@/utils/request'; import { formatGroupSize } from '@/hooks/useProductsSets'; import { isEmpty, isNotEmpty } from '@/utils/commons'; +import { usingStorage } from '@/hooks/usingStorage'; /** * 产品价格日志 @@ -199,6 +200,7 @@ const useLogMethod = (method) => { */ const ProductQuotationLogPopover = ({ method, triggerProps = {}, onOpenChange, ...props }) => { const { travel_agency_id, product_id, price_id, use_year } = props; + const { travelAgencyId } = usingStorage(); const { t } = useTranslation('products'); const [open, setOpen] = useState(false); @@ -211,7 +213,7 @@ const ProductQuotationLogPopover = ({ method, triggerProps = {}, onOpenChange, . const [loading, setLoading] = useState(false); const getData = async () => { setLoading(true); - const { data } = await fetchData({ travel_agency_id, product_id, price_id, use_year }); + const { data } = await fetchData({ travel_agency_id: travel_agency_id || travelAgencyId, product_id, price_id, use_year }); setLogData(data); invokeOpenChange(true); setLoading(false); From 1b302f0f7aa2dd59bb409884f9c895597fadac44 Mon Sep 17 00:00:00 2001 From: LiaoYijun Date: Fri, 8 Aug 2025 17:01:32 +0800 Subject: [PATCH 55/56] =?UTF-8?q?perf=EF=BC=9A=E4=B8=8D=E5=88=86=E4=BA=BA?= =?UTF-8?q?=E7=AD=89=E3=80=81=E4=B8=8D=E9=99=90=E5=A2=9E=E5=8A=A0=E6=A0=A1?= =?UTF-8?q?=E9=AA=8C=E5=B9=B6=E9=80=9A=E8=BF=87=E5=90=8E=E5=86=8D=E5=85=B3?= =?UTF-8?q?=E9=97=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/account/Management.jsx | 2 +- src/views/account/RoleList.jsx | 2 +- .../products/Detail/ContractRemarksModal.jsx | 2 +- .../products/Detail/ProductInfoQuotation.jsx | 737 +++++++++++------- 4 files changed, 457 insertions(+), 286 deletions(-) diff --git a/src/views/account/Management.jsx b/src/views/account/Management.jsx index 7e51825..e6030c4 100644 --- a/src/views/account/Management.jsx +++ b/src/views/account/Management.jsx @@ -231,7 +231,7 @@ function Management() { }} title={t('account:detail')} open={isAccountModalOpen} onCancel={() => setAccountModalOpen(false)} - destroyOnClose + destroyOnHidden forceRender modalRender={(dom) => (
setRoleModalOpen(false)} - destroyOnClose + destroyOnHidden forceRender modalRender={(dom) => ( { open={isRemarksModalOpen} onOk={() => onRemarksFinish()} onCancel={() => setRemarksModalOpen(false)} - destroyOnClose + destroyOnHidden forceRender > [dayjs().year(year).startOf('y'), dayjs().year(year).endOf('y')] +const getYearRange = (year) => [ + dayjs().year(year).startOf("y"), + dayjs().year(year).endOf("y"), +]; const generateDefinitionValue = (year) => ({ - 'useDateList': [{'useDate': getYearRange(year)}], - 'unitId': '0', - 'currency': 'RMB', - 'weekend': [], - 'priceList': [defaultPriceValue] - }) + useDateList: [{ useDate: getYearRange(year) }], + unitId: "0", + currency: "RMB", + weekend: [], + priceList: [defaultPriceValue], +}); const ProductInfoQuotation = ({ editable, ...props }) => { + const { onChange } = props; - const { onChange } = props + const { t } = useTranslation(); - const { t } = useTranslation() - - const [quotationList, newEmptyQuotation, appendQuotationList, saveOrUpdateQuotation, deleteQuotation, switchParams] = - useProductsStore((state) => [ - state.quotationList, state.newEmptyQuotation, state.appendQuotationList, state.saveOrUpdateQuotation, state.deleteQuotation, - state.switchParams - ]) + const [ + quotationList, + newEmptyQuotation, + appendQuotationList, + saveOrUpdateQuotation, + deleteQuotation, + switchParams, + ] = useProductsStore((state) => [ + state.quotationList, + state.newEmptyQuotation, + state.appendQuotationList, + state.saveOrUpdateQuotation, + state.deleteQuotation, + state.switchParams, + ]); const batchSetupInitialValues = { - 'defList': [ + defList: [ // 全年 { - 'useDateList': [{'useDate': getYearRange(switchParams.use_year)}], - 'unitId': '0', - 'currency': 'RMB', - 'weekend': [], - 'priceList': [ + useDateList: [{ useDate: getYearRange(switchParams.use_year) }], + unitId: "0", + currency: "RMB", + weekend: [], + priceList: [ { - 'priceInput': { - 'numberStart': 1, - 'numberEnd': 2, - 'audultPrice': 0, - 'childrenPrice': 0 - } + priceInput: { + numberStart: 1, + numberEnd: 2, + audultPrice: 0, + childrenPrice: 0, + }, }, { - 'priceInput': { - 'numberStart': 3, - 'numberEnd': 4, - 'audultPrice': 0, - 'childrenPrice': 0 - } + priceInput: { + numberStart: 3, + numberEnd: 4, + audultPrice: 0, + childrenPrice: 0, + }, }, { - 'priceInput': { - 'numberStart': 5, - 'numberEnd': 6, - 'audultPrice': 0, - 'childrenPrice': 0 - } + priceInput: { + numberStart: 5, + numberEnd: 6, + audultPrice: 0, + childrenPrice: 0, + }, }, { - 'priceInput': { - 'numberStart': 7, - 'numberEnd': 9, - 'audultPrice': 0, - 'childrenPrice': 0 - } - } - ] + priceInput: { + numberStart: 7, + numberEnd: 9, + audultPrice: 0, + childrenPrice: 0, + }, + }, + ], }, // 特殊时间段 { - 'useDateList': [ + useDateList: [ { - 'useDate': [ - dayjs().year(switchParams.use_year).subtract(2, 'M').startOf('M'), dayjs().year(switchParams.use_year).endOf('M') - ] - } + useDate: [ + dayjs().year(switchParams.use_year).subtract(2, "M").startOf("M"), + dayjs().year(switchParams.use_year).endOf("M"), + ], + }, ], - 'unitId': '0', - 'currency': 'RMB', - 'weekend': [], - 'priceList': [ + unitId: "0", + currency: "RMB", + weekend: [], + priceList: [ { - 'priceInput': { - 'numberStart': 1, - 'numberEnd': 2, - 'audultPrice': 0, - 'childrenPrice': 0 - } + priceInput: { + numberStart: 1, + numberEnd: 2, + audultPrice: 0, + childrenPrice: 0, + }, }, { - 'priceInput': { - 'numberStart': 3, - 'numberEnd': 4, - 'audultPrice': 0, - 'childrenPrice': 0 - } + priceInput: { + numberStart: 3, + numberEnd: 4, + audultPrice: 0, + childrenPrice: 0, + }, }, { - 'priceInput': { - 'numberStart': 5, - 'numberEnd': 6, - 'audultPrice': 0, - 'childrenPrice': 0 - } + priceInput: { + numberStart: 5, + numberEnd: 6, + audultPrice: 0, + childrenPrice: 0, + }, }, { - 'priceInput': { - 'numberStart': 7, - 'numberEnd': 9, - 'audultPrice': 0, - 'childrenPrice': 0 - } - } - ] - } - ] - } + priceInput: { + numberStart: 7, + numberEnd: 9, + audultPrice: 0, + childrenPrice: 0, + }, + }, + ], + }, + ], + }; - const [defaultUseDates, setDefaultUseDates] = useState(getYearRange(switchParams.use_year)) - const [defaultDefinitionValue, setDefaultDefinitionValue] = useState(generateDefinitionValue(switchParams.use_year)) - const [isQuotationModalOpen, setQuotationModalOpen] = useState(false) - const [isBatchSetupModalOpen, setBatchSetupModalOpen] = useState(false) - const [groupSizeUnlimit, setGroupSizeUnlimit] = useState(false) - const [groupMaxUnlimit, setGroupMaxUnlimit] = useState(false) - const { modal, notification } = App.useApp() - const [quotationForm] = Form.useForm() - const [batchSetupForm] = Form.useForm() + const [defaultUseDates, setDefaultUseDates] = useState( + getYearRange(switchParams.use_year) + ); + const [defaultDefinitionValue, setDefaultDefinitionValue] = useState( + generateDefinitionValue(switchParams.use_year) + ); + const [isQuotationModalOpen, setQuotationModalOpen] = useState(false); + const [isBatchSetupModalOpen, setBatchSetupModalOpen] = useState(false); + const [groupAllSize, setGroupAllSize] = useState(false); + const [groupMaxUnlimit, setGroupMaxUnlimit] = useState(false); + const { modal, notification } = App.useApp(); + const [quotationForm] = Form.useForm(); + const [batchSetupForm] = Form.useForm(); - const datePresets = useDatePresets() + const datePresets = useDatePresets(); useEffect(() => { - setDefaultUseDates(getYearRange(switchParams.use_year)) - setDefaultDefinitionValue(generateDefinitionValue(switchParams.use_year)) - }, [switchParams]) - + setDefaultUseDates(getYearRange(switchParams.use_year)); + setDefaultDefinitionValue(generateDefinitionValue(switchParams.use_year)); + }, [switchParams]); const triggerChange = (changedValue) => { - onChange?.( - changedValue - ) - } + onChange?.(changedValue); + }; const onQuotationSeleted = async (quotation) => { // 把 start, end 转换为 RangePicker 数组格式 - quotation.use_dates = [dayjs(quotation.use_dates_start), dayjs(quotation.use_dates_end)] - quotation.weekdayList = quotation.weekdays.split(',') - quotationForm.setFieldsValue(quotation) - setQuotationModalOpen(true) - } + quotation.use_dates = [ + dayjs(quotation.use_dates_start), + dayjs(quotation.use_dates_end), + ]; + quotation.weekdayList = quotation.weekdays.split(","); + quotationForm.setFieldsValue(quotation); + setQuotationModalOpen(true); + }; const onNewQuotation = () => { - const emptyQuotation = newEmptyQuotation(defaultUseDates) - quotationForm.setFieldsValue(emptyQuotation) - setQuotationModalOpen(true) - } + const emptyQuotation = newEmptyQuotation(defaultUseDates); + quotationForm.setFieldsValue(emptyQuotation); + setQuotationModalOpen(true); + }; const onQuotationFinish = (values) => { - const newList = saveOrUpdateQuotation(values) - triggerChange(newList) - setQuotationModalOpen(false) - } + const newList = saveOrUpdateQuotation(values); + triggerChange(newList); + setQuotationModalOpen(false); + }; const onBatchSetupFinish = () => { - const defList = batchSetupForm.getFieldsValue().defList - const newList = appendQuotationList(defList) - triggerChange(newList) - setBatchSetupModalOpen(false) - } + const defList = batchSetupForm.getFieldsValue().defList; + const newList = appendQuotationList(defList); + triggerChange(newList); + setBatchSetupModalOpen(false); + }; const onDeleteQuotation = (quotation) => { modal.confirm({ - title: '请确认', + title: "请确认", icon: , - content: '你要删除这条价格吗?', + content: "你要删除这条价格吗?", onOk() { - deleteQuotation(quotation) - .catch(ex => { - notification.error({ - message: 'Notification', - description: ex.message, - placement: 'top', - duration: 4, - }) - }) + deleteQuotation(quotation).catch((ex) => { + notification.error({ + message: "Notification", + description: ex.message, + placement: "top", + duration: 4, + }); + }); }, - }) - } + }); + }; const quotationColumns = [ // { title: 'id', dataIndex: 'id', width: 40, className: 'italic text-gray-400' }, // test: 0 // { title: 'WPI_SN', dataIndex: 'WPI_SN', width: 40, className: 'italic text-gray-400' }, // test: 0 - { title: t('products:adultPrice'), dataIndex: 'adult_cost', width: '5rem' }, - { title: t('products:childrenPrice'), dataIndex: 'child_cost', width: '5rem' }, - { title: t('products:currency'), dataIndex: 'currency', width: '4rem' }, + { title: t("products:adultPrice"), dataIndex: "adult_cost", width: "5rem" }, + { + title: t("products:childrenPrice"), + dataIndex: "child_cost", + width: "5rem", + }, + { title: t("products:currency"), dataIndex: "currency", width: "4rem" }, { - title: (<>{t('products:unit_name')} ), - dataIndex: 'unit_id', - width: '6rem', + title: ( + <> + {t("products:unit_name")}{" "} + + + {" "} + + ), + dataIndex: "unit_id", + width: "6rem", render: (text) => t(`products:PriceUnit.${text}`), // (text === '0' ? '每人' : text === '1' ? '每团' : text), }, { - title: t('products:group_size'), - dataIndex: 'group_size', - width: '6rem', - render: (_, record) => formatGroupSize(record.group_size_min,record.group_size_max), + title: t("products:group_size"), + dataIndex: "group_size", + width: "6rem", + render: (_, record) => + formatGroupSize(record.group_size_min, record.group_size_max), }, { - title: (<>{t('products:use_dates')} ), - dataIndex: 'use_dates', + title: ( + <> + {t("products:use_dates")}{" "} + + + {" "} + + ), + dataIndex: "use_dates", // width: '6rem', - render: (_, record) => `${record.use_dates_start}-${record.use_dates_end}`, + render: (_, record) => + `${record.use_dates_start}-${record.use_dates_end}`, }, - { title: t('products:Weekdays'), dataIndex: 'weekdays', width: '4rem' }, + { title: t("products:Weekdays"), dataIndex: "weekdays", width: "4rem" }, { - title: t('products:operation'), - dataIndex: 'operation', - width: '10rem', + title: t("products:operation"), + dataIndex: "operation", + width: "10rem", render: (_, quotation) => { // const _rowEditable = [-1,3].includes(quotation.audit_state_id); const _rowEditable = true; // test: 0 return ( - - + + - ) + ); }, }, - ] + ]; return ( <> -

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

-
{t("products:EditComponents.Quotation")} +
- { - editable && + {editable && ( - - - } + )} onBatchSetupFinish()} onCancel={() => setBatchSetupModalOpen(false)} - destroyOnClose + destroyOnHidden forceRender > - + {(fields, { add, remove }) => ( - + {fields.map((field, index) => ( : { - remove(field.name) - }} />} + extra={ + index == 0 ? ( + + ) : ( + { + remove(field.name); + }} + /> + ) + } > - + - RMB - USD - THB - JPY + RMB + USD + THB + JPY - + - 每人 - 每团 + 每人 + 每团 - - + + - - + + {(useDateFieldList, useDateOptList) => ( - + {useDateFieldList.map((useDateField, index) => ( - - + + - {index == 0 ? : useDateOptList.remove(useDateField.name)} />} + {index == 0 ? ( + + ) : ( + + useDateOptList.remove(useDateField.name) + } + /> + )} ))} - )} - - + + {(priceFieldList, priceOptList) => ( - + {priceFieldList.map((priceField, index) => ( - + - {index == 0 ? : priceOptList.remove(priceField.name)} />} + {index == 0 ? ( + + ) : ( + + priceOptList.remove(priceField.name) + } + /> + )} ))} - @@ -358,7 +496,12 @@ const ProductInfoQuotation = ({ editable, ...props }) => { ))} - @@ -371,152 +514,180 @@ const ProductInfoQuotation = ({ editable, ...props }) => { centered okButtonProps={{ autoFocus: true, - htmlType: 'submit', + htmlType: "submit", }} - title={t('account:detail')} - open={isQuotationModalOpen} onCancel={() => setQuotationModalOpen(false)} - destroyOnClose + title={t("products:EditComponents.Quotation")} + open={isQuotationModalOpen} + onCancel={() => setQuotationModalOpen(false)} + destroyOnHidden forceRender modalRender={(dom) => ( {dom} )} > - - - + + + + + + + + + - + - + - RMB - USD - THB - JPY + RMB + USD + THB + JPY - 每人 - 每团 + 每人 + 每团 - { + { if (e.target.checked) { - quotationForm.setFieldValue('group_size_min', 0) - quotationForm.setFieldValue('group_size_max', 1000) - setGroupSizeUnlimit(true) - + quotationForm.setFieldValue("group_size_min", 1); + quotationForm.setFieldValue("group_size_max", 1000); + setGroupAllSize(true); } else { - quotationForm.setFieldValue('group_size_min', 1) - if (!groupMaxUnlimit) quotationForm.setFieldValue('group_size_max', 999) - setGroupSizeUnlimit(false) + setGroupAllSize(false); } - }}>不分人等(0~1000) + }} + > + 不分人等(1~1000) + { + if (value > 1000 || value < 1) { + return Promise.reject("人等必须在 1~1000 之间"); + } + return Promise.resolve(); + }, }, ]} > - + - { + { if (e.target.checked) { - quotationForm.setFieldValue('group_size_max', 1000) - setGroupMaxUnlimit(true) + quotationForm.setFieldValue("group_size_max", 1000); + setGroupMaxUnlimit(true); } else { - quotationForm.setFieldValue('group_size_max', 999) - setGroupMaxUnlimit(false) + setGroupMaxUnlimit(false); } - }}>不限(1000) + }} + > + 不限(1000) + { + if (value > 1000 || value < 1) { + return Promise.reject("人等必须在 1~1000 之间"); + } + return Promise.resolve(); + }, }, ]} > - + - + - - + + - ) -} + ); +}; -export default ProductInfoQuotation +export default ProductInfoQuotation; From 38206514242c873eb118e483a5680664aaa71115 Mon Sep 17 00:00:00 2001 From: LiaoYijun Date: Mon, 11 Aug 2025 11:28:18 +0800 Subject: [PATCH 56/56] =?UTF-8?q?perf=EF=BC=9A=E4=BE=9B=E5=BA=94=E5=95=86?= =?UTF-8?q?=E5=A4=9A=E9=80=89=E8=87=B3=E5=B0=91=E6=98=BE=E7=A4=BA=E4=B8=80?= =?UTF-8?q?=E4=B8=AA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/SearchForm.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/SearchForm.jsx b/src/components/SearchForm.jsx index cc182ae..7959904 100644 --- a/src/components/SearchForm.jsx +++ b/src/components/SearchForm.jsx @@ -271,7 +271,7 @@ function getFields(props) { "agency", //地接社 99, - + , fieldProps?.agency?.col || 6 ),