feat(产品管理): 复制指定产品

main
Lei OT 2 months ago
parent 3820651424
commit b780c37a57

@ -1,5 +1,6 @@
{
"ProductType": "项目类型",
"ProductName": "产品名称",
"ContractRemarks": "合同备注",
"versionHistory": "查看历史",
"versionPublished": "已发布的",
@ -84,7 +85,8 @@
"withQuote": "是否复制报价",
"requiredVendor": "请选择目标供应商",
"requiredTypes": "请选择产品类型",
"requiredDept": "请选择所属小组"
"requiredDept": "请选择所属小组",
"copyTo": "复制到"
},
"Validation": {
"adultPrice": "请输入成人价",

@ -0,0 +1,56 @@
import { useEffect, useState } from 'react';
import { Select, Spin } from 'antd';
import { fetchJSON } from '@/utils/request';
import { HT_HOST } from '@/config';
import { useTranslation } from 'react-i18next';
import { groupBy } from '@/utils/commons';
//
export const fetchAgencyProductsList = async (params) => {
const map = { title: 'label', id: 'value' };
const { errcode, result } = await fetchJSON(`${HT_HOST}/Service_BaseInfoWeb/travel_agency_products`, params);
const byTypes = errcode !== 0 ? {} : (groupBy(result.products, (row) => row.info.product_type_name));
// console.log(byTypes)
return Object.keys(byTypes).map((type_name) => ({ lable: type_name, title: type_name, key: type_name, options: byTypes[type_name].map(row => ({...row, label: `${row.info.code} : ${row.info.title}`, value: row.info.id})) }));
};
const ProductsSelector = ({ params, ...props }) => {
const { t } = useTranslation();
const [fetching, setFetching] = useState(false);
const [options, setOptions] = useState([]);
const fetchAction = async () => {
setOptions([]);
setFetching(true);
const data = await fetchAgencyProductsList(params);
// console.log(data)
setOptions(data);
setFetching(false);
return data;
};
useEffect(() => {
fetchAction();
return () => {};
}, []);
return (
<>
<Select
placeholder={t('products:ProductName')}
labelInValue
// filterOption={false}
showSearch
allowClear
maxTagCount={0}
dropdownStyle={{ width: '20rem' }}
{...props}
// onSearch={debounceFetcher}
notFoundContent={fetching ? <Spin size='small' /> : null}
optionFilterProp='label'
options={options}>
</Select>
</>
);
};
export default ProductsSelector;

@ -1,5 +1,5 @@
import { useState, useEffect } from 'react';
import { App, Form, Modal, DatePicker, Divider, Switch } from 'antd';
import { App, Form, Modal, DatePicker, Divider, Switch, Space, Flex } from 'antd';
import { isEmpty, objectMapper } from '@/utils/commons';
import { useTranslation } from 'react-i18next';
@ -13,43 +13,102 @@ import { copyAgencyDataAction } from '@/stores/Products/Index';
import useAuthStore from '@/stores/Auth';
import RequireAuth from '@/components/RequireAuth';
import { PERM_PRODUCTS_MANAGEMENT } from '@/config';
import ProductsSelector from '@/components/ProductsSelector';
dayjs.extend(arraySupport);
export const CopyProductsForm = ({ action, initialValues, onFormInstanceReady, source, ...props }) => {
const { t } = useTranslation();
const [form] = Form.useForm();
const {
sourceAgency: { travel_agency_id },
sourceYear: use_year,
} = source;
const isPermitted = useAuthStore((state) => state.isPermitted);
const [typeDisabled, setTypeDisabled] = useState(false);
useEffect(() => {
onFormInstanceReady(form);
}, []);
const onValuesChange = (changeValues, allValues) => {};
return (
<Form layout='horizontal' form={form} name='form_in_modal' initialValues={initialValues} onValuesChange={onValuesChange}>
{action === '#' && <Form.Item name='agency' label={`${t('products:CopyFormMsg.target')}${t('products:Vendor')}`} rules={[{ required: true, message: t('products:CopyFormMsg.requiredVendor') }]}>
<VendorSelector mode={null} placeholder={t('products:Vendor')} />
</Form.Item>}
<Form.Item name={`products_types`} label={t('products:ProductType')} >
<ProductsTypesSelector maxTagCount={1} mode={'multiple'} placeholder={t('All')} />
</Form.Item>
{action === '#' && <RequireAuth subject={PERM_PRODUCTS_MANAGEMENT}>
<Flex gap={8}>
<div className='basis-96 shrink-0 flex-auto'>
{action === '#' && (
<RequireAuth subject={PERM_PRODUCTS_MANAGEMENT}>
<Form.Item name={`dept`} label={t('products:Dept')} rules={[{ required: false, message: t('products:CopyFormMsg.requiredDept') }]}>
<DeptSelector isLeaf={true} />
</Form.Item>
</RequireAuth>}
<Form.Item name={'source_use_year'} label={`${t('products:CopyFormMsg.Source')}${t('products:UseYear')}`} initialValue={dayjs([source.sourceYear, 1, 1])} rules={[{ required: true,}]}>
</RequireAuth>
)}
<Form.Item name={`products_types`} label={t('products:ProductType')} dependencies={['products_list']} rules={[
({ getFieldValue }) => ({
warningOnly: true,
validator: async () => {
if (!isEmpty(getFieldValue('products_list'))) {
// setTypeDisabled(true);
return Promise.reject(new Error(t(`⚠勾选了复制的产品名称之后 🔽, 将忽略选择的类型 🔼`)));
}
// setTypeDisabled(false);
return Promise.resolve();
},
}),
]}>
<ProductsTypesSelector disabled={typeDisabled} maxTagCount={1} mode={'multiple'} placeholder={t('All')} />
</Form.Item>
<Form.Item
name={'products_list'}
label={t('products:ProductName')} dependencies={['products_types']} >
<ProductsSelector params={{ travel_agency_id, use_year }} mode={'multiple'} placeholder={t('All')} />
</Form.Item>
<Divider orientation='left'>{t('products:CopyFormMsg.copyTo')}:</Divider>
{action === '#' && (
<Form.Item
name='agency'
label={`${t('products:CopyFormMsg.target')}${t('products:Vendor')}`}
rules={[{ required: true, message: t('products:CopyFormMsg.requiredVendor') }]}>
<VendorSelector mode={null} placeholder={t('products:Vendor')} />
</Form.Item>
)}
<Divider orientation='left'></Divider>
<Form.Item noStyle>
<Space.Compact className='w-full gap-2'>
<Form.Item
name={'source_use_year'}
label={`${t('products:CopyFormMsg.Source')}${t('products:UseYear')}`}
initialValue={dayjs([source.sourceYear, 1, 1])}
rules={[{ required: true }]}>
<DatePicker picker='year' allowClear />
</Form.Item>
<Form.Item name={'target_use_year'} label={`${t('products:CopyFormMsg.target')}${t('products:UseYear')}`} rules={[{ required: true,}]}>
<Form.Item name={'target_use_year'} label={`${t('products:CopyFormMsg.target')}${t('products:UseYear')}`} rules={[{ required: true }]}>
<DatePicker picker='year' allowClear />
{/* disabledDate={(current) => current <= dayjs([source.sourceYear, 12, 31])} */}
</Form.Item>
</Space.Compact>
</Form.Item>
<Form.Item name={'with_quote'} label={`${t('products:CopyFormMsg.withQuote')}`}>
<Switch checkedChildren={'含报价金额'} unCheckedChildren={'仅人等+日期'} />
</Form.Item>
</div>
<Form.Item noStyle shouldUpdate>
{() => (
<div className='max-h-96 overflow-auto divide-x-0 divide-y divide-solid divide-stone-200'>
{!isEmpty(form.getFieldValue('products_list')) && <b>已选择的产品 预览:</b>}
{(form.getFieldValue('products_list') || []).map((item, index) => (
<div key={item.value}>
{index + 1}.&nbsp;{item.label}
</div>
))}
</div>
)}
</Form.Item>
</Flex>
</Form>
);
};
@ -76,9 +135,10 @@ const formValuesMapper = (values) => {
},
},
'with_quote': { key: 'with_quote', transform: (value) => (value ? 1 : 0) },
'products_list': { key: 'product_id_list', transform: (value) => (Array.isArray(value) ? value.map((ele) => ele.key).join(',') : value ? value.value : '') },
};
let dest = {};
const { agency, year, ...omittedValue } = values;
const { agency, year, products_list, ...omittedValue } = values;
dest = { ...omittedValue, ...objectMapper(values, destinationObject) };
for (const key in dest) {
if (Object.prototype.hasOwnProperty.call(dest, key)) {
@ -101,15 +161,18 @@ export const CopyProductsFormModal = ({ source, action = '#' | 'o', open, onSubm
const handleCopyAgency = async (param) => {
param.target_agency = isEmpty(param.target_agency) ? source.sourceAgency.travel_agency_id : param.target_agency;
setCopyLoading(true);
// console.log(param);
// debug:
// console.log('ready params', param);
// setCopyLoading(false);
// throw new Error('');
// const toID = param.target_agency;
const success = await copyAgencyDataAction({...param, source_agency: source.sourceAgency.travel_agency_id}).catch(ex => {
const success = await copyAgencyDataAction({ ...param, source_agency: source.sourceAgency.travel_agency_id }).catch((ex) => {
notification.error({
message: 'Notification',
description: ex.message,
placement: 'top',
duration: 4,
})
});
});
setCopyLoading(false);
success ? message.success(t('Success')) : message.error(t('Failed'));
@ -122,7 +185,7 @@ export const CopyProductsFormModal = ({ source, action = '#' | 'o', open, onSubm
};
return (
<Modal
width={600}
width={800}
open={open}
title={`${t('Copy')}${t('products:#')}${t('products:Offer')}`}
okText='确认'
@ -153,7 +216,8 @@ export const CopyProductsFormModal = ({ source, action = '#' | 'o', open, onSubm
{source.sourceYear}
</div>
</RequireAuth>
<CopyProductsForm action={action}
<CopyProductsForm
action={action}
source={source}
initialValues={initialValues}
onFormInstanceReady={(instance) => {

Loading…
Cancel
Save