feat: print all barcodes for selected deal
This commit is contained in:
3
src/client/models/GetDealProductsBarcodesPdfRequest.ts
Normal file
3
src/client/models/GetDealProductsBarcodesPdfRequest.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export type GetDealProductsBarcodesPdfRequest = {
|
||||||
|
dealId: number;
|
||||||
|
};
|
||||||
5
src/client/models/GetDealProductsBarcodesPdfResponse.ts
Normal file
5
src/client/models/GetDealProductsBarcodesPdfResponse.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export type GetDealProductsBarcodesPdfResponse = {
|
||||||
|
base64String: string;
|
||||||
|
filename: string;
|
||||||
|
mimeType: string;
|
||||||
|
};
|
||||||
@@ -47,6 +47,8 @@ import type { DealUpdateServiceQuantityRequest } from '../models/DealUpdateServi
|
|||||||
import type { DealUpdateServiceQuantityResponse } from '../models/DealUpdateServiceQuantityResponse';
|
import type { DealUpdateServiceQuantityResponse } from '../models/DealUpdateServiceQuantityResponse';
|
||||||
import type { DealUpdateServiceRequest } from '../models/DealUpdateServiceRequest';
|
import type { DealUpdateServiceRequest } from '../models/DealUpdateServiceRequest';
|
||||||
import type { DealUpdateServiceResponse } from '../models/DealUpdateServiceResponse';
|
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 type { CancelablePromise } from '../core/CancelablePromise';
|
||||||
import { OpenAPI } from '../core/OpenAPI';
|
import { OpenAPI } from '../core/OpenAPI';
|
||||||
import { request as __request } from '../core/request';
|
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<GetDealProductsBarcodesPdfResponse> {
|
||||||
|
return __request(OpenAPI, {
|
||||||
|
method: 'POST',
|
||||||
|
url: '/deal/barcodes/get-pdf',
|
||||||
|
body: requestBody,
|
||||||
|
mediaType: 'application/json',
|
||||||
|
errors: {
|
||||||
|
422: `Validation Error`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ type RestProps = {
|
|||||||
};
|
};
|
||||||
type Props = CRUDTableProps<DealSummary> & RestProps;
|
type Props = CRUDTableProps<DealSummary> & RestProps;
|
||||||
|
|
||||||
const DealsTable: FC<Props> = ({ items, viewOnly = false }) => {
|
const DealsTable: FC<Props> = ({ items, onSelectionChange, viewOnly = false }) => {
|
||||||
const columns = useDealsTableColumns();
|
const columns = useDealsTableColumns();
|
||||||
const { setSelectedDeal } = useDealPageContext();
|
const { setSelectedDeal } = useDealPageContext();
|
||||||
const onEditClick = (dealSummary: DealSummary) => {
|
const onEditClick = (dealSummary: DealSummary) => {
|
||||||
@@ -21,10 +21,12 @@ const DealsTable: FC<Props> = ({ items, viewOnly = false }) => {
|
|||||||
setSelectedDeal(deal);
|
setSelectedDeal(deal);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BaseTable
|
<BaseTable
|
||||||
data={items}
|
data={items}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
|
onSelectionChange={onSelectionChange}
|
||||||
restProps={
|
restProps={
|
||||||
{
|
{
|
||||||
enableSorting: true,
|
enableSorting: true,
|
||||||
@@ -33,6 +35,7 @@ const DealsTable: FC<Props> = ({ items, viewOnly = false }) => {
|
|||||||
enableBottomToolbar: !viewOnly,
|
enableBottomToolbar: !viewOnly,
|
||||||
paginationDisplayMode: "pages",
|
paginationDisplayMode: "pages",
|
||||||
enableRowActions: true,
|
enableRowActions: true,
|
||||||
|
enableRowSelection: true,
|
||||||
renderRowActions: ({ row }) => (
|
renderRowActions: ({ row }) => (
|
||||||
<Flex gap="md">
|
<Flex gap="md">
|
||||||
<Tooltip label="Редактировать">
|
<Tooltip label="Редактировать">
|
||||||
|
|||||||
@@ -5,9 +5,6 @@
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.search-input {
|
|
||||||
}
|
|
||||||
|
|
||||||
.boards {
|
.boards {
|
||||||
margin-top: 1rem;
|
margin-top: 1rem;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
@@ -41,3 +38,7 @@
|
|||||||
gap: rem(10);
|
gap: rem(10);
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.print-deals-button {
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,25 +3,23 @@ import styles from "./LeadsPage.module.css";
|
|||||||
import Board from "../../../components/Dnd/Board/Board.tsx";
|
import Board from "../../../components/Dnd/Board/Board.tsx";
|
||||||
import { DragDropContext, Droppable, DropResult } from "@hello-pangea/dnd";
|
import { DragDropContext, Droppable, DropResult } from "@hello-pangea/dnd";
|
||||||
import { useDealSummaries } from "../hooks/useDealSummaries.tsx";
|
import { useDealSummaries } from "../hooks/useDealSummaries.tsx";
|
||||||
import {
|
import { DealStatus, getDealStatusByName } from "../../../shared/enums/DealStatus.ts";
|
||||||
DealStatus,
|
|
||||||
getDealStatusByName,
|
|
||||||
} from "../../../shared/enums/DealStatus.ts";
|
|
||||||
import PageBlock from "../../../components/PageBlock/PageBlock.tsx";
|
import PageBlock from "../../../components/PageBlock/PageBlock.tsx";
|
||||||
import DealEditDrawer from "../drawers/DealEditDrawer/DealEditDrawer.tsx";
|
import DealEditDrawer from "../drawers/DealEditDrawer/DealEditDrawer.tsx";
|
||||||
import { DealPageContextProvider } from "../contexts/DealPageContext.tsx";
|
import { DealPageContextProvider } from "../contexts/DealPageContext.tsx";
|
||||||
import { modals } from "@mantine/modals";
|
import { modals } from "@mantine/modals";
|
||||||
import { DealService, DealSummaryReorderRequest } from "../../../client";
|
import { DealService, DealSummary, DealSummaryReorderRequest } from "../../../client";
|
||||||
import { ActionIcon, Flex, NumberInput, rem, Text } from "@mantine/core";
|
import { ActionIcon, Flex, NumberInput, rem, Text, Tooltip } from "@mantine/core";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import { notifications } from "../../../shared/lib/notifications.ts";
|
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 useDealsPageState from "../../DealsPage/hooks/useDealsPageState.tsx";
|
||||||
import DealStatusSelect from "../../DealsPage/components/DealStatusSelect/DealStatusSelect.tsx";
|
import DealStatusSelect from "../../DealsPage/components/DealStatusSelect/DealStatusSelect.tsx";
|
||||||
import BaseMarketplaceSelect from "../../../components/Selects/BaseMarketplaceSelect/BaseMarketplaceSelect.tsx";
|
import BaseMarketplaceSelect from "../../../components/Selects/BaseMarketplaceSelect/BaseMarketplaceSelect.tsx";
|
||||||
import ClientSelectNew from "../../../components/Selects/ClientSelectNew/ClientSelectNew.tsx";
|
import ClientSelectNew from "../../../components/Selects/ClientSelectNew/ClientSelectNew.tsx";
|
||||||
import DealsTable from "../../DealsPage/components/DealsTable/DealsTable.tsx";
|
import DealsTable from "../../DealsPage/components/DealsTable/DealsTable.tsx";
|
||||||
import { motion } from "framer-motion";
|
import { motion } from "framer-motion";
|
||||||
|
import { base64ToBlob } from "../../../shared/lib/utils.ts";
|
||||||
|
|
||||||
enum DisplayMode {
|
enum DisplayMode {
|
||||||
BOARD,
|
BOARD,
|
||||||
@@ -37,6 +35,9 @@ export const LeadsPage: FC = () => {
|
|||||||
DisplayMode.BOARD
|
DisplayMode.BOARD
|
||||||
);
|
);
|
||||||
const [isDragEnded, setIsDragEnded] = useState(true);
|
const [isDragEnded, setIsDragEnded] = useState(true);
|
||||||
|
|
||||||
|
const [selectedDeals, setSelectedDeals] = useState<DealSummary[]>([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setSummaries(summariesRaw);
|
setSummaries(summariesRaw);
|
||||||
}, [summariesRaw]);
|
}, [summariesRaw]);
|
||||||
@@ -151,7 +152,7 @@ export const LeadsPage: FC = () => {
|
|||||||
initial={{ opacity: 0 }}
|
initial={{ opacity: 0 }}
|
||||||
animate={{ opacity: 1 }}
|
animate={{ opacity: 1 }}
|
||||||
transition={{ duration: 0.2 }}>
|
transition={{ duration: 0.2 }}>
|
||||||
<DealsTable items={data} />
|
<DealsTable items={data} onSelectionChange={setSelectedDeals} />
|
||||||
</motion.div>
|
</motion.div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -182,7 +183,7 @@ export const LeadsPage: FC = () => {
|
|||||||
summaries={summaries.filter(
|
summaries={summaries.filter(
|
||||||
summary =>
|
summary =>
|
||||||
summary.status ==
|
summary.status ==
|
||||||
DealStatus.AWAITING_ACCEPTANCE
|
DealStatus.AWAITING_ACCEPTANCE,
|
||||||
)}
|
)}
|
||||||
title={"Ожидает приемки"}
|
title={"Ожидает приемки"}
|
||||||
droppableId={"AWAITING_ACCEPTANCE"}
|
droppableId={"AWAITING_ACCEPTANCE"}
|
||||||
@@ -191,7 +192,7 @@ export const LeadsPage: FC = () => {
|
|||||||
<Board
|
<Board
|
||||||
summaries={summaries.filter(
|
summaries={summaries.filter(
|
||||||
summary =>
|
summary =>
|
||||||
summary.status == DealStatus.PACKAGING
|
summary.status == DealStatus.PACKAGING,
|
||||||
)}
|
)}
|
||||||
title={"Упаковка"}
|
title={"Упаковка"}
|
||||||
droppableId={"PACKAGING"}
|
droppableId={"PACKAGING"}
|
||||||
@@ -201,7 +202,7 @@ export const LeadsPage: FC = () => {
|
|||||||
summaries={summaries.filter(
|
summaries={summaries.filter(
|
||||||
summary =>
|
summary =>
|
||||||
summary.status ==
|
summary.status ==
|
||||||
DealStatus.AWAITING_SHIPMENT
|
DealStatus.AWAITING_SHIPMENT,
|
||||||
)}
|
)}
|
||||||
title={"Ожидает отгрузки"}
|
title={"Ожидает отгрузки"}
|
||||||
droppableId={"AWAITING_SHIPMENT"}
|
droppableId={"AWAITING_SHIPMENT"}
|
||||||
@@ -211,7 +212,7 @@ export const LeadsPage: FC = () => {
|
|||||||
summaries={summaries.filter(
|
summaries={summaries.filter(
|
||||||
summary =>
|
summary =>
|
||||||
summary.status ==
|
summary.status ==
|
||||||
DealStatus.AWAITING_PAYMENT
|
DealStatus.AWAITING_PAYMENT,
|
||||||
)}
|
)}
|
||||||
title={"Ожидает оплаты"}
|
title={"Ожидает оплаты"}
|
||||||
droppableId={"AWAITING_PAYMENT"}
|
droppableId={"AWAITING_PAYMENT"}
|
||||||
@@ -220,7 +221,7 @@ export const LeadsPage: FC = () => {
|
|||||||
<Board
|
<Board
|
||||||
summaries={summaries.filter(
|
summaries={summaries.filter(
|
||||||
summary =>
|
summary =>
|
||||||
summary.status == DealStatus.COMPLETED
|
summary.status == DealStatus.COMPLETED,
|
||||||
)}
|
)}
|
||||||
title={"Завершена"}
|
title={"Завершена"}
|
||||||
droppableId={"COMPLETED"}
|
droppableId={"COMPLETED"}
|
||||||
@@ -233,7 +234,7 @@ export const LeadsPage: FC = () => {
|
|||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
styles["delete"],
|
styles["delete"],
|
||||||
isDragEnded && styles["delete-hidden"]
|
isDragEnded && styles["delete-hidden"],
|
||||||
)}>
|
)}>
|
||||||
<Droppable droppableId={"DELETE"}>
|
<Droppable droppableId={"DELETE"}>
|
||||||
{(provided, snapshot) => (
|
{(provided, snapshot) => (
|
||||||
@@ -254,7 +255,7 @@ export const LeadsPage: FC = () => {
|
|||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
styles["delete"],
|
styles["delete"],
|
||||||
isDragEnded && styles["delete-hidden"]
|
isDragEnded && styles["delete-hidden"],
|
||||||
)}>
|
)}>
|
||||||
<Droppable droppableId={"SUCCESS"}>
|
<Droppable droppableId={"SUCCESS"}>
|
||||||
{(provided, snapshot) => (
|
{(provided, snapshot) => (
|
||||||
@@ -345,11 +346,44 @@ export const LeadsPage: FC = () => {
|
|||||||
? "flex"
|
? "flex"
|
||||||
: "none",
|
: "none",
|
||||||
}}>
|
}}>
|
||||||
|
{
|
||||||
|
selectedDeals.length === 1 &&
|
||||||
|
<Tooltip
|
||||||
|
className={styles["print-deals-button"]}
|
||||||
|
label={"Распечатать штрихкоды сделки"}
|
||||||
|
>
|
||||||
|
<ActionIcon
|
||||||
|
onClick={async () => {
|
||||||
|
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"}>
|
||||||
|
<IconBarcode />
|
||||||
|
</ActionIcon>
|
||||||
|
</Tooltip>
|
||||||
|
}
|
||||||
<NumberInput
|
<NumberInput
|
||||||
min={1}
|
min={1}
|
||||||
step={1}
|
|
||||||
placeholder={"Введите номер"}
|
placeholder={"Введите номер"}
|
||||||
{...form.getInputProps("id")}
|
{...form.getInputProps("id")}
|
||||||
|
hideControls
|
||||||
/>
|
/>
|
||||||
<DealStatusSelect
|
<DealStatusSelect
|
||||||
onClear={() =>
|
onClear={() =>
|
||||||
|
|||||||
Reference in New Issue
Block a user