perf: 产品管理: 导出按钮

main
Lei OT 1 month ago
parent 45aa339fc6
commit 4ba8751a77

@ -89,7 +89,7 @@ export const useProductsAuditStates = () => {
return types; return types;
}; };
export const useProductsAuditStatesMapVal = (value) => { export const useProductsAuditStatesMapVal = () => {
const stateSets = useProductsAuditStates(); const stateSets = useProductsAuditStates();
const stateMapVal = stateSets.reduce((r, c) => ({ ...r, [`${c.value}`]: c }), {}); const stateMapVal = stateSets.reduce((r, c) => ({ ...r, [`${c.value}`]: c }), {});
return stateMapVal; return stateMapVal;

@ -7,24 +7,18 @@ import { useTranslation } from "react-i18next";
import useProductsStore, { import useProductsStore, {
postAgencyProductsAuditAction, postAgencyProductsAuditAction,
postAgencyAuditAction, postAgencyAuditAction,
getAgencyAllExtrasAction,
} from "@/stores/Products/Index"; } from "@/stores/Products/Index";
import { isEmpty, objectMapper } from "@/utils/commons"; import { isEmpty, objectMapper } from "@/utils/commons";
import useAuthStore from "@/stores/Auth"; import useAuthStore from "@/stores/Auth";
import RequireAuth from "@/components/RequireAuth"; import RequireAuth from "@/components/RequireAuth";
// import PrintContractPDF from './PrintContractPDF';
import { PERM_PRODUCTS_OFFER_AUDIT, PERM_PRODUCTS_OFFER_PUT } from "@/config"; import { PERM_PRODUCTS_OFFER_AUDIT, PERM_PRODUCTS_OFFER_PUT } from "@/config";
import dayjs from "dayjs"; import dayjs from "dayjs";
import VendorSelector from "@/components/VendorSelector"; import VendorSelector from "@/components/VendorSelector";
import AuditStateSelector from "@/components/AuditStateSelector"; import AuditStateSelector from "@/components/AuditStateSelector";
import { usingStorage } from "@/hooks/usingStorage"; import { usingStorage } from "@/hooks/usingStorage";
import AgencyContract from "../Print/AgencyContract";
// import AgencyContract from "../Print/AgencyContract_v0903";
import { saveAs } from "file-saver";
import { Packer } from "docx";
import AgencyPreview from "../Print/AgencyPreview"; import AgencyPreview from "../Print/AgencyPreview";
import ExportDocxBtn from "../Print/ExportDocxBtn";
const Header = ({ refresh, ...props }) => { const Header = ({ refresh, ...props }) => {
const location = useLocation(); const location = useLocation();
@ -44,7 +38,6 @@ const Header = ({ refresh, ...props }) => {
state.setSwitchParams, state.setSwitchParams,
]); ]);
// const [activeAgencyState] = useProductsStore((state) => [state.activeAgencyState]); // const [activeAgencyState] = useProductsStore((state) => [state.activeAgencyState]);
const [agencyProducts] = useProductsStore((state) => [state.agencyProducts]);
const stateMapVal = useProductsAuditStatesMapVal(); const stateMapVal = useProductsAuditStatesMapVal();
const { message, notification } = App.useApp(); const { message, notification } = App.useApp();
const navigate = useNavigate(); const navigate = useNavigate();
@ -58,10 +51,6 @@ const Header = ({ refresh, ...props }) => {
yearOptions.push({ label: i, value: i }); yearOptions.push({ label: i, value: i });
} }
const { getRemarkList } = useProductsStore((selector) => ({
getRemarkList: selector.getRemarkList,
}));
const [param, setParam] = useState({ const [param, setParam] = useState({
pick_year: baseYear, pick_year: baseYear,
pick_agency: travel_agency_id, pick_agency: travel_agency_id,
@ -168,31 +157,6 @@ const Header = ({ refresh, ...props }) => {
}); });
}; };
const handleDownload = async () => {
// await refresh();
const agencyExtras = await getAgencyAllExtrasAction(switchParams);
const remarks = await getRemarkList()
const remarksMappedByType = remarks.reduce((r, v) => ({...r, [v.product_type_id]: v}), {});
const documentCreator = new AgencyContract();
const doc = documentCreator.create([
switchParams,
activeAgency,
agencyProducts,
agencyExtras,
// remarks,
remarksMappedByType,
]);
const _d = dayjs().format("YYYYMMDD_HH.mm.ss.SSS"); // Date.now().toString(32)
const _state = pickAuditState.value ? pickAuditState.label : '';
Packer.toBlob(doc).then((blob) => {
saveAs(
blob,
`${activeAgency.travel_agency_name}${pickYear}年地接合同-${_state}-${_d}.docx`
);
});
};
return ( return (
<div className="flex justify-end items-center gap-4 h-full"> <div className="flex justify-end items-center gap-4 h-full">
<div className="grow"> <div className="grow">
@ -241,14 +205,7 @@ const Header = ({ refresh, ...props }) => {
</h2> </h2>
</div> </div>
<AgencyPreview params={switchParams} /> <AgencyPreview params={switchParams} />
{/* <Button size="small" onClick={handlePreview}>{t('Preview')}</Button> */} <ExportDocxBtn params={switchParams} />
{/* todo: export, 审核完成之后才能导出 */}
<RequireAuth subject={PERM_PRODUCTS_OFFER_AUDIT}>
<Button size="small" onClick={handleDownload}>
{t("Export")} .docx
</Button>
{/* <PrintContractPDF /> */}
</RequireAuth>
{/* {activeAgencyState === 0 && ( */} {/* {activeAgencyState === 0 && ( */}
<> <>
<RequireAuth subject={PERM_PRODUCTS_OFFER_PUT}> <RequireAuth subject={PERM_PRODUCTS_OFFER_PUT}>

@ -1,18 +1,24 @@
import { useState } from 'react'; import { useState } from 'react';
import { useParams } from 'react-router-dom'; import { useParams, Link } from 'react-router-dom';
import { Button, Drawer, Card, Table } from 'antd'; import { Button, Drawer, Card, Table } from 'antd';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import useProductsStore, { getAgencyAllExtrasAction } from '@/stores/Products/Index'; import useProductsStore, { getAgencyAllExtrasAction } from '@/stores/Products/Index';
import { useProductsTypes, formatGroupSize } from '@/hooks/useProductsSets'; import { useProductsTypes, formatGroupSize } from '@/hooks/useProductsSets';
import { chunkBy, splitTable_6, splitTable_7, splitTable_8, splitTable_B, splitTable_D, splitTable_J, splitTable_Q, splitTable_R } from '@/hooks/useProductsQuotationFormat'; import { chunkBy, splitTable_6, splitTable_7, splitTable_8, splitTable_B, splitTable_D, splitTable_J, splitTable_Q, splitTable_R } from '@/hooks/useProductsQuotationFormat';
import { groupBy } from '@/utils/commons'; import { groupBy, isNotEmpty } from '@/utils/commons';
import useAuthStore from '@/stores/Auth';
import { PERM_PRODUCTS_MANAGEMENT, PERM_PRODUCTS_OFFER_AUDIT, PERM_PRODUCTS_OFFER_PUT } from '@/config';
import ExportDocxBtn from './ExportDocxBtn';
const AgencyPreview = ({ params, ...props }) => { const AgencyPreview = ({ params, ...props }) => {
const isPermitted = useAuthStore(state => state.isPermitted);
const { t } = useTranslation(); const { t } = useTranslation();
const { travel_agency_id, use_year } = params; const { travel_agency_id, use_year } = params;
const productsTypes = useProductsTypes(); const productsTypes = useProductsTypes();
const [agencyProducts] = useProductsStore((state) => [state.agencyProducts]); const [agencyProducts] = useProductsStore((state) => [state.agencyProducts]);
const [setEditingProduct] = useProductsStore((state) => [state.setEditingProduct]);
const [previewMode, setPreviewMode] = useState(false); const [previewMode, setPreviewMode] = useState(false);
const [tables, setTables] = useState([]); const [tables, setTables] = useState([]);
@ -52,6 +58,27 @@ const AgencyPreview = ({ params, ...props }) => {
const cityRowHighlights = (record) => (record.info.isCityRow ? 'font-bold text-center ' : '') const cityRowHighlights = (record) => (record.info.isCityRow ? 'font-bold text-center ' : '')
const renderTitle = (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}/all/edit`
: isPermitted(PERM_PRODUCTS_OFFER_PUT)
? `/products/edit`
: '';
return (
<div className=''>
{isNotEmpty(itemLink) && (r.info?.isCityRow !== true) ? (
<div className='' onClick={() => setEditingProduct({ info: r.info })}>
<Link to={itemLink}>{title}</Link>
</div>
) : (
title
)}
<b>{r.info.id}</b>
</div>
);
};
const renderTable_6 = () => { const renderTable_6 = () => {
// console.log('666666'); // console.log('666666');
if (!('6' in agencyProducts)) { if (!('6' in agencyProducts)) {
@ -525,19 +552,28 @@ const AgencyPreview = ({ params, ...props }) => {
<div className='divide-x-0 divide-y divide-solid divide-stone-200'> <div className='divide-x-0 divide-y divide-solid divide-stone-200'>
{(SS || []).length === 1 ? ( {(SS || []).length === 1 ? (
<div className='flex justify-between divide-x divide-y-0 divide-solid divide-stone-200'> <div className='flex justify-between divide-x divide-y-0 divide-solid divide-stone-200'>
<span className='flex-0 w-32 text-start'>{SS[0].unit_id === '0' ? '' : `${formatGroupSize(SS[0].group_size_min, SS[0].group_size_max, true)}, ${SS[0].unit_name}`}</span> {SS[0].unit_id === '0' && SS[0].group_size_min <= 1 && SS[0].group_size_max === 1000 ? (
<span className='flex-0 text-center w-32'></span>
) : (
<>
<span className='flex-0 w-16 text-start'>{formatGroupSize(SS[0].group_size_min, SS[0].group_size_max, true)}</span>
<span className='flex-0 w-16 text-center'>{SS[0].unit_name}</span>
</>
)}
<span className='flex-1 text-center'>{SS[0].adult_cost}</span> <span className='flex-1 text-center'>{SS[0].adult_cost}</span>
<span className='flex-1 text-center'>{SS[0].child_cost}</span> <span className='flex-1 text-center'>{SS[0].child_cost}</span>
</div> </div>
) : ( ) : (
(SS || []).map((ele, qi) => (SS || []).map((ele, qi) => (
<div key={qi} className=''> <div key={qi} className=''>
<div className='flex justify-between text-center divide-x divide-y-0 divide-solid divide-stone-200'> <div className='flex justify-between text-center divide-x divide-y-0 divide-solid divide-stone-200'>
<span className='flex-0 w-32 text-start'>{formatGroupSize(ele.group_size_min, ele.group_size_max, true)}, {ele.unit_name}</span> <span className='flex-0 w-16 text-start'>{formatGroupSize(ele.group_size_min, ele.group_size_max, true)}</span>
<span className='flex-1'>{ele.adult_cost}</span> <span className='flex-0 w-16'>{ele.unit_name}</span>
<span className='flex-1'>{ele.child_cost}</span> <span className='flex-1'>{ele.adult_cost}</span>
<span className='flex-1'>{ele.child_cost}</span>
</div>
</div> </div>
</div>) ))
)} )}
</div> </div>
), ),
@ -563,11 +599,12 @@ const AgencyPreview = ({ params, ...props }) => {
<div key={pi}> <div key={pi}>
<div className='flex justify-between divide-x divide-y-0 divide-solid divide-stone-200'> <div className='flex justify-between divide-x divide-y-0 divide-solid divide-stone-200'>
<div className='flex-0 text-center w-32'> <div className='flex-0 text-center w-32'>
{ele.rows.map((d, di) => ( {ele.rows.map((d, di) => (
<div key={di}> <div key={di}>
{d.use_dates_start.replace(`${use_year}.`, '')}~{d.use_dates_end.replace(`${use_year}.`, '')} {d.use_dates_start.replace(`${use_year}.`, '')}~{d.use_dates_end.replace(`${use_year}.`, '')}
</div> </div>
))}</div> ))}
</div>
<span className='flex-1 self-center'>{ele.adult_cost}</span> <span className='flex-1 self-center'>{ele.adult_cost}</span>
<span className='flex-1 self-center'>{ele.child_cost}</span> <span className='flex-1 self-center'>{ele.child_cost}</span>
</div> </div>
@ -576,10 +613,23 @@ const AgencyPreview = ({ params, ...props }) => {
</div> </div>
), ),
}, },
{ title: '特殊项目', width: '9rem', key: 'extras', render: (_, r) => { {
const _extras = extras[r.info.id] || []; title: '特殊项目',
return (<div>{_extras.map(e => <div key={e.info.id}>{e.info.product_title}{e.info.product_type_name}</div>)}</div>); width: '9rem',
}}, key: 'extras',
render: (_, r) => {
const _extras = extras[r.info.id] || [];
return (
<div>
{_extras.map((e) => (
<div key={e.info.id}>
{e.info.product_title}{e.info.product_type_name}
</div>
))}
</div>
);
},
},
]} ]}
/> />
</> </>
@ -762,10 +812,19 @@ const AgencyPreview = ({ params, ...props }) => {
<Button size='small' onClick={handlePreview}> <Button size='small' onClick={handlePreview}>
{t('Preview')} {t('Preview')}
</Button> </Button>
<Drawer title={`${t('Preview')}`} width={'70%'} open={previewMode} onClose={() => setPreviewMode(false)} > <Drawer
<div className='flex flex-col gap-2'> title={
{renderTableByType(tables)} <>
</div> <div className='flex gap-4'>
<span>{t('Preview')}</span>
<ExportDocxBtn params={params} />
</div>
</>
}
width={'70%'}
open={previewMode}
onClose={() => setPreviewMode(false)}>
<div className='flex flex-col gap-2'>{renderTableByType(tables)}</div>
</Drawer> </Drawer>
</> </>
); );

@ -0,0 +1,59 @@
import { Button } from 'antd';
import { useProductsAuditStatesMapVal } from '@/hooks/useProductsSets';
import { useTranslation } from 'react-i18next';
import useProductsStore, { getAgencyAllExtrasAction } from '@/stores/Products/Index';
import RequireAuth from '@/components/RequireAuth';
import { PERM_PRODUCTS_OFFER_AUDIT } from '@/config';
import dayjs from 'dayjs';
import AgencyContract from '../Print/AgencyContract';
import { saveAs } from 'file-saver';
import { Packer } from 'docx';
import { isEmpty } from '@/utils/commons';
const ExportDocxBtn = ({ params = { travel_agency_id: '', use_year: '', audit_state: '' }, ...props }) => {
const { t } = useTranslation();
const [agencyProducts] = useProductsStore((state) => [state.agencyProducts]);
const [activeAgency] = useProductsStore((state) => [state.activeAgency]);
const { travel_agency_id, use_year, audit_state } = params;
const auditStatesMap = useProductsAuditStatesMapVal();
const { getRemarkList } = useProductsStore((selector) => ({
getRemarkList: selector.getRemarkList,
}));
const handleDownload = async () => {
// await refresh();
const agencyExtras = await getAgencyAllExtrasAction(params);
const remarks = await getRemarkList();
const remarksMappedByType = remarks.reduce((r, v) => ({ ...r, [v.product_type_id]: v }), {});
const documentCreator = new AgencyContract();
const doc = documentCreator.create([
params,
activeAgency,
agencyProducts,
agencyExtras,
// remarks,
remarksMappedByType,
]);
const _d = dayjs().format('YYYYMMDD_HH.mm.ss.SSS'); // Date.now().toString(32)
// console.log(params);
const _state = isEmpty(audit_state) ? '' : auditStatesMap[audit_state].label;
Packer.toBlob(doc).then((blob) => {
saveAs(blob, `${activeAgency.travel_agency_name}${use_year}年地接合同-${_state}-${_d}.docx`);
});
};
return (
<>
{/* todo: export, 审核完成之后才能导出 */}
<RequireAuth subject={PERM_PRODUCTS_OFFER_AUDIT}>
<Button size='small' onClick={handleDownload}>
{t('Export')} .docx
</Button>
{/* <PrintContractPDF /> */}
</RequireAuth>
</>
);
};
export default ExportDocxBtn;
Loading…
Cancel
Save