diff --git a/src/client/models/GetDealProductsBarcodesPdfRequest.ts b/src/client/models/GetDealProductsBarcodesPdfRequest.ts new file mode 100644 index 0000000..9161eb1 --- /dev/null +++ b/src/client/models/GetDealProductsBarcodesPdfRequest.ts @@ -0,0 +1,3 @@ +export type GetDealProductsBarcodesPdfRequest = { + dealId: number; +}; diff --git a/src/client/models/GetDealProductsBarcodesPdfResponse.ts b/src/client/models/GetDealProductsBarcodesPdfResponse.ts new file mode 100644 index 0000000..ae7f80e --- /dev/null +++ b/src/client/models/GetDealProductsBarcodesPdfResponse.ts @@ -0,0 +1,5 @@ +export type GetDealProductsBarcodesPdfResponse = { + base64String: string; + filename: string; + mimeType: string; +}; \ No newline at end of file diff --git a/src/client/services/DealService.ts b/src/client/services/DealService.ts index 2665000..b6a4f71 100644 --- a/src/client/services/DealService.ts +++ b/src/client/services/DealService.ts @@ -47,6 +47,8 @@ import type { DealUpdateServiceQuantityRequest } from '../models/DealUpdateServi import type { DealUpdateServiceQuantityResponse } from '../models/DealUpdateServiceQuantityResponse'; import type { DealUpdateServiceRequest } from '../models/DealUpdateServiceRequest'; import type { DealUpdateServiceResponse } from '../models/DealUpdateServiceResponse'; +import type { GetDealProductsBarcodesPdfRequest } from '../models/GetDealProductsBarcodesPdfRequest.ts'; +import type { GetDealProductsBarcodesPdfResponse } from '../models/GetDealProductsBarcodesPdfResponse.ts'; import type { CancelablePromise } from '../core/CancelablePromise'; import { OpenAPI } from '../core/OpenAPI'; import { request as __request } from '../core/request'; @@ -586,4 +588,24 @@ export class DealService { }, }); } + /** + * Get Deal Products Barcodes Pdf + * @returns GetProductBarcodePdfResponse Successful Response + * @throws ApiError + */ + public static getDealProductsBarcodesPdf({ + requestBody, + }: { + requestBody: GetDealProductsBarcodesPdfRequest, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'POST', + url: '/deal/barcodes/get-pdf', + body: requestBody, + mediaType: 'application/json', + errors: { + 422: `Validation Error`, + }, + }); + } } diff --git a/src/pages/DealsPage/components/DealsTable/DealsTable.tsx b/src/pages/DealsPage/components/DealsTable/DealsTable.tsx index 066c7cc..df1d22a 100644 --- a/src/pages/DealsPage/components/DealsTable/DealsTable.tsx +++ b/src/pages/DealsPage/components/DealsTable/DealsTable.tsx @@ -13,7 +13,7 @@ type RestProps = { }; type Props = CRUDTableProps & RestProps; -const DealsTable: FC = ({ items, viewOnly = false }) => { +const DealsTable: FC = ({ items, onSelectionChange, viewOnly = false }) => { const columns = useDealsTableColumns(); const { setSelectedDeal } = useDealPageContext(); const onEditClick = (dealSummary: DealSummary) => { @@ -21,10 +21,12 @@ const DealsTable: FC = ({ items, viewOnly = false }) => { setSelectedDeal(deal); }); }; + return ( = ({ items, viewOnly = false }) => { enableBottomToolbar: !viewOnly, paginationDisplayMode: "pages", enableRowActions: true, + enableRowSelection: true, renderRowActions: ({ row }) => ( diff --git a/src/pages/LeadsPage/ui/LeadsPage.module.css b/src/pages/LeadsPage/ui/LeadsPage.module.css index 32b82f6..42cedae 100644 --- a/src/pages/LeadsPage/ui/LeadsPage.module.css +++ b/src/pages/LeadsPage/ui/LeadsPage.module.css @@ -5,9 +5,6 @@ height: 100%; } -.search-input { -} - .boards { margin-top: 1rem; flex: 1; @@ -41,3 +38,7 @@ gap: rem(10); display: flex; } + +.print-deals-button { + align-self: center; +} diff --git a/src/pages/LeadsPage/ui/LeadsPage.tsx b/src/pages/LeadsPage/ui/LeadsPage.tsx index b9e1c83..6a71fda 100644 --- a/src/pages/LeadsPage/ui/LeadsPage.tsx +++ b/src/pages/LeadsPage/ui/LeadsPage.tsx @@ -3,25 +3,23 @@ import styles from "./LeadsPage.module.css"; import Board from "../../../components/Dnd/Board/Board.tsx"; import { DragDropContext, Droppable, DropResult } from "@hello-pangea/dnd"; import { useDealSummaries } from "../hooks/useDealSummaries.tsx"; -import { - DealStatus, - getDealStatusByName, -} from "../../../shared/enums/DealStatus.ts"; +import { DealStatus, getDealStatusByName } from "../../../shared/enums/DealStatus.ts"; import PageBlock from "../../../components/PageBlock/PageBlock.tsx"; import DealEditDrawer from "../drawers/DealEditDrawer/DealEditDrawer.tsx"; import { DealPageContextProvider } from "../contexts/DealPageContext.tsx"; import { modals } from "@mantine/modals"; -import { DealService, DealSummaryReorderRequest } from "../../../client"; -import { ActionIcon, Flex, NumberInput, rem, Text } from "@mantine/core"; +import { DealService, DealSummary, DealSummaryReorderRequest } from "../../../client"; +import { ActionIcon, Flex, NumberInput, rem, Text, Tooltip } from "@mantine/core"; import classNames from "classnames"; import { notifications } from "../../../shared/lib/notifications.ts"; -import { IconMenu2, IconMenuDeep } from "@tabler/icons-react"; +import { IconBarcode, IconMenu2, IconMenuDeep } from "@tabler/icons-react"; import useDealsPageState from "../../DealsPage/hooks/useDealsPageState.tsx"; import DealStatusSelect from "../../DealsPage/components/DealStatusSelect/DealStatusSelect.tsx"; import BaseMarketplaceSelect from "../../../components/Selects/BaseMarketplaceSelect/BaseMarketplaceSelect.tsx"; import ClientSelectNew from "../../../components/Selects/ClientSelectNew/ClientSelectNew.tsx"; import DealsTable from "../../DealsPage/components/DealsTable/DealsTable.tsx"; import { motion } from "framer-motion"; +import { base64ToBlob } from "../../../shared/lib/utils.ts"; enum DisplayMode { BOARD, @@ -37,6 +35,9 @@ export const LeadsPage: FC = () => { DisplayMode.BOARD ); const [isDragEnded, setIsDragEnded] = useState(true); + + const [selectedDeals, setSelectedDeals] = useState([]); + useEffect(() => { setSummaries(summariesRaw); }, [summariesRaw]); @@ -151,7 +152,7 @@ export const LeadsPage: FC = () => { initial={{ opacity: 0 }} animate={{ opacity: 1 }} transition={{ duration: 0.2 }}> - + ); }; @@ -182,7 +183,7 @@ export const LeadsPage: FC = () => { summaries={summaries.filter( summary => summary.status == - DealStatus.AWAITING_ACCEPTANCE + DealStatus.AWAITING_ACCEPTANCE, )} title={"Ожидает приемки"} droppableId={"AWAITING_ACCEPTANCE"} @@ -191,7 +192,7 @@ export const LeadsPage: FC = () => { - summary.status == DealStatus.PACKAGING + summary.status == DealStatus.PACKAGING, )} title={"Упаковка"} droppableId={"PACKAGING"} @@ -201,7 +202,7 @@ export const LeadsPage: FC = () => { summaries={summaries.filter( summary => summary.status == - DealStatus.AWAITING_SHIPMENT + DealStatus.AWAITING_SHIPMENT, )} title={"Ожидает отгрузки"} droppableId={"AWAITING_SHIPMENT"} @@ -211,7 +212,7 @@ export const LeadsPage: FC = () => { summaries={summaries.filter( summary => summary.status == - DealStatus.AWAITING_PAYMENT + DealStatus.AWAITING_PAYMENT, )} title={"Ожидает оплаты"} droppableId={"AWAITING_PAYMENT"} @@ -220,7 +221,7 @@ export const LeadsPage: FC = () => { - summary.status == DealStatus.COMPLETED + summary.status == DealStatus.COMPLETED, )} title={"Завершена"} droppableId={"COMPLETED"} @@ -233,7 +234,7 @@ export const LeadsPage: FC = () => {
{(provided, snapshot) => ( @@ -254,7 +255,7 @@ export const LeadsPage: FC = () => {
{(provided, snapshot) => ( @@ -345,11 +346,44 @@ export const LeadsPage: FC = () => { ? "flex" : "none", }}> + { + selectedDeals.length === 1 && + + { + const response = + await DealService.getDealProductsBarcodesPdf({ + requestBody: { + dealId: selectedDeals[0].id, + }, + }); + const pdfBlob = base64ToBlob( + response.base64String, + response.mimeType, + ); + const pdfUrl = URL.createObjectURL(pdfBlob); + const pdfWindow = window.open(pdfUrl); + if (!pdfWindow) { + notifications.error({ message: "Ошибка" }); + return; + } + pdfWindow.onload = () => { + pdfWindow.print(); + }; + }} + variant={"default"}> + + + + }