diff --git a/src/client/index.ts b/src/client/index.ts index 2e9397c..dd66a79 100644 --- a/src/client/index.ts +++ b/src/client/index.ts @@ -9,6 +9,8 @@ export type { OpenAPIConfig } from './core/OpenAPI'; export type { AuthLoginRequest } from './models/AuthLoginRequest'; export type { AuthLoginResponse } from './models/AuthLoginResponse'; +export type { BarcodeAttributeSchema } from './models/BarcodeAttributeSchema'; +export type { BarcodeSchema } from './models/BarcodeSchema'; export type { BarcodeTemplateAdditionalAttributeSchema } from './models/BarcodeTemplateAdditionalAttributeSchema'; export type { BarcodeTemplateAttributeSchema } from './models/BarcodeTemplateAttributeSchema'; export type { BarcodeTemplateCreateRequest } from './models/BarcodeTemplateCreateRequest'; @@ -16,6 +18,7 @@ export type { BarcodeTemplateCreateResponse } from './models/BarcodeTemplateCrea export type { BarcodeTemplateDeleteRequest } from './models/BarcodeTemplateDeleteRequest'; export type { BarcodeTemplateDeleteResponse } from './models/BarcodeTemplateDeleteResponse'; export type { BarcodeTemplateSchema } from './models/BarcodeTemplateSchema'; +export type { BarcodeTemplateSizeSchema } from './models/BarcodeTemplateSizeSchema'; export type { BarcodeTemplateUpdateRequest } from './models/BarcodeTemplateUpdateRequest'; export type { BarcodeTemplateUpdateResponse } from './models/BarcodeTemplateUpdateResponse'; export type { ClientCreateRequest } from './models/ClientCreateRequest'; @@ -67,9 +70,12 @@ export type { DealUpdateProductQuantityResponse } from './models/DealUpdateProdu export type { DealUpdateServiceQuantityRequest } from './models/DealUpdateServiceQuantityRequest'; export type { DealUpdateServiceQuantityResponse } from './models/DealUpdateServiceQuantityResponse'; export type { GetAllBarcodeTemplateAttributesResponse } from './models/GetAllBarcodeTemplateAttributesResponse'; +export type { GetAllBarcodeTemplateSizesResponse } from './models/GetAllBarcodeTemplateSizesResponse'; export type { GetAllBarcodeTemplatesResponse } from './models/GetAllBarcodeTemplatesResponse'; export type { GetBarcodeTemplateByIdRequest } from './models/GetBarcodeTemplateByIdRequest'; export type { GetBarcodeTemplateByIdResponse } from './models/GetBarcodeTemplateByIdResponse'; +export type { GetProductBarcodeRequest } from './models/GetProductBarcodeRequest'; +export type { GetProductBarcodeResponse } from './models/GetProductBarcodeResponse'; export type { HTTPValidationError } from './models/HTTPValidationError'; export type { PaginationInfoSchema } from './models/PaginationInfoSchema'; export type { ProductAddBarcodeRequest } from './models/ProductAddBarcodeRequest'; diff --git a/src/client/models/BarcodeAttributeSchema.ts b/src/client/models/BarcodeAttributeSchema.ts new file mode 100644 index 0000000..2ed5397 --- /dev/null +++ b/src/client/models/BarcodeAttributeSchema.ts @@ -0,0 +1,9 @@ +/* generated using openapi-typescript-codegen -- do no edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export type BarcodeAttributeSchema = { + name: string; + value: string; +}; + diff --git a/src/client/models/BarcodeSchema.ts b/src/client/models/BarcodeSchema.ts new file mode 100644 index 0000000..680730c --- /dev/null +++ b/src/client/models/BarcodeSchema.ts @@ -0,0 +1,10 @@ +/* generated using openapi-typescript-codegen -- do no edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +import type { BarcodeAttributeSchema } from './BarcodeAttributeSchema'; +export type BarcodeSchema = { + barcode: string; + attributes: Array; +}; + diff --git a/src/client/models/BarcodeTemplateCreateRequest.ts b/src/client/models/BarcodeTemplateCreateRequest.ts index 94c3cfb..f657204 100644 --- a/src/client/models/BarcodeTemplateCreateRequest.ts +++ b/src/client/models/BarcodeTemplateCreateRequest.ts @@ -3,11 +3,11 @@ /* tslint:disable */ /* eslint-disable */ import type { BarcodeTemplateAdditionalAttributeSchema } from './BarcodeTemplateAdditionalAttributeSchema'; +import type { BarcodeTemplateSizeSchema } from './BarcodeTemplateSizeSchema'; export type BarcodeTemplateCreateRequest = { name: string; isDefault: boolean; - width: number; - height: number; + size: BarcodeTemplateSizeSchema; additionalAttributes: Array; attributeIds: Array; }; diff --git a/src/client/models/BarcodeTemplateSchema.ts b/src/client/models/BarcodeTemplateSchema.ts index 53cf1cb..4585b28 100644 --- a/src/client/models/BarcodeTemplateSchema.ts +++ b/src/client/models/BarcodeTemplateSchema.ts @@ -4,11 +4,11 @@ /* eslint-disable */ import type { BarcodeTemplateAdditionalAttributeSchema } from './BarcodeTemplateAdditionalAttributeSchema'; import type { BarcodeTemplateAttributeSchema } from './BarcodeTemplateAttributeSchema'; +import type { BarcodeTemplateSizeSchema } from './BarcodeTemplateSizeSchema'; export type BarcodeTemplateSchema = { name: string; isDefault: boolean; - width: number; - height: number; + size: BarcodeTemplateSizeSchema; additionalAttributes: Array; id: number; attributes: Array; diff --git a/src/client/models/BarcodeTemplateSizeSchema.ts b/src/client/models/BarcodeTemplateSizeSchema.ts new file mode 100644 index 0000000..25c4cd4 --- /dev/null +++ b/src/client/models/BarcodeTemplateSizeSchema.ts @@ -0,0 +1,12 @@ +/* generated using openapi-typescript-codegen -- do no edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export type BarcodeTemplateSizeSchema = { + id: number; + name: string; + key: string; + width: number; + height: number; +}; + diff --git a/src/client/models/BarcodeTemplateUpdateRequest.ts b/src/client/models/BarcodeTemplateUpdateRequest.ts index 8392aa3..b48d70d 100644 --- a/src/client/models/BarcodeTemplateUpdateRequest.ts +++ b/src/client/models/BarcodeTemplateUpdateRequest.ts @@ -3,11 +3,11 @@ /* tslint:disable */ /* eslint-disable */ import type { BarcodeTemplateAdditionalAttributeSchema } from './BarcodeTemplateAdditionalAttributeSchema'; +import type { BarcodeTemplateSizeSchema } from './BarcodeTemplateSizeSchema'; export type BarcodeTemplateUpdateRequest = { name: string; isDefault: boolean; - width: number; - height: number; + size: BarcodeTemplateSizeSchema; additionalAttributes: Array; id: number; attributeIds: Array; diff --git a/src/client/models/GetAllBarcodeTemplateSizesResponse.ts b/src/client/models/GetAllBarcodeTemplateSizesResponse.ts new file mode 100644 index 0000000..b194f43 --- /dev/null +++ b/src/client/models/GetAllBarcodeTemplateSizesResponse.ts @@ -0,0 +1,9 @@ +/* generated using openapi-typescript-codegen -- do no edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +import type { BarcodeTemplateSizeSchema } from './BarcodeTemplateSizeSchema'; +export type GetAllBarcodeTemplateSizesResponse = { + sizes: Array; +}; + diff --git a/src/client/models/GetProductBarcodeRequest.ts b/src/client/models/GetProductBarcodeRequest.ts new file mode 100644 index 0000000..ce822ea --- /dev/null +++ b/src/client/models/GetProductBarcodeRequest.ts @@ -0,0 +1,10 @@ +/* generated using openapi-typescript-codegen -- do no edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export type GetProductBarcodeRequest = { + productId: number; + barcode: string; + barcodeTemplateId?: (number | null); +}; + diff --git a/src/client/models/GetProductBarcodeResponse.ts b/src/client/models/GetProductBarcodeResponse.ts new file mode 100644 index 0000000..7bac3df --- /dev/null +++ b/src/client/models/GetProductBarcodeResponse.ts @@ -0,0 +1,9 @@ +/* generated using openapi-typescript-codegen -- do no edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +import type { BarcodeSchema } from './BarcodeSchema'; +export type GetProductBarcodeResponse = { + barcode: BarcodeSchema; +}; + diff --git a/src/client/services/BarcodeService.ts b/src/client/services/BarcodeService.ts index ba0c3c1..8d3fc30 100644 --- a/src/client/services/BarcodeService.ts +++ b/src/client/services/BarcodeService.ts @@ -11,6 +11,7 @@ import type { BarcodeTemplateUpdateResponse } from '../models/BarcodeTemplateUpd import type { CreateBarcodeTemplateAttributeRequest } from '../models/CreateBarcodeTemplateAttributeRequest'; import type { CreateBarcodeTemplateAttributeResponse } from '../models/CreateBarcodeTemplateAttributeResponse'; import type { GetAllBarcodeTemplateAttributesResponse } from '../models/GetAllBarcodeTemplateAttributesResponse'; +import type { GetAllBarcodeTemplateSizesResponse } from '../models/GetAllBarcodeTemplateSizesResponse'; import type { GetAllBarcodeTemplatesResponse } from '../models/GetAllBarcodeTemplatesResponse'; import type { GetBarcodeTemplateByIdRequest } from '../models/GetBarcodeTemplateByIdRequest'; import type { GetBarcodeTemplateByIdResponse } from '../models/GetBarcodeTemplateByIdResponse'; @@ -140,4 +141,15 @@ export class BarcodeService { }, }); } + /** + * Get All Barcode Template Sizes + * @returns GetAllBarcodeTemplateSizesResponse Successful Response + * @throws ApiError + */ + public static getAllBarcodeTemplateSizes(): CancelablePromise { + return __request(OpenAPI, { + method: 'GET', + url: '/barcode/template/size/get-all', + }); + } } diff --git a/src/client/services/ProductService.ts b/src/client/services/ProductService.ts index feb466e..138c405 100644 --- a/src/client/services/ProductService.ts +++ b/src/client/services/ProductService.ts @@ -2,6 +2,8 @@ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ +import type { GetProductBarcodeRequest } from '../models/GetProductBarcodeRequest'; +import type { GetProductBarcodeResponse } from '../models/GetProductBarcodeResponse'; import type { ProductAddBarcodeRequest } from '../models/ProductAddBarcodeRequest'; import type { ProductAddBarcodeResponse } from '../models/ProductAddBarcodeResponse'; import type { ProductCreateRequest } from '../models/ProductCreateRequest'; @@ -191,4 +193,24 @@ export class ProductService { }, }); } + /** + * Get Product Barcode + * @returns GetProductBarcodeResponse Successful Response + * @throws ApiError + */ + public static getProductBarcode({ + requestBody, + }: { + requestBody: GetProductBarcodeRequest, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'POST', + url: '/product/barcode/get', + body: requestBody, + mediaType: 'application/json', + errors: { + 422: `Validation Error`, + }, + }); + } } diff --git a/src/modals/PrintBarcodeModal/PrintBarcodeContainer.tsx b/src/modals/PrintBarcodeModal/PrintBarcodeContainer.tsx new file mode 100644 index 0000000..40d4945 --- /dev/null +++ b/src/modals/PrintBarcodeModal/PrintBarcodeContainer.tsx @@ -0,0 +1,63 @@ +import {BarcodeAttributeSchema} from "../../client"; +import {forwardRef} from "react"; +import styles from "./PrintBarcodeModal.module.css"; +import {Flex, Text} from "@mantine/core"; +import Barcode from "react-barcode"; + +type Props = { + attributes: BarcodeAttributeSchema[] + barcode?: string; + quantity: number; +} +type Ref = HTMLDivElement; +const PrintBarcodeContainer = forwardRef(function PrintBarcodeContainer(props: Props, ref) { + const {attributes, barcode, quantity} = props; + + const MAX_ATTRIBUTES = 6; + const MIN_BARCODE_SIZE = 30; + const MAX_BARCODE_SIZE = 100; + const STEP = (MAX_BARCODE_SIZE - MIN_BARCODE_SIZE) / MAX_ATTRIBUTES; + const MAX_ATTRIBUTE_LENGTH = 35; + + const getBarcodeHeight = () => { + return MIN_BARCODE_SIZE + (MAX_ATTRIBUTES - attributes.length) * STEP; + } + const getAttributeText = (attribute: BarcodeAttributeSchema) => { + let result = `${attribute.name}: ${attribute.value}`; + if (result.length > MAX_ATTRIBUTE_LENGTH) { + result = result.slice(0, MAX_ATTRIBUTE_LENGTH - 1) + "."; + } + return result; + } + + return ( +
+ {barcode && Array.from({length: quantity}).map((_, index) => ( + <> + + + + + {attributes.slice(0, MAX_ATTRIBUTES).map((attr) => ( + + {getAttributeText(attr)} + + ))} + + + ))} +
+ + ) +}); + +export default PrintBarcodeContainer; \ No newline at end of file diff --git a/src/modals/PrintBarcodeModal/PrintBarcodeModal.module.css b/src/modals/PrintBarcodeModal/PrintBarcodeModal.module.css index 265123a..a492e0b 100644 --- a/src/modals/PrintBarcodeModal/PrintBarcodeModal.module.css +++ b/src/modals/PrintBarcodeModal/PrintBarcodeModal.module.css @@ -6,4 +6,16 @@ .print-only { display: block; } + + + .barcode-container { + text-align: left; + margin: 1.25mm; + padding: 1.25mm; + background-color: white; + } + + .barcode-attribute-text { + line-height: 1; + } } \ No newline at end of file diff --git a/src/modals/PrintBarcodeModal/PrintBarcodeModal.tsx b/src/modals/PrintBarcodeModal/PrintBarcodeModal.tsx index 3273ee1..5fdef31 100644 --- a/src/modals/PrintBarcodeModal/PrintBarcodeModal.tsx +++ b/src/modals/PrintBarcodeModal/PrintBarcodeModal.tsx @@ -1,12 +1,11 @@ import {ContextModalProps, modals} from "@mantine/modals"; -import {Button, Divider, Flex, NumberInput, rem, Select, Spoiler} from "@mantine/core"; -import Barcode from "react-barcode"; +import {Button, Divider, Flex, NumberInput, rem, Select} from "@mantine/core"; import {useEffect, useRef, useState} from "react"; import {useReactToPrint} from "react-to-print"; -import {ProductService} from "../../client"; -import styles from "./PrintBarcodeModal.module.css"; +import {BarcodeSchema, ProductService} from "../../client"; import {useGetProductById} from "../../api/product/useGetProductById.tsx"; import {notifications} from "../../shared/lib/notifications.ts"; +import PrintBarcodeContainer from "./PrintBarcodeContainer.tsx"; type Props = { productId: number; @@ -18,6 +17,7 @@ const PrintBarcodeModal = ({ const {productId, defaultQuantity = 1} = innerProps; const [quantity, setQuantity] = useState(defaultQuantity); const [barcode, setBarcode] = useState() + const [barcodeData, setBarcodeData] = useState(); const {product, refetch} = useGetProductById(productId); @@ -55,11 +55,26 @@ const PrintBarcodeModal = ({ setBarcode(barcode); }) } + const fetchBarcodeData = () => { + if (!barcode) return; + ProductService.getProductBarcode({ + requestBody: + {barcode, productId} + }).then(({barcode}) => { + setBarcodeData(barcode); + }) + } useEffect(() => { if (!product) return; if (product.barcodes.length === 1) setBarcode(product.barcodes[0]); }, [product]); + + useEffect(() => { + if (!barcode) return; + fetchBarcodeData(); + }, [barcode]); + return ( <> typeof value === "number" && setQuantity(value)} min={1} /> - -
- {barcode && - - } -
-
+ @@ -120,11 +121,13 @@ const PrintBarcodeModal = ({ >Печать
-
- {barcode && Array.from({length: quantity}).map((_, index) => ( - - ))} -
+ ) } diff --git a/src/pages/BarcodePage/components/BarcodeTemplateSizeSelect/BarcodeTemplateSizeSelect.tsx b/src/pages/BarcodePage/components/BarcodeTemplateSizeSelect/BarcodeTemplateSizeSelect.tsx new file mode 100644 index 0000000..177302e --- /dev/null +++ b/src/pages/BarcodePage/components/BarcodeTemplateSizeSelect/BarcodeTemplateSizeSelect.tsx @@ -0,0 +1,16 @@ +import {BarcodeTemplateSizeSchema} from "../../../../client"; +import ObjectSelect, {ObjectSelectProps} from "../../../../components/ObjectSelect/ObjectSelect.tsx"; +import useBarcodeTemplateSizesList from "../../hooks/useBarcodeTemplateSizesList.tsx"; + +type Props = Omit, 'data'> +const BarcodeTemplateSizeSelect = (props: Props) => { + const {barcodeTemplateSizes} = useBarcodeTemplateSizesList(); + + return ( + + ) +} +export default BarcodeTemplateSizeSelect; \ No newline at end of file diff --git a/src/pages/BarcodePage/components/BarcodeTemplatesTable/columns.tsx b/src/pages/BarcodePage/components/BarcodeTemplatesTable/columns.tsx index 9382a7d..e73a44a 100644 --- a/src/pages/BarcodePage/components/BarcodeTemplatesTable/columns.tsx +++ b/src/pages/BarcodePage/components/BarcodeTemplatesTable/columns.tsx @@ -15,8 +15,8 @@ export const useBarcodeTemplatesTableColumns = () => { Cell: ({row}) => <>{row.original.attributes.map(attr => attr.name).join(', ')} }, { + accessorKey: "size.name", header: "Размер", - Cell: ({row}) => <>{row.original.width}x{row.original.height} }, { accessorKey: "isDefault", diff --git a/src/pages/BarcodePage/hooks/useBarcodeTemplateSizesList.tsx b/src/pages/BarcodePage/hooks/useBarcodeTemplateSizesList.tsx new file mode 100644 index 0000000..f0e5621 --- /dev/null +++ b/src/pages/BarcodePage/hooks/useBarcodeTemplateSizesList.tsx @@ -0,0 +1,14 @@ +import {BarcodeService} from "../../../client"; +import {useQuery} from "@tanstack/react-query"; + +const useBarcodeTemplateSizesList = () => { + const {isLoading, data, error, refetch} = useQuery({ + queryKey: ['getAllBarcodeTemplateSizes'], + queryFn: BarcodeService.getAllBarcodeTemplateSizes + }); + + const barcodeTemplateSizes = isLoading || error || !data ? [] : data.sizes; + + return {barcodeTemplateSizes, refetch} +} +export default useBarcodeTemplateSizesList; \ No newline at end of file diff --git a/src/pages/BarcodePage/modals/BarcodeTemplateFormModal/BarcodeTemplateFormModal.tsx b/src/pages/BarcodePage/modals/BarcodeTemplateFormModal/BarcodeTemplateFormModal.tsx index 128d0a9..c5be565 100644 --- a/src/pages/BarcodePage/modals/BarcodeTemplateFormModal/BarcodeTemplateFormModal.tsx +++ b/src/pages/BarcodePage/modals/BarcodeTemplateFormModal/BarcodeTemplateFormModal.tsx @@ -6,12 +6,12 @@ import { } from "../../../../client"; import {ContextModalProps} from "@mantine/modals"; import {useForm} from "@mantine/form"; -import {Checkbox, Fieldset, Flex, NumberInput, rem, TextInput} from "@mantine/core"; -import {IconX} from "@tabler/icons-react"; +import {Checkbox, Fieldset, Flex, rem, TextInput} from "@mantine/core"; import BarcodeTemplateAttributeMultiselect from "../../components/BarcodeTemplateAttributeMultiselect/BarcodeTemplateAttributeMultiselect.tsx"; import BarcodeTemplateAdditionalFieldTable from "../../components/BarcodeTemplateAdditionalFieldTable/BarcodeTemplateAdditionalFieldTable.tsx"; +import BarcodeTemplateSizeSelect from "../../components/BarcodeTemplateSizeSelect/BarcodeTemplateSizeSelect.tsx"; type Props = CreateEditFormProps const BarcodeTemplateFormModal = ({ @@ -22,8 +22,6 @@ const BarcodeTemplateFormModal = ({ const isEditing = 'onChange' in innerProps; const initialValues = isEditing ? innerProps.element : { name: "", - width: undefined, - height: undefined, isDefault: false, attributes: [] as Array, additionalAttributes: [] as Array @@ -31,9 +29,7 @@ const BarcodeTemplateFormModal = ({ const form = useForm>({ initialValues: initialValues, validate: { - width: (width: number | undefined) => width && width > 0 ? null : "Ширина должна быть больше 0", - height: (height: number | undefined) => height && height > 0 ? null : "Высота должна быть больше 0", - attributes: (attributes: Array | undefined) => attributes && attributes.length > 0 ? null : "Необходимо добавить хотя бы один атрибут", + attributes: (attributes: Array | undefined) => attributes ? null : "Необходимо добавить хотя бы один атрибут", name: (name: string | undefined) => name && name.trim() !== '' ? null : "Необходимо ввести название шаблона", } }) @@ -55,21 +51,12 @@ const BarcodeTemplateFormModal = ({ placeholder={"Введите название шаблона"} {...form.getInputProps('name')} /> - - - - - + +