feat: 产品: 附加项目: 新增; 删除; 读取
parent
1b97cb41dd
commit
2bdf22c140
@ -0,0 +1,173 @@
|
|||||||
|
import { createContext, useContext, useEffect, useState } from 'react';
|
||||||
|
import { useParams } from 'react-router-dom';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { App, Table, Button, Modal, Popconfirm } from 'antd';
|
||||||
|
import useProductsStore, { postProductsQuoteAudit, getAgencyProductExtrasAction, getAgencyProductsAction, addProductExtraAction, delProductExtrasAction } from '@/stores/Products/Index';
|
||||||
|
import { isEmpty, cloneDeep } from '@/utils/commons';
|
||||||
|
import SearchForm from '@/components/SearchForm';
|
||||||
|
|
||||||
|
import RequireAuth from '@/components/RequireAuth';
|
||||||
|
import { PERM_PRODUCTS_MANAGEMENT } from '@/config';
|
||||||
|
|
||||||
|
const NewAddonModal = ({ onPick, ...props }) => {
|
||||||
|
const { travel_agency_id, use_year } = useParams();
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const { notification, message } = App.useApp();
|
||||||
|
|
||||||
|
const [open, setOpen] = useState(false);
|
||||||
|
const [loading, setLoading] = useState(false); // bind loading
|
||||||
|
const [searchLoading, setSearchLoading] = useState(false);
|
||||||
|
const [searchResult, setSearchResult] = useState([]);
|
||||||
|
|
||||||
|
const onSearchProducts = async (values) => {
|
||||||
|
const copyObject = cloneDeep(values);
|
||||||
|
const { starttime, endtime, ...param } = copyObject;
|
||||||
|
setSearchLoading(true);
|
||||||
|
setSearchResult([]);
|
||||||
|
const result = await getAgencyProductsAction({ ...param, audit_state: '0', travel_agency_id, use_year });
|
||||||
|
setSearchResult(result?.products || []);
|
||||||
|
setSearchLoading(false);
|
||||||
|
};
|
||||||
|
const handleAddExtras = async (item) => {
|
||||||
|
// const success = await fetchBindOrder({ coli_sn, conversationid: currentConversationID });
|
||||||
|
// success ? message.success('绑定成功') : message.error('绑定失败');
|
||||||
|
// setOpen(false);
|
||||||
|
if (typeof onPick === 'function') {
|
||||||
|
onPick(item);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// todo:
|
||||||
|
const searchResultColumns = [
|
||||||
|
{ key: 'title', dataIndex: ['info', 'title'], width: '16rem', title: t('products:Title') },
|
||||||
|
{
|
||||||
|
title: t('products:price'),
|
||||||
|
dataIndex: ['quotation', '0', 'value'],
|
||||||
|
width: '10rem',
|
||||||
|
render: (_, { quotation }) => `${quotation[0].value} ${quotation[0].currency} / ${quotation[0].unit_name}`, // todo: 成人 儿童
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'action',
|
||||||
|
title: '',
|
||||||
|
width: 150,
|
||||||
|
render: (_, record) => (
|
||||||
|
<Button className='text-primary' onClick={() => handleAddExtras(record)}>
|
||||||
|
附加此项目
|
||||||
|
</Button>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const paginationProps = {
|
||||||
|
showTotal: (total) => t('Table.Total', { total }),
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Button type='primary' onClick={() => setOpen(true)} className='mt-2'>
|
||||||
|
{t('New')}
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Modal width={'95%'} style={{ top: 20 }} open={open} title={'添加附加'} footer={false} onCancel={() => setOpen(false)} destroyOnClose>
|
||||||
|
<SearchForm
|
||||||
|
fieldsConfig={{
|
||||||
|
shows: ['dates', 'year', 'keyword'],
|
||||||
|
fieldProps: {
|
||||||
|
dates: { label: t('products:CreateDate') },
|
||||||
|
keyword: { label: t('products:Title'), col: 4 },
|
||||||
|
},
|
||||||
|
// sort: { keyword: 100 },
|
||||||
|
}}
|
||||||
|
initialValue={
|
||||||
|
{
|
||||||
|
// dates: [dayjs().subtract(2, 'M').startOf('M'), dayjs().endOf('M')],
|
||||||
|
// year: dayjs().add(1, 'year'),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onSubmit={(err, formVal, filedsVal) => {
|
||||||
|
onSearchProducts(formVal);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Table
|
||||||
|
size={'small'}
|
||||||
|
key={'searchProductsTable'}
|
||||||
|
loading={searchLoading}
|
||||||
|
dataSource={searchResult}
|
||||||
|
columns={searchResultColumns}
|
||||||
|
pagination={searchResult.length <= 10 ? false : paginationProps}
|
||||||
|
/>
|
||||||
|
</Modal>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
const Extras = ({ productId, onChange, ...props }) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const { notification, message } = App.useApp();
|
||||||
|
|
||||||
|
const { travel_agency_id, use_year } = useParams();
|
||||||
|
|
||||||
|
const [extrasData, setExtrasData] = useState([]);
|
||||||
|
|
||||||
|
const handleGetAgencyProductExtras = async () => {
|
||||||
|
const data = await getAgencyProductExtrasAction({ id: productId, travel_agency_id, use_year });
|
||||||
|
setExtrasData(data);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleNewAddOn = async (item) => {
|
||||||
|
setExtrasData(prev => [].concat(prev, [item]));
|
||||||
|
// todo: 提交后端; 重复绑定同一个
|
||||||
|
const newSuccess = await addProductExtraAction({ travel_agency_id, id: productId, extras: [2] });
|
||||||
|
newSuccess ? message.success(t('Success')) : message.error(t('Failed'));
|
||||||
|
await handleGetAgencyProductExtras();
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDelAddon = async (item) => {
|
||||||
|
// todo: 提交后端
|
||||||
|
const delSuccess = await delProductExtrasAction({ travel_agency_id, id: productId, extras: [2] });
|
||||||
|
delSuccess ? message.success(t('Success')) : message.error(t('Failed'));
|
||||||
|
await handleGetAgencyProductExtras();
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
handleGetAgencyProductExtras();
|
||||||
|
|
||||||
|
return () => {};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
{ title: t('products:Title'), dataIndex: ['info', 'title'], width: '16rem', },
|
||||||
|
{
|
||||||
|
title: t('products:Offer'),
|
||||||
|
dataIndex: ['quotation', '0', 'value'],
|
||||||
|
width: '10rem',
|
||||||
|
|
||||||
|
render: (_, { quotation }) => `${quotation[0].value} ${quotation[0].currency} / ${quotation[0].unit_name}`, // todo: 成人 儿童
|
||||||
|
},
|
||||||
|
// { title: t('products:Types'), dataIndex: 'age_type', width: '40%', },
|
||||||
|
{
|
||||||
|
title: '',
|
||||||
|
dataIndex: 'operation',
|
||||||
|
width: '4rem',
|
||||||
|
render: (_, r) => (
|
||||||
|
<Popconfirm title={t('products:sureDelete')} onConfirm={(e) => handleDelAddon(r)} >
|
||||||
|
<Button size='small' type='link' danger>
|
||||||
|
{t('Delete')}
|
||||||
|
</Button>
|
||||||
|
</Popconfirm>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<RequireAuth subject={PERM_PRODUCTS_MANAGEMENT}>
|
||||||
|
<h2>{t('products:Components.Extras')}</h2>
|
||||||
|
<Table dataSource={extrasData} columns={columns} bordered pagination={false} rowKey={(r) => r.info.id} />
|
||||||
|
<NewAddonModal onPick={handleNewAddOn} />
|
||||||
|
</RequireAuth>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export default Extras;
|
Loading…
Reference in New Issue