feat: 复制产品价格

perf/export-docx
Lei OT 12 months ago
parent 472273396c
commit 6ae1984b91

@ -59,6 +59,7 @@
"tourTime": "Tour time",
"recommendationRate": "Recommends rate",
"Name": "Name",
"Price":"Price",
"Description":"Description",
"supplierQuotation": "Supplier quotation",
"addQuotation": "Add quotation",
@ -95,6 +96,7 @@
},
"CopyFormMsg": {
"target": "Target ",
"requiredVendor": "Please pick a target vendor",
"requiredTypes": "Please select product types",
"requiredDept": "Please pick a owner department"
@ -111,5 +113,5 @@
"Weekdays": "Weekdays"
},
"#": "#"
"#": "Products"
}

@ -96,6 +96,7 @@
},
"CopyFormMsg": {
"target": "目标",
"requiredVendor": "请选择目标供应商",
"requiredTypes": "请选择产品类型",
"requiredDept": "请选择所属小组"
@ -112,5 +113,5 @@
"Operation": "Operation"
},
"#": "#"
"#": "产品"
}

@ -0,0 +1,23 @@
import { Select } from 'antd';
import { useProductsTypes } from '@/hooks/useProductsSets';
import { useTranslation } from 'react-i18next';
import { fetchJSON } from '@/utils/request';
import { HT_HOST } from '@/config';
//
export const fetchVendorList = async (q) => {
const { errcode, result } = await fetchJSON(`${HT_HOST}/Service_BaseInfoWeb/VendorList`, { q })
return errcode !== 0 ? [] : result
}
const ProductsTypesSelector = ({...props}) => {
const productsTypes = useProductsTypes();
const { t } = useTranslation();
return (
<>
<Select labelInValue allowClear placeholder={t('products:ProductType')} options={productsTypes} {...props}/>
</>
);
};
export default ProductsTypesSelector;

@ -4,34 +4,15 @@ import { objectMapper, at } from '@/utils/commons';
import { DATE_FORMAT, SMALL_DATETIME_FORMAT } from '@/config';
import useFormStore from '@/stores/Form';
import { useDatePresets } from '@/hooks/useDatePresets';
import { useProductsTypes } from '@/hooks/useProductsSets';
import { useTranslation } from 'react-i18next';
import { fetchJSON } from '@/utils/request';
import { HT_HOST } from '@/config';
import SearchInput from './SearchInput';
import AuditStateSelector from './AuditStateSelector';
import DeptSelector from './DeptSelector';
//
export const fetchVendorList = async (q) => {
const { errcode, result } = await fetchJSON(`${HT_HOST}/Service_BaseInfoWeb/VendorList`, { q })
return errcode !== 0 ? [] : result
}
import ProductsTypesSelector, { fetchVendorList } from './ProductsTypesSelector';
const { RangePicker } = DatePicker;
export const SelectProductsTypes = ({...props}) => {
const productsTypes = useProductsTypes();
const { t } = useTranslation();
return (
<>
<Select labelInValue allowClear placeholder={t('products:ProductType')} options={productsTypes} {...props}/>
</>
);
};
const SearchForm = ({ initialValue, onSubmit, onReset, confirmText, formName, formLayout, loading, ...props }) => {
const { t } = useTranslation();
const presets = useDatePresets();
@ -283,7 +264,7 @@ function getFields(props) {
'products_types',
99,
<Form.Item name={`products_types`} label={t('products:ProductType')} {...fieldProps.products_types} initialValue={at(props, 'initialValue.products_types')[0] || undefined}>
<SelectProductsTypes maxTagCount={1} {...fieldComProps.products_types} />
<ProductsTypesSelector maxTagCount={1} {...fieldComProps.products_types} />
</Form.Item>,
fieldProps?.products_types?.col || 6
),

@ -25,7 +25,7 @@ export const copyAgencyDataAction = async (postbody) => {
Object.keys(postbody).forEach((key) => {
formData.append(key, postbody[key]);
});
const { errcode, result } = await postForm(`${HT_HOST}/agency/products/copy`, formData);
const { errcode, result } = await postForm(`${HT_HOST}/Service_BaseInfoWeb/agency_products_copy`, formData);
return errcode === 0 ? true : false;
};

@ -0,0 +1,160 @@
import { useState, useEffect } from 'react';
import { App, Form, Modal, DatePicker, Divider } from 'antd';
import { isEmpty, objectMapper } from '@/utils/commons';
import { useTranslation } from 'react-i18next';
import SearchInput from '@/components/SearchInput';
import DeptSelector from '@/components/DeptSelector';
import ProductsTypesSelector, { fetchVendorList } from '@/components/ProductsTypesSelector';
import dayjs from 'dayjs';
import arraySupport from 'dayjs/plugin/arraySupport';
import { copyAgencyDataAction } from '@/stores/Products/Index';
import useAuthStore from '@/stores/Auth';
import RequireAuth from '@/components/RequireAuth';
import { PERM_PRODUCTS_MANAGEMENT } from '@/config';
dayjs.extend(arraySupport);
export const CopyProductsForm = ({ action, initialValues, onFormInstanceReady, source, ...props }) => {
const { t } = useTranslation();
const [form] = Form.useForm();
const isPermitted = useAuthStore((state) => state.isPermitted);
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') }]}>
<SearchInput
placeholder={t('products:Vendor')}
mode={null}
maxTagCount={0}
fetchOptions={fetchVendorList}
map={{ travel_agency_name: 'label', travel_agency_id: 'value' }}
/>
</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}>
<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])}>
<DatePicker picker='year' allowClear />
</Form.Item>
<Form.Item name={'target_use_year'} label={`${t('products:CopyFormMsg.target')}${t('products:UseYear')}`}>
<DatePicker picker='year' allowClear disabledDate={(current) => current <= dayjs([source.sourceYear, 12, 31])} />
</Form.Item>
</Form>
);
};
const formValuesMapper = (values) => {
const destinationObject = {
'agency': {
key: 'target_agency',
transform: (value) => {
return Array.isArray(value) ? value.map((ele) => ele.key).join(',') : value ? value.value : '';
},
},
'source_use_year': [{ key: 'source_use_year', transform: (arrVal) => (arrVal ? arrVal.format('YYYY') : '') }],
'target_use_year': [{ key: 'target_use_year', transform: (arrVal) => (arrVal ? arrVal.format('YYYY') : '') }],
'products_types': {
key: 'products_types',
transform: (value) => {
return Array.isArray(value) ? value.map((ele) => ele.key).join(',') : value ? value.value : '';
},
},
'dept': {
key: 'dept',
transform: (value) => {
return Array.isArray(value) ? value.map((ele) => ele.key).join(',') : value ? value.value : '';
},
},
};
let dest = {};
const { agency, year, ...omittedValue } = values;
dest = { ...omittedValue, ...objectMapper(values, destinationObject) };
for (const key in dest) {
if (Object.prototype.hasOwnProperty.call(dest, key)) {
dest[key] = typeof dest[key] === 'string' ? (dest[key] || '').trim() : dest[key];
}
}
// omit empty
// Object.keys(dest).forEach((key) => (dest[key] == null || dest[key] === '' || dest[key].length === 0) && delete dest[key]);
return dest;
};
/**
*
*/
export const CopyProductsFormModal = ({ source, action = '#' | 'o', open, onSubmit, onCancel, initialValues, loading, copyModalVisible, setCopyModalVisible }) => {
const { t } = useTranslation();
const { notification, message } = App.useApp();
const [formInstance, setFormInstance] = useState();
const [copyLoading, setCopyLoading] = useState(false);
const handleCopyAgency = async (param) => {
param.target_agency = isEmpty(param.target_agency) ? source.sourceAgency.travel_agency_id : param.target_agency;
setCopyLoading(true);
console.log(param);
const toID = param.target_agency;
const success = await copyAgencyDataAction({...param, source_agency: source.sourceAgency.travel_agency_id});
setCopyLoading(false);
success ? message.success(t('Success')) : message.error(t('Failed'));
if (typeof onSubmit === 'function') {
onSubmit(param);
}
// setCopyModalVisible(false);
// navigate(`/products/${toID}/${searchValues.use_year || 'all'}/${searchValues.audit_state || 'all'}/edit`);
};
return (
<Modal
width={600}
open={open}
title={`${t('Copy')}${t('products:#')}${t('products:Offer')}`}
okText='确认'
// cancelText='Cancel'
okButtonProps={{
autoFocus: true,
}}
confirmLoading={copyLoading}
onCancel={() => {
onCancel();
formInstance?.resetFields();
}}
destroyOnClose
onOk={async () => {
try {
const values = await formInstance?.validateFields();
// formInstance?.resetFields();
const dest = formValuesMapper(values);
handleCopyAgency(dest);
} catch (error) {
console.log('Failed:', error);
}
}}>
<RequireAuth subject={PERM_PRODUCTS_MANAGEMENT}>
<div className='py-2'>
{t('products:CopyFormMsg.Source')}: {source.sourceAgency.travel_agency_name}
<Divider type={'vertical'} />
{source.sourceYear}
</div>
</RequireAuth>
<CopyProductsForm action={action}
source={source}
initialValues={initialValues}
onFormInstanceReady={(instance) => {
setFormInstance(instance);
}}
/>
</Modal>
);
};
export default CopyProductsFormModal;

@ -1,12 +1,16 @@
import { useEffect, useState } from 'react';
import { Link, useNavigate } from 'react-router-dom';
import { App, Space, Table, Button, Modal } from 'antd';
import { App, Space, Table, Button, Modal, Divider } from 'antd';
import SearchForm from '@/components/SearchForm';
import dayjs from 'dayjs';
import arraySupport from 'dayjs/plugin/arraySupport';
import { useTranslation } from 'react-i18next';
import useProductsStore, { copyAgencyDataAction } from '@/stores/Products/Index';
import useFormStore from '@/stores/Form';
import { objectMapper } from '@/utils/commons';
import CopyProductsFormModal from './Detail/CopyProducts';
dayjs.extend(arraySupport);
function Index() {
const { notification, message } = App.useApp();
@ -16,6 +20,8 @@ function Index() {
const [searchValues, setSearchValues] = useProductsStore((state) => [state.searchValues, state.setSearchValues]);
const formValuesToSub = useFormStore(state => state.formValuesToSub);
const useYear = formValuesToSub.year;
const handleSearchAgency = (formVal = undefined) => {
const { starttime, endtime, ...param } = formVal || formValuesToSub;
const searchParam = objectMapper(param, { agency: 'travel_agency_ids', startdate: 'edit_date1', enddate: 'edit_date2', year: 'use_year' });
@ -25,21 +31,22 @@ function Index() {
const [copyModalVisible, setCopyModalVisible] = useState(false);
const [sourceAgency, setSourceAgency] = useState({});
const [copyAction, setCopyAction] = useState();
const [copyLoading, setCopyLoading] = useState(false);
const handleCopyAgency = async (param) => {
setCopyLoading(true);
const postbody = objectMapper(param, { agency: 'target_agency', });
const toID = postbody.target_agency;
const success = await copyAgencyDataAction({...postbody, source_agency: sourceAgency.travel_agency_id});
setCopyLoading(false);
success ? message.success('复制成功') : message.error('复制失败');
// setCopyLoading(true);
const toID = param.target_agency;
// const success = await copyAgencyDataAction({...param, source_agency: sourceAgency.travel_agency_id});
// setCopyLoading(false);
// success ? message.success('') : message.error('');
setCopyModalVisible(false);
navigate(`/products/${toID}/${searchValues.use_year || 'all'}/${searchValues.audit_state || 'all'}/edit`);
};
const openCopyModal = (from) => {
const openCopyModal = (from, action) => {
setSourceAgency(from);
setCopyAction(action);
setCopyModalVisible(true);
};
@ -51,8 +58,8 @@ function Index() {
const columns = [
{ title: t('products:Vendor'), key: 'vendor', dataIndex: 'travel_agency_name' },
{ title: t('products:CreatedBy'), key: 'created_by', dataIndex: 'created_by_name' },
{ title: t('products:CreateDate'), key: 'create_date', dataIndex: 'create_date' },
{ title: t('products:CreatedBy'), key: 'poster_by', dataIndex: 'poster_name' },
{ title: t('products:CreateDate'), key: 'poster_date', dataIndex: 'poster_date' },
{ title: t('products:AuState'), key: 'audit_state', dataIndex: 'audit_state' },
{ title: t('products:AuditedBy'), key: 'audited_by', dataIndex: 'audited_by_name' },
{ title: t('products:AuditDate'), key: 'audit_date', dataIndex: 'audit_date' },
@ -63,7 +70,8 @@ function Index() {
<Space size={'large'}>
<Link to={`/products/${r.travel_agency_id}/${searchValues.use_year || 'all'}/${searchValues.audit_state || 'all'}/edit`}>{t('Edit')}</Link>
<Link to={`/products/${r.travel_agency_id}/${searchValues.use_year || 'all'}/${searchValues.audit_state || 'all'}/audit`}>{t('Audit')}</Link>
<Button type='link' onClick={() => openCopyModal(r)}>{t('Copy')}</Button>
<Button type='link' size={'small'} onClick={() => openCopyModal(r, '#')}>{t('Copy')+'-'+t('products:#')}</Button>
<Button type='link' size={'small'} onClick={() => openCopyModal(r, 'o')}>{t('Copy')+'-'+t('products:Offer')}</Button>
</Space>
),
},
@ -72,19 +80,19 @@ function Index() {
<Space direction='vertical' style={{ width: '100%' }}>
<SearchForm
fieldsConfig={{
shows: ['agency', 'audit_state', 'dates', 'year', ],
shows: ['agency', 'audit_state', 'dates', 'year'],
fieldProps: {
agency: { col: 4 },
dates: { label: t('products:CreateDate') },
keyword: { label: t('products:Title'), col: 4 },
year: { col: 4 },
year: { col: 4, rules: [{ required: true }] },
},
sort: { agency: 1, audit_state: 2, keyword: 100 },
}}
initialValue={{
dates: [dayjs().subtract(2, 'M').startOf('M'), dayjs().endOf('M')],
audit_state: { value: '', label: t('products:State') },
year: dayjs().add(1, 'year'),
year: dayjs(), // .add(1, 'year'),
}}
onSubmit={(err, formVal, filedsVal) => {
handleSearchAgency(formVal);
@ -93,28 +101,16 @@ function Index() {
<Table bordered={true} columns={columns} dataSource={agencyList} pagination={{ defaultPageSize: 20, showTotal: showTotal }} loading={loading} rowKey={'travel_agency_id'} />
{/* 复制弹窗 */}
<Modal width={600} open={copyModalVisible} title={`复制供应商产品`} footer={false} onCancel={() => setCopyModalVisible(false)} destroyOnClose>
<div className='py-2'>复制源: {sourceAgency.travel_agency_name}</div>
<SearchForm formName='copyform' loading={copyLoading}
confirmText={t('Confirm')}
fieldsConfig={{
shows: ['agency', 'products_types', 'dept'],
fieldProps: {
agency: { label: `目标${t('products:Vendor')}`, col: 24, rules: [{ required: true, message: t('products:CopyFormMsg.requiredVendor') }] },
products_types: { col: 24 },
dept: { col: 24, rules: [{ required: true, message: t('products:CopyFormMsg.requiredDept') }] },
},
fieldComProps: {
agency: { mode: null }, //
products_types: { mode: 'multiple' },
dept: { isLeaf: true },
},
}}
onSubmit={(err, formVal, filedsVal) => {
handleCopyAgency(formVal);
}}
/>
</Modal>
<CopyProductsFormModal
open={copyModalVisible}
action={copyAction}
source={{ sourceAgency, sourceYear: useYear }}
onCancel={() => setCopyModalVisible(false)}
onSubmit={(formVal) => {
handleCopyAgency(formVal);
}}
{...{copyModalVisible, setCopyModalVisible}}
/>
</Space>
);
}

Loading…
Cancel
Save