feat: 支持新样式配置 (#1000)

Reviewed-on: daoyoucloud/tachybase#1000
This commit is contained in:
sealday 2024-05-16 19:01:26 +08:00
parent 87245462e2
commit 9ba7c8f3c3
19 changed files with 612 additions and 904 deletions

View File

@ -29,5 +29,6 @@ export class PluginOutbound extends Plugin {
this.app.schemaInitializerManager.addItem('table:configureActions', outboundItem.name, outboundItem);
this.app.schemaInitializerManager.addItem('details:configureActions', outboundItem.name, outboundItem);
this.app.schemaInitializerManager.addItem('kanban:configureActions', outboundItem.name, outboundItem);
this.app.schemaInitializerManager.addItem('pdfViewer:configureActions', outboundItem.name, outboundItem);
}
}

View File

@ -1,4 +1,4 @@
import React, { createContext, useContext, useRef, useState } from 'react';
import React, { createContext, useContext, useRef } from 'react';
import { PrinterOutlined } from '@ant-design/icons';
import {
ActionInitializer,
@ -8,6 +8,7 @@ import {
useSchemaInitializer,
useSchemaInitializerItem,
} from '@tachybase/client';
import { tval } from '../../locale';
const PDFViewerContext = createContext(null);
@ -43,7 +44,7 @@ export const usePDFViewerPrintActionProps = () => {
export const PDFViewerPrintActionInitializer = (props) => {
const schema = {
title: '{{ t("Print") }}',
title: tval('Print'),
'x-action': 'print',
'x-component': 'Action',
'x-designer': 'Action.Designer',
@ -56,7 +57,7 @@ export const PDFViewerPrintActionInitializer = (props) => {
};
export const pdfViewActionInitializer = new SchemaInitializer({
name: 'PDFViewActionInitializer',
name: 'pdfViewer:configureActions',
title: 'Configure actions',
icon: 'SettingOutlined',
style: {
@ -64,19 +65,19 @@ export const pdfViewActionInitializer = new SchemaInitializer({
},
items: [
{
name: 'enbaleActions',
name: 'enableActions',
type: 'itemGroup',
title: '{{t("Enable actions")}}',
title: tval('Enable actions'),
children: [
{
name: 'print',
type: 'item',
title: '{{t("Print")}}',
title: tval('Print'),
component: 'PDFViewerPrintActionInitializer',
},
{
name: 'edit',
title: '{{t("Edit")}}',
title: tval('Edit'),
Component: 'UpdateActionInitializer',
schema: {
'x-component': 'Action',
@ -110,7 +111,7 @@ export const PDFViewerBlockInitializer = () => {
properties: {
actions: {
type: 'void',
'x-initializer': 'PDFViewActionInitializer',
'x-initializer': 'pdfViewer:configureActions',
'x-component': 'ActionBar',
'x-component-props': {},
properties: {},

View File

@ -2,7 +2,7 @@ import React, { useEffect, useRef, useState } from 'react';
import { PDFViewer } from '../../components/PDFViewer';
import { Space } from 'antd';
import { css } from '@tachybase/client';
import { usePDFViewerRef } from '../../schema-initializer/blocks/PDFVIewerBlockInitializer';
import { usePDFViewerRef } from './PDFVIewerBlockInitializer';
import { debounce } from 'lodash';
export const InternalPDFViewer = (props) => {

View File

@ -1,13 +1,13 @@
import { Plugin } from '@tachybase/client';
import { tval } from '../../locale';
import {
PDFViewerBlockInitializer,
PDFViewerPrintActionInitializer,
PDFViewerProvider,
pdfViewActionInitializer,
usePDFViewerPrintActionProps,
} from '../../schema-initializer';
import { InternalPDFViewer } from '../../schema-components';
import { tval } from '../../locale';
} from './PDFVIewerBlockInitializer';
import { InternalPDFViewer } from './PDFViewer';
export class PluginPDF extends Plugin {
async load() {
@ -21,7 +21,6 @@ export class PluginPDF extends Plugin {
PDFViwer: InternalPDFViewer,
});
this.schemaInitializerManager.add(pdfViewActionInitializer);
// 预览区块需要提前加进来,没法放在 afterload 中,这块后面需要重构
const previewBlockItem = {
title: tval('preview block'),
name: 'previewBlock',

View File

@ -67,7 +67,7 @@ import { PluginPDF } from './features/pdf';
import { PluginExtendedFilterForm } from './features/extended-filter-form';
import { PluginOutbound } from './features/outbound';
import { PluginModeHighlight } from './features/mode-highlight';
export { usePDFViewerRef } from './schema-initializer';
export { usePDFViewerRef } from './features/pdf/PDFVIewerBlockInitializer';
export * from './components/custom-components/custom-components';
export class PluginCoreClient extends Plugin {

View File

@ -1,3 +1,2 @@
export * from './auto-complete/AutoComplete';
export * from './blocks/GroupBlock';
export * from './blocks/PDFViewer';

View File

@ -1,6 +1,4 @@
export * from './items/CustomFilterFormItemInitializer';
export * from './blocks/PDFVIewerBlockInitializer';
export * from '../features/outbound/OutboundLinkActionInitializer';
export * from './actions/CreateSubmitActionInitializer';
export * from './blocks/SettingBlockInitializer';
export * from './blocks/GroupBlockInitializer';

View File

@ -17,27 +17,36 @@ export const PdfMargingTopContext = createContext({
setMargingTop: null,
});
export const PrintStyleContext = createContext({
styleId: -1,
setStyleId: null,
});
export const PdfIsDoubleProvider = (props) => {
const [isDouble, setIsDouble] = useState(false);
const [settingType, setSettingLoad] = useState(false);
const [margingTop, setMargingTop] = useState(0);
const [styleId, setStyleId] = useState(-1);
return (
<PdfMargingTopContext.Provider value={{ margingTop, setMargingTop }}>
<PdfIsDoubleContext.Provider value={{ isDouble, setIsDouble }}>
<PdfIsLoadContext.Provider value={{ settingType, setSettingLoad }}>{props.children}</PdfIsLoadContext.Provider>
</PdfIsDoubleContext.Provider>
</PdfMargingTopContext.Provider>
<PrintStyleContext.Provider value={{ styleId, setStyleId }}>
<PdfMargingTopContext.Provider value={{ margingTop, setMargingTop }}>
<PdfIsDoubleContext.Provider value={{ isDouble, setIsDouble }}>
<PdfIsLoadContext.Provider value={{ settingType, setSettingLoad }}>
{props.children}
</PdfIsLoadContext.Provider>
</PdfIsDoubleContext.Provider>
</PdfMargingTopContext.Provider>
</PrintStyleContext.Provider>
);
};
export const useRecordPdfPath = () => {
const record = useRecord();
const { isDouble } = useContext(PdfIsDoubleContext);
const { styleId } = useContext(PrintStyleContext);
const { settingType } = useContext(PdfIsLoadContext);
const { margingTop } = useContext(PdfMargingTopContext);
const path = useMemo(
() => `/records:pdf?recordId=${record.id}&isDouble=${isDouble}&settingType=${settingType}&margingTop=${margingTop}`,
[record.id, isDouble, settingType, margingTop],
() => `/records:pdf?recordId=${record.id}&settingType=${settingType}&styleId=${styleId}`,
[record.id, settingType, styleId],
);
return path;
};

View File

@ -49,6 +49,7 @@ import {
PrintSetupMargingTop,
} from './schema-initializer/actions/RecordPrintSetupMargingTopInitializer';
import { UnusedRecordsBlockHelper } from './schema-initializer/blocks/UnusedRecordsBlockInitializer';
import { PrintStyleSetupInitializer, StyleSetup } from './schema-initializer/actions/PrintStyleSetupInitializer';
export class PluginRentalClient extends Plugin {
locale: Locale;
async afterAdd() {}
@ -70,7 +71,7 @@ export class PluginRentalClient extends Plugin {
'enbaleActions.' + addToReconciliationItem.name,
addToReconciliationItem,
);
this.app.schemaInitializerManager.addItem('PDFViewActionInitializer', 'enbaleActions.printCounter', {
this.app.schemaInitializerManager.addItem('pdfViewer:configureActions', 'enableActions.printCounter', {
type: 'item',
title: '{{t("Print(countable)")}}',
component: 'PDFViewerCountablePrintActionInitializer',
@ -80,7 +81,7 @@ export class PluginRentalClient extends Plugin {
return name === 'records';
},
});
this.app.schemaInitializerManager.addItem('PDFViewActionInitializer', 'enbaleActions.columnSwitch', {
this.app.schemaInitializerManager.addItem('pdfViewer:configureActions', 'enableActions.columnSwitch', {
type: 'item',
title: '{{t("Column switch")}}',
component: 'ColumnSwitchActionInitializer',
@ -90,12 +91,12 @@ export class PluginRentalClient extends Plugin {
return name === 'records';
},
});
this.app.schemaInitializerManager.addItem('PDFViewActionInitializer', 'enbaleActions.recordPrintSetup', {
this.app.schemaInitializerManager.addItem('pdfViewer:configureActions', 'enableActions.recordPrintSetup', {
type: 'item',
title: '{{t("Record print setup")}}',
component: 'RecordPrintSetupActionInitializer',
});
this.app.schemaInitializerManager.addItem('PDFViewActionInitializer', 'enbaleActions.recordPrintMargingTop', {
this.app.schemaInitializerManager.addItem('pdfViewer:configureActions', 'enableActions.recordPrintMargingTop', {
type: 'item',
title: '{{t("Record print margingtop")}}',
component: 'RecordPrintSetupMargingTopInitializer',
@ -105,7 +106,17 @@ export class PluginRentalClient extends Plugin {
return name === 'records' || name === 'waybills';
},
});
this.app.schemaInitializerManager.addItem('PDFViewActionInitializer', 'enbaleActions.settlementExcelExport', {
this.app.schemaInitializerManager.addItem('pdfViewer:configureActions', 'enableActions.styleSetup', {
type: 'item',
title: tval('Style setup'),
Component: 'PrintStyleSetupInitializer',
useVisible() {
const collection = useCollection();
const name = collection['options']['name'];
return name === 'records' || name === 'waybills';
},
});
this.app.schemaInitializerManager.addItem('pdfViewer:configureActions', 'enableActions.settlementExcelExport', {
type: 'item',
title: '{{t("Settlement excel export")}}',
component: 'SettlementExcelExportActionInitializer',
@ -115,7 +126,7 @@ export class PluginRentalClient extends Plugin {
return name === 'settlements';
},
});
this.app.schemaInitializerManager.addItem('PDFViewActionInitializer', 'enbaleActions.settlementStyleSwitch', {
this.app.schemaInitializerManager.addItem('pdfViewer:configureActions', 'enableActions.settlementStyleSwitch', {
type: 'item',
title: '{{t("Settlement style switch")}}',
component: 'SettlementStyleSwitchActionInitializer',
@ -170,6 +181,8 @@ export class PluginRentalClient extends Plugin {
RecordDetails,
DetailChecks,
PdfIsDoubleProvider,
PrintStyleSetupInitializer,
StyleSetup,
WaybillsProvider,
AddToChecklistActionInitializer,
PrintCounterProvider,

View File

@ -0,0 +1,254 @@
import React, { useContext, useEffect, useState } from 'react';
import { ActionInitializer, useAPIClient, useRequest, useCurrentUserContext } from '@tachybase/client';
import { Button, Form, Input, Popover, Radio, Select, Space, Spin, message } from 'antd';
import { DeleteOutlined, VerticalAlignBottomOutlined, VerticalAlignTopOutlined } from '@ant-design/icons';
import { tval, useTranslation } from '../../locale';
import { PrintStyleContext } from '../../hooks/usePdfPath';
type FieldType = {
name: string;
margin: string;
fontSize: string;
size: string;
orientation: string;
column: 'single' | 'double';
comment: 'classical' | 'unified';
};
const MarginInput = (props) => {
const values = props.value ?? [0, 0, 0, 0];
return (
<Space.Compact>
<Input
value={values[0]}
onChange={(v) => {
values[0] = Number(v.target.value);
props.onChange([...values]);
}}
prefix={<VerticalAlignTopOutlined rotate={0} />}
></Input>
<Input
value={values[1]}
onChange={(v) => {
values[1] = Number(v.target.value);
props.onChange([...values]);
}}
prefix={<VerticalAlignBottomOutlined />}
></Input>
<Input
value={values[2]}
onChange={(v) => {
values[2] = Number(v.target.value);
props.onChange([...values]);
}}
prefix={<VerticalAlignTopOutlined rotate={-90} />}
></Input>
<Input
value={values[3]}
onChange={(v) => {
values[3] = Number(v.target.value);
props.onChange([...values]);
}}
prefix={<VerticalAlignTopOutlined rotate={90} />}
></Input>
</Space.Compact>
);
};
const StyleSetupContent = ({ setOpen, initialValues, refresh }) => {
const { t } = useTranslation();
const api = useAPIClient();
const [form] = Form.useForm();
useEffect(() => {
form.resetFields(Object.keys(initialValues));
}, [initialValues, form]);
return (
<Form
form={form}
labelCol={{ span: 8 }}
wrapperCol={{ span: 16 }}
style={{ width: 450 }}
initialValues={{ ...initialValues, name: (initialValues?.name ?? '') + t('new') }}
onFinish={(values) => {
api
.resource('printStyles')
.updateOrCreate({
values,
filterKeys: ['name'],
})
.then(() => {
setOpen(false);
refresh();
message.success(t('Success'));
})
.catch(console.error);
}}
autoComplete="off"
>
<Form.Item<FieldType> label={t('Name')} name="name" required>
<Input />
</Form.Item>
<Form.Item<FieldType> label={t('Margin')} name="margin" required>
<MarginInput />
</Form.Item>
<Form.Item<FieldType> label={t('Font size')} name="fontSize" required wrapperCol={{ span: 8 }}>
<Input suffix="pt" />
</Form.Item>
<Form.Item<FieldType> label={t('Paper size')} name="size" required>
<Radio.Group
options={[
{ label: t('A3'), value: 'A3' },
{ label: t('A4'), value: 'A4' },
{ label: t('A5'), value: 'A5' },
{ label: t('B4'), value: 'B4' },
{ label: t('B5'), value: 'B5' },
]}
buttonStyle="solid"
optionType="button"
/>
</Form.Item>
<Form.Item<FieldType> label={t('Paper orientation')} name="orientation" required>
<Radio.Group
options={[
{ label: t('Landscape'), value: 'landscape' },
{ label: t('Portrait'), value: 'portrait' },
]}
buttonStyle="solid"
optionType="button"
/>
</Form.Item>
<Form.Item<FieldType> label={t('Column style')} name="column" required>
<Radio.Group
options={[
{ label: t('Single column'), value: 'single' },
{ label: t('Double column'), value: 'double' },
]}
buttonStyle="solid"
optionType="button"
/>
</Form.Item>
<Form.Item<FieldType> label={t('Comment style')} name="comment" required>
<Radio.Group
options={[
{ label: t('Classical'), value: 'classical' },
{ label: t('Unified'), value: 'unified' },
]}
buttonStyle="solid"
optionType="button"
/>
</Form.Item>
<Form.Item wrapperCol={{ span: 24 }}>
<Button type="primary" htmlType="submit" block>
{t('Save')}
</Button>
</Form.Item>
</Form>
);
};
export const StyleSetup = () => {
const { t } = useTranslation();
const api = useAPIClient();
const { styleId, setStyleId } = useContext(PrintStyleContext);
const [open, setOpen] = useState(false);
const { data } = useCurrentUserContext();
const userId = data.data?.id;
const users = useRequest<any>({
resource: 'users',
action: 'get',
params: {
filter: {
id: userId,
},
appends: ['defaultPrintStyle'],
},
});
const printStyles = useRequest<any>({
resource: 'printStyles',
action: 'list',
});
useEffect(() => {
if (styleId === -1) {
if (users.data?.data?.defaultPrintStyle) {
setStyleId(users.data.data.defaultPrintStyle.id);
} else if (printStyles.data?.data && printStyles.data?.data.length > 0) {
setStyleId(printStyles.data.data[0].id);
}
}
}, [styleId, users, setStyleId, printStyles]);
if (users.loading && !users.data) {
return <Spin />;
}
if (printStyles.loading && !printStyles.data) {
return <Spin />;
}
const defaultStyle = users.data.data.defaultPrintStyle;
const styles = printStyles.data.data;
return (
<Space.Compact>
<Select
options={printStyles.data?.data?.map((v) => ({ label: v.name, value: v.id }))}
value={styleId}
optionRender={(option) => (
<span style={{ display: 'inline-flex', width: '100%' }}>
<span style={{ flex: 1 }}>{option.label}</span>
{styles.length > 1 && (
<DeleteOutlined
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
api
.resource('printStyles')
.destroy({
filterByTk: option.value,
})
.then(() => {
printStyles.refresh();
})
.catch(console.error);
}}
/>
)}
</span>
)}
onChange={(i) => {
setStyleId(i);
api.resource('users').update({
filterByTk: userId,
values: {
defaultPrintStyleId: i,
},
});
}}
/>
<Popover
content={
<StyleSetupContent
refresh={() => printStyles.refresh()}
setOpen={setOpen}
initialValues={{ margin: [12, 12, 12, 12], ...styles.find((style) => style.id === styleId) }}
/>
}
placement="bottom"
trigger="click"
open={open}
onOpenChange={setOpen}
>
<Button>{t('Add new style')}</Button>
</Popover>
</Space.Compact>
);
};
export const PrintStyleSetupInitializer = (props) => {
const schema = {
title: tval('Style setup'),
'x-component': 'StyleSetup',
};
return <ActionInitializer {...props} schema={schema} />;
};

View File

@ -1,4 +1,5 @@
export interface RecordPdfOptions {
isDouble: number;
printSetup: String;
styleId: number;
}

View File

@ -1,6 +1,22 @@
{
"Add new style": "Add new style",
"Name": "Name",
"Margin": "Margin",
"Paper size": "Paper size",
"Paper orientation": "Paper orientation",
"Column style": "Column style",
"Comment style": "Comment style",
"Landscape": "Landscape",
"Portrait": "Portrait",
"Single column": "Single column",
"Double column": "Double column",
"Classical": "Classical",
"Unified": "Unified",
"Save": "Save",
"Font size": "Font size",
"record": "record",
"waybill": "waybill",
"settlement": "settlement",
"Style setup": "Style setup",
"Add to checklist": "Add to checklist"
}

View File

@ -1,6 +1,22 @@
{
"Add new style": "添加新样式",
"Name": "名称",
"Margin": "外边距",
"Paper size": "纸张大小",
"Paper orientation": "纸张方向",
"Column style": "列样式",
"Comment style": "备注样式",
"Landscape": "横向",
"Portrait": "竖向",
"Single column": "单列",
"Double column": "双列",
"Classical": "经典",
"Unified": "统一备注",
"Save": "保存",
"Font size": "字体大小",
"record": "记录单",
"waybill": "运输单",
"settlement": "结算单",
"Style setup": "样式配置",
"Add to checklist": "添加到检查列表"
}

View File

@ -177,7 +177,7 @@ export class RecordPreviewController {
@Action('pdf')
async printPreview(ctx: Context) {
const {
params: { recordId, isDouble, settingType, margingTop },
params: { recordId, isDouble, settingType, margingTop, styleId = -1 },
} = ctx.action;
// 拉侧面文字说明
const pdfExplain = await ctx.db.getRepository('basic_configuration').find();
@ -227,7 +227,12 @@ export class RecordPreviewController {
const double = isDouble === '0' || isDouble === '1' ? isDouble : pdfExplain[0].record_columns;
const cache = ctx.app.cacheManager.getCache('@hera/plugin-rental') as Cache;
const key = stringify({ record, leaseData, feeData, settings: { isDouble: double, printSetup } });
const key = stringify({
record,
leaseData,
feeData,
settings: { isDouble: double, printSetup, styleId: Number(styleId) },
});
const result = await cache.get(key);
if (result) {
@ -239,7 +244,11 @@ export class RecordPreviewController {
} else {
const buf = await getStream.buffer(
// @ts-ignore
await this.recordPdfService.transformPdfV2(record, leaseData, feeData, { isDouble: double, printSetup }),
await this.recordPdfService.transformPdfV2(record, leaseData, feeData, {
isDouble: double,
printSetup,
styleId: Number(styleId),
}),
);
ctx.body = buf;
await cache.set(key, buf);

View File

@ -0,0 +1,50 @@
import { defineCollection } from '@tachybase/database';
export default defineCollection({
dumpRules: 'required',
name: 'printStyles',
fields: [
{
type: 'string',
name: 'name',
allowNull: false,
defaultValue: false,
},
{
type: 'json',
name: 'margin',
allowNull: false,
defaultValue: false,
},
{
type: 'string',
name: 'size',
allowNull: false,
defaultValue: false,
},
{
type: 'string',
name: 'fontSize',
allowNull: false,
defaultValue: false,
},
{
type: 'string',
name: 'orientation',
allowNull: false,
defaultValue: false,
},
{
type: 'string',
name: 'column',
allowNull: false,
defaultValue: false,
},
{
type: 'string',
name: 'comment',
allowNull: false,
defaultValue: false,
},
],
});

View File

@ -0,0 +1,12 @@
import { extendCollection } from '@tachybase/database';
export default extendCollection({
name: 'users',
fields: [
{
type: 'belongsTo',
name: 'defaultPrintStyle',
target: 'printStyles',
},
],
});

View File

@ -1,676 +0,0 @@
import React from 'react';
import { Document, Page, Text, View, StyleSheet, Image, renderToStream, Font } from '@hera/plugin-core';
import { Record } from '../../interfaces/record';
import * as QRCode from 'qrcode';
import { ConversionLogics, RecordCategory } from '../../utils/constants';
import { formatCurrency, formatQuantity } from '../../utils/currencyUtils';
const fontSizes = {
title: '12px',
subTitle: '9px',
main: '7px',
side: '6px',
};
const styles = StyleSheet.create({
page: {
flexDirection: 'column',
backgroundColor: '#FFF',
fontFamily: 'source-han-sans',
padding: '12px',
},
title: {
textAlign: 'center',
fontSize: fontSizes.title,
},
subTitle: {
textAlign: 'center',
fontSize: fontSizes.subTitle,
},
content: {
flexDirection: 'row',
marginLeft: '10pt',
marginRight: '10pt',
},
main: {
flex: 1,
},
side: {
width: '11px',
fontSize: fontSizes.side,
paddingLeft: '2px',
},
tableHeader: {
fontSize: fontSizes.main,
flexDirection: 'row',
},
headerLeft: {
width: '205px',
},
headerMiddle: {
flex: 1,
},
headerLeftLeft: {
flex: 2,
// textAlign: 'left',
},
headerLeftRight: {
flex: 1,
// textAlign: 'right',
},
headerRight: {
width: '205px',
},
tableContentTitle: {
fontSize: fontSizes.main,
flexDirection: 'row',
},
tableCellLargeTitle: {
flex: 2,
textAlign: 'center',
borderLeft: '1px solid black',
marginLeft: '-1px',
borderTop: '1px solid black',
marginTop: '-1px',
},
tableCellTitle: {
flex: 1,
textAlign: 'center',
borderLeft: '1px solid black',
marginLeft: '-1px',
borderTop: '1px solid black',
marginTop: '-1px',
},
tableCell2Title: {
flex: 2,
textAlign: 'center',
borderLeft: '1px solid black',
marginLeft: '-1px',
borderTop: '1px solid black',
marginTop: '-1px',
},
tableCellTitleLast: {
flex: 1,
textAlign: 'center',
borderLeft: '1px solid black',
marginLeft: '-1px',
borderTop: '1px solid black',
marginTop: '-1px',
borderRight: '1px solid black',
marginRight: '-1px',
},
tableCell2TitleLast: {
flex: 2,
textAlign: 'center',
borderLeft: '1px solid black',
marginLeft: '-1px',
borderTop: '1px solid black',
marginTop: '-1px',
borderRight: '1px solid black',
marginRight: '-1px',
},
tableContent: {
fontSize: fontSizes.main,
flexDirection: 'row',
},
tableCell: {
flex: 1,
textAlign: 'right',
borderLeft: '1px solid black',
marginLeft: '-1px',
borderTop: '1px solid black',
marginTop: '-1px',
borderBottom: '1px solid black',
},
tableCellNoLeft: {
flex: 1,
textAlign: 'right',
borderTop: '1px solid black',
marginTop: '-1px',
borderBottom: '1px solid black',
},
tableCell2: {
flex: 2,
textAlign: 'right',
borderLeft: '1px solid black',
marginLeft: '-1px',
borderTop: '1px solid black',
marginTop: '-1px',
},
tableCellLast: {
flex: 1,
textAlign: 'right',
borderLeft: '1px solid black',
marginLeft: '-1px',
borderTop: '1px solid black',
marginTop: '-1px',
borderRight: '1px solid black',
marginRight: '-1px',
borderBottom: '1px solid black',
},
tableCell2Last: {
flex: 2,
textAlign: 'right',
borderLeft: '1px solid black',
marginLeft: '-1px',
borderTop: '1px solid black',
marginTop: '-1px',
borderRight: '1px solid black',
marginRight: '-1px',
borderBottom: '1px solid black',
},
tableFooter: {
flexDirection: 'row',
},
tableFooterQr: {
width: '50px',
marginLeft: '-50px',
transform: 'translate(50px, 0)',
},
tableFooterLeft: {
flex: 1,
fontSize: fontSizes.main,
borderLeft: '1px solid black',
paddingLeft: '50px',
marginLeft: '-1px',
borderTop: '1px solid black',
marginTop: '-1px',
borderBottom: '1px solid black',
marginBottom: '-1px',
},
tableFooterRight: {
flex: 1,
fontSize: fontSizes.main,
border: '1px solid black',
paddingRight: '50px',
margin: '-1px',
},
sign: {
marginTop: '0px',
flexDirection: 'row',
},
signPart: {
flex: 1,
fontSize: fontSizes.main,
},
});
/**
*
* @param isDouble 01
* @returns
*/
const PreviewDocument = ({
imageUrl,
record,
calc,
isDouble,
}: {
imageUrl: string;
record: Record;
calc: any;
isDouble: Number;
}) => {
if (Number(record.category) >= 4) {
return (
<Document>
<Page size="A4" style={styles.page}>
<Text style={styles.title}></Text>
</Page>
</Document>
);
}
const recordType = {
'0': '租赁',
'1': '购销',
'2': '暂存',
'3': '盘点',
};
isDouble = Number(isDouble);
// 出入库判断
const outOfStorage = record.movement === '1' ? '入库' : '出库';
// 订单日期
const date = record.date;
// 流水号
const number = record.number;
// 车号
const car = record.vehicles ? record.vehicles.map((item) => item?.number).join(' ') : '';
// 原始单号
const origin = record.original_number;
// 订单状态
const type = record.category;
// 说明
const explain =
type === RecordCategory.inventory
? `盘点单用于清算仓库盈亏盈余。`
: `如供需双方未签正式合同,本${
recordType[type]
}${outOfStorage} ${
outOfStorage === '入库' ? '出库方' : '采购方'
} `;
// 备注
const comments = record.comment;
// 制单人
const singlePlayer = record.nickname + ' ' + record?.userPhone;
// 合同编号
const contractId = record.contract ? record.contract.id : '';
// 状态
const status = record.contract?.project ? (record.contract.project?.status === 0 ? '进行中' : '已完结') : '';
// 客户号
const projectId = record?.contract?.project ? record?.contract?.project?.id : '';
// 出入库仓库
const outOfStorageAddress = (type) => {
// 此type用于展示出入类型
if (type === 1) {
// 返回出库
return record.out_stock.name;
} else {
// 确定入库
return record.in_stock.name;
}
};
// 双列展示
const transformRecord = calc;
const dobuleData = [];
if (isDouble && transformRecord) {
// 双列展示
const leftData = transformRecord.slice(0, Math.ceil(transformRecord.length / 2));
const rightData = transformRecord.slice(Math.ceil(transformRecord.length / 2));
for (let index = 0; index < leftData.length; index++) {
const left = Object.fromEntries(Object.entries(leftData[index]).map(([key, value]) => ['left_' + key, value]));
let right;
if (rightData[index]) {
right = Object.fromEntries(Object.entries(rightData[index]).map(([key, value]) => ['right_' + key, value]));
} else {
right = {};
}
const result = { ...left, ...right };
dobuleData.push(result);
}
}
// 总金额
const getAllPrice = () => {
let price = 0;
if (!record_other_fee) return;
record_other_fee.forEach((element) => {
price += element.allPrice;
});
return formatCurrency(price, 2);
};
// 购销单,报价
const getRecordItemCount = (category) => {
let count = 0;
let unit = '';
let type = category.conversion_logic_id;
let data;
let isWeight = false;
let weight = 1;
if (category.product_id > 99999) {
data = transformRecord.filter(
(element) => element.product_category?.id === category.product.id - 99999 && !element.isTotal,
);
} else {
data = transformRecord.filter((element) => element.product?.id === category.product.id && !element.isTotal);
}
if (type > 4) {
const otherRule = category.ucl.other_rules.filter(
(item) => item.product_id === category.product.id || item.product_id === category.product.id - 99999,
)[0];
type = otherRule?.conversion_logic_id;
isWeight = true;
weight = otherRule?.weight;
}
if (type === ConversionLogics.Keep) {
data.forEach((element) => {
count += element.count || 0;
unit = element.product_category.unit || '';
});
} else if (type === ConversionLogics.Product) {
if (isWeight) {
data.forEach((element) => {
count += element.count * weight * (element.product_category.convertible ? element.product.ratio : 1) || 0;
unit = element.product_category.convertible
? element.product_category.conversion_unit
: element.product_category.unit;
});
} else {
data.forEach((element) => {
count += element.count * (element.product_category.convertible ? element.product.ratio : 1) || 0;
unit = element.product_category.convertible
? element.product_category.conversion_unit
: element.product_category.unit;
});
}
} else if (type === ConversionLogics.ActualWeight) {
// 取分组重量数据
if (record.record_weight_items?.length) {
const id = category.product.id > 99999 ? category.product.id - 99999 : category.product.id;
count = record.record_weight_items.filter((item) => item.product_category_id === id)[0].weight || record.weight;
unit = '吨';
} else {
count = record.weight;
unit = '吨';
}
} else if (type === ConversionLogics.ProductWeight) {
data.forEach((element) => {
count += element.count * element.product.weight || 0;
unit = '吨';
});
}
if (type === ConversionLogics.ProductWeight) count = count / 1000;
return { count, unit };
};
const record_other_fee =
record.record_lease_rules?.map((item) => {
const data = {
...item,
name: item.product.label,
unit_price: item.unit_price,
origin_unit: getRecordItemCount(item).unit,
total: getRecordItemCount(item).count
? formatQuantity(getRecordItemCount(item).count, 3) + getRecordItemCount(item).unit
: '',
allPrice: getRecordItemCount(item).count ? getRecordItemCount(item).count * item.unit_price : '',
};
return data;
}) || [];
// 双列展示
const rules_dobuleData = [];
if (isDouble && record_other_fee && type === RecordCategory.purchase) {
// 双列展示
const leftData = record_other_fee.slice(0, Math.ceil(record_other_fee.length / 2));
const rightData = record_other_fee.slice(Math.ceil(record_other_fee.length / 2));
for (let index = 0; index < leftData.length; index++) {
const left = Object.fromEntries(Object.entries(leftData[index]).map(([key, value]) => ['left_' + key, value]));
let right;
if (rightData[index]) {
right = Object.fromEntries(Object.entries(rightData[index]).map(([key, value]) => ['right_' + key, value]));
} else {
right = {};
}
const result = { ...left, ...right };
rules_dobuleData.push(result);
}
}
// 打印单公司标题名称
const getTitle = () => {
let name;
if (type === RecordCategory.lease) {
name = record.contract?.project?.associated_company?.name ?? record.systemTitle;
} else {
if (outOfStorage === '入库') {
name = record.out_stock?.associated_company?.name ?? record.systemTitle;
} else {
name = record.in_stock?.associated_company?.name ?? record.systemTitle;
}
}
return name;
};
const recordsName = getTitle();
// 项目联系人信息
const projectPhone = record.contract?.project?.contacts
?.map((item) => (item.name || '') + (item.phone || ''))
.join(' ');
const transUnit = (count, unit) => {
if (unit && unit === 'KG') {
return formatQuantity(count / 1000, 3) + '吨';
} else {
return formatQuantity(count, 3) + unit;
}
};
return (
<Document>
<Page size="A4" style={styles.page}>
<Text style={styles.title}>{recordsName}</Text>
<Text style={styles.subTitle}>{record.category === RecordCategory.inventory ? '盘点' : outOfStorage}</Text>
<View style={styles.content}>
<View style={styles.main}>
{/* 第一行 */}
<View style={styles.tableHeader}>
{record.category === RecordCategory.purchase && (
<Text style={styles.headerLeft}>{outOfStorageAddress(1)}</Text>
)}
{record.category === RecordCategory.staging && (
<Text style={styles.headerLeft}>{outOfStorageAddress(1)}</Text>
)}
{record.category === RecordCategory.inventory && (
<Text style={styles.headerLeft}>{record.in_stock?.name}</Text>
)}
{record.category !== RecordCategory.lease && (
<Text style={styles.headerMiddle}>{date && date.toLocaleDateString()}</Text>
)}
{record.category !== RecordCategory.lease && <Text style={styles.headerRight}>{number}</Text>}
</View>
{/* 第二行 */}
<View style={styles.tableHeader}>
{record.category === RecordCategory.purchase && (
<Text style={styles.headerLeft}>{outOfStorageAddress(0)}</Text>
)}
{record.category === RecordCategory.staging && (
<Text style={styles.headerLeft}>{outOfStorageAddress(0)}</Text>
)}
{record.category !== RecordCategory.inventory && record.category !== RecordCategory.lease && (
<Text style={styles.headerMiddle}>{car}</Text>
)}
{record.category !== RecordCategory.inventory && record.category !== RecordCategory.lease && (
<Text style={styles.headerRight}>{origin}</Text>
)}
</View>
{/* 租赁 */}
{record.category === RecordCategory.lease && (
<View style={styles.tableHeader}>
<Text style={styles.headerLeftLeft}>{record.contract?.project?.company?.name || ''}</Text>
<Text style={styles.headerLeftRight}>{date && date.toLocaleDateString()}</Text>
</View>
)}
{record.category === RecordCategory.lease && (
<View style={styles.tableHeader}>
<Text style={styles.headerLeftLeft}>
{record.contract?.project?.id + ' ' || ''}
{record.contract?.project?.name || ''}
</Text>
<Text style={styles.headerLeftRight}>{number}</Text>
</View>
)}
{record.category === RecordCategory.lease && (
<View style={styles.tableHeader}>
<Text style={styles.headerLeftLeft}>{record.contract?.project?.address}</Text>
<Text style={styles.headerLeftRight}>{origin}</Text>
</View>
)}
{record.category === RecordCategory.lease && (
<View style={styles.tableHeader}>
<Text style={styles.headerLeftLeft}>{projectPhone}</Text>
<Text style={styles.headerLeftRight}>{car}</Text>
</View>
)}
{!isDouble && type === RecordCategory.purchase && (
<View style={styles.tableContentTitle}>
<Text style={styles.tableCellLargeTitle}></Text>
<Text style={styles.tableCellTitle}></Text>
<Text style={styles.tableCellTitle}></Text>
<Text style={styles.tableCellTitle}></Text>
<Text style={styles.tableCellTitleLast}></Text>
</View>
)}
{!isDouble &&
type === RecordCategory.purchase &&
record_other_fee.map((item) => (
<View key={'key'} style={styles.tableContent}>
<Text style={styles.tableCell2}>{item?.name}</Text>
<Text style={styles.tableCell}>
{item?.unit_price && item?.unit_price + '元/' + item.origin_unit}
</Text>
<Text style={styles.tableCell}>{item?.total}</Text>
<Text style={styles.tableCell}>
{item?.allPrice ? formatCurrency(item.allPrice, 2) : '无对应规则,请检查!'}
</Text>
<Text style={styles.tableCellLast}>{item?.comment || ''}</Text>
</View>
))}
{isDouble && type === RecordCategory.purchase && (
<View style={styles.tableContentTitle}>
<Text style={styles.tableCellLargeTitle}></Text>
<Text style={styles.tableCellTitle}></Text>
<Text style={styles.tableCellTitle}></Text>
<Text style={styles.tableCellTitle}></Text>
<Text style={styles.tableCellTitle}></Text>
<Text style={styles.tableCellLargeTitle}></Text>
<Text style={styles.tableCellTitle}></Text>
<Text style={styles.tableCellTitle}></Text>
<Text style={styles.tableCellTitle}></Text>
<Text style={styles.tableCellTitleLast}></Text>
</View>
)}
{isDouble &&
type === RecordCategory.purchase &&
rules_dobuleData.map((item) => (
<View key={'key'} style={styles.tableContent}>
<Text style={styles.tableCell2}>{item.left_name}</Text>
<Text style={styles.tableCell}>{item.left_unit_price + '元/' + item.left_origin_unit}</Text>
<Text style={styles.tableCell}>{item.left_total}</Text>
<Text style={styles.tableCell}>
{item?.left_allPrice
? formatCurrency(item?.left_allPrice, 2)
: item?.left_name
? '无对应规则,请检查!'
: ''}
</Text>
<Text style={styles.tableCell}>{item.left_comment || ''}</Text>
<Text style={styles.tableCell2}>{item?.right_name}</Text>
<Text style={styles.tableCell}>
{item?.right_unit_price && item?.right_unit_price + '元/' + item?.right_origin_unit}
</Text>
<Text style={styles.tableCell}>{item?.right_total}</Text>
<Text style={styles.tableCell}>
{item?.right_allPrice
? formatCurrency(item?.right_allPrice, 2)
: item?.right_name
? '无对应规则,请检查!'
: ''}
</Text>
<Text style={styles.tableCellLast}>{item?.right_comment || ''}</Text>
</View>
))}
{/* 表格 */}
{/* ==========================================================================两表分割================================================================================================ */}
{!isDouble && (
<View style={styles.tableContentTitle}>
<Text style={styles.tableCellLargeTitle}></Text>
<Text style={styles.tableCellTitle}></Text>
<Text style={styles.tableCellTitle}></Text>
<Text style={type === RecordCategory.purchase ? styles.tableCell2TitleLast : styles.tableCellTitleLast}>
</Text>
</View>
)}
{!isDouble &&
transformRecord.map((item) => (
<View key={'key'} style={styles.tableContent}>
<Text style={styles.tableCell2}>{item.name}</Text>
<Text style={styles.tableCell}>{item.count + item.unit}</Text>
<Text style={item.isTotal ? styles.tableCellNoLeft : styles.tableCell}>
{item.total_uni === 'KG' ? formatQuantity(item.total / 1000, 2) : formatQuantity(item.total, 2)}
{item.total_unit === 'KG' ? '吨' : item.total_unit}
</Text>
<Text style={type === RecordCategory.purchase ? styles.tableCell2Last : styles.tableCellLast}>
{item.comment || ''}
</Text>
</View>
))}
{!isDouble && type === RecordCategory.purchase && (
<View style={styles.tableContent}>
<Text style={styles.tableCell2}></Text>
<Text style={styles.tableCell}></Text>
<Text style={styles.tableCell}>{type === RecordCategory.purchase && getAllPrice()}</Text>
<Text style={type === RecordCategory.purchase ? styles.tableCell2Last : styles.tableCellLast}></Text>
</View>
)}
{isDouble && (
<View style={styles.tableContentTitle}>
<Text style={styles.tableCellLargeTitle}></Text>
<Text style={styles.tableCellTitle}></Text>
<Text style={styles.tableCellTitle}></Text>
<Text style={type === RecordCategory.purchase ? styles.tableCell2Title : styles.tableCellTitle}>
</Text>
<Text style={styles.tableCellLargeTitle}></Text>
<Text style={styles.tableCellTitle}></Text>
<Text style={styles.tableCellTitle}></Text>
<Text style={type === RecordCategory.purchase ? styles.tableCell2TitleLast : styles.tableCellTitleLast}>
</Text>
</View>
)}
{isDouble &&
dobuleData.map((item) => (
<View key={'key'} style={styles.tableContent}>
<Text style={styles.tableCell2}>{item.left_name}</Text>
<Text style={styles.tableCell}>{item.left_count + item.left_unit}</Text>
<Text style={item.left_isTotal ? styles.tableCellNoLeft : styles.tableCell}>
{transUnit(item.left_total, item.left_total_unit)}
</Text>
<Text style={type === RecordCategory.purchase ? styles.tableCell2 : styles.tableCell}>
{item.comment || ''}
</Text>
<Text style={styles.tableCell2}>{item?.right_name}</Text>
<Text style={styles.tableCell}>
{item?.right_count} {item?.right_unit}
</Text>
<Text style={item?.right_isTotal ? styles.tableCellNoLeft : styles.tableCell}>
{item.right_name && transUnit(item.right_total, item.right_total_unit)}
</Text>
<Text style={type === RecordCategory.purchase ? styles.tableCell2Last : styles.tableCellLast}>
{item?.comment}
</Text>
</View>
))}
{isDouble && type === RecordCategory.purchase && (
<View style={styles.tableContent}>
<Text style={styles.tableCell2}></Text>
<Text style={styles.tableCell}></Text>
<Text style={styles.tableCell}></Text>
<Text style={type === RecordCategory.purchase ? styles.tableCell2 : styles.tableCell}></Text>
<Text style={styles.tableCell2}></Text>
<Text style={styles.tableCell}></Text>
<Text style={styles.tableCell}>{type === RecordCategory.purchase && getAllPrice()}</Text>
<Text style={type === RecordCategory.purchase ? styles.tableCell2Last : styles.tableCellLast}></Text>
</View>
)}
{/* 表格底部 */}
<View style={styles.tableFooter}>
<View style={styles.tableFooterQr}>
<Image src={imageUrl} />
</View>
<View style={styles.tableFooterLeft}>
<Text>{explain}</Text>
</View>
<Text style={styles.tableFooterRight}>
{' '}
<Text>{comments}</Text>
</Text>
</View>
<View style={styles.sign}>
<Text style={styles.signPart}>{singlePlayer}</Text>
{type === RecordCategory.lease && <Text style={styles.signPart}></Text>}
{type === RecordCategory.lease && <Text style={styles.signPart}></Text>}
{type === RecordCategory.purchase && <Text style={styles.signPart}></Text>}
{type === RecordCategory.purchase && <Text style={styles.signPart}></Text>}
{type === RecordCategory.staging && <Text style={styles.signPart}></Text>}
{type === RecordCategory.inventory && <Text style={styles.signPart}></Text>}
</View>
</View>
<View style={styles.side}>
<Text>{record.pdfExplain}</Text>
</View>
</View>
</Page>
</Document>
);
};
export const renderIt = async (rent: { record: Record; calc; isDouble: Number }) => {
const url = 'https://shcx.daoyoucloud.com/admin';
const imageUrl = await QRCode.toDataURL(url);
return await renderToStream(<PreviewDocument imageUrl={imageUrl} {...rent} />);
};

View File

@ -4,194 +4,6 @@ import * as QRCode from 'qrcode';
import { RecordCategory } from '../../utils/constants';
import { formatCurrency, formatQuantity } from '../../utils/currencyUtils';
import { dayjs } from '@tachybase/utils';
import { PrintSetup } from '../../utils/system';
const fontSizes = {
title: '13px',
subTitle: '11px',
main: '9px',
side: '8px',
};
const styles = StyleSheet.create({
page: {
flexDirection: 'column',
backgroundColor: '#FFF',
fontFamily: 'source-han-sans',
padding: '12px',
},
title: {
textAlign: 'center',
fontSize: fontSizes.title,
},
subTitle: {
textAlign: 'center',
fontSize: fontSizes.subTitle,
},
content: {
flexDirection: 'row',
marginLeft: '10pt',
marginRight: '10pt',
},
main: {
flex: 1,
},
side: {
width: '11px',
fontSize: fontSizes.side,
paddingLeft: '2px',
},
tableHeader: {
fontSize: fontSizes.main,
flexDirection: 'row',
},
headerLeft: {
width: '205px',
},
headerMiddle: {
flex: 1,
},
headerLeftLeft: {
flex: 2,
},
headerLeftRight: {
flex: 1,
},
headerRight: {
width: '205px',
},
tableContentTitle: {
fontSize: fontSizes.main,
flexDirection: 'row',
},
tableCellLargeTitle: {
flex: 2,
textAlign: 'center',
borderLeft: '1px solid black',
marginLeft: '-1px',
borderTop: '1px solid black',
marginTop: '-1px',
},
tableCellTitle: {
flex: 1,
textAlign: 'center',
borderLeft: '1px solid black',
marginLeft: '-1px',
borderTop: '1px solid black',
marginTop: '-1px',
},
tableCell2Title: {
flex: 2,
textAlign: 'center',
borderLeft: '1px solid black',
marginLeft: '-1px',
borderTop: '1px solid black',
marginTop: '-1px',
},
tableCellTitleLast: {
flex: 1,
textAlign: 'center',
borderLeft: '1px solid black',
marginLeft: '-1px',
borderTop: '1px solid black',
marginTop: '-1px',
borderRight: '1px solid black',
marginRight: '-1px',
},
tableCell2TitleLast: {
flex: 2,
textAlign: 'center',
borderLeft: '1px solid black',
marginLeft: '-1px',
borderTop: '1px solid black',
marginTop: '-1px',
borderRight: '1px solid black',
marginRight: '-1px',
},
tableContent: {
fontSize: fontSizes.main,
flexDirection: 'row',
},
tableCell: {
flex: 1,
textAlign: 'right',
borderLeft: '1px solid black',
marginLeft: '-1px',
borderTop: '1px solid black',
marginTop: '-1px',
borderBottom: '1px solid black',
},
tableCellNoLeft: {
flex: 1,
textAlign: 'right',
borderTop: '1px solid black',
marginTop: '-1px',
borderBottom: '1px solid black',
},
tableCell2: {
flex: 2,
textAlign: 'right',
borderLeft: '1px solid black',
marginLeft: '-1px',
borderTop: '1px solid black',
marginTop: '-1px',
borderBottom: '1px solid black',
},
tableCellLast: {
flex: 1,
textAlign: 'right',
borderLeft: '1px solid black',
marginLeft: '-1px',
borderTop: '1px solid black',
marginTop: '-1px',
borderRight: '1px solid black',
marginRight: '-1px',
borderBottom: '1px solid black',
},
tableCell2Last: {
flex: 2,
textAlign: 'right',
borderLeft: '1px solid black',
marginLeft: '-1px',
borderTop: '1px solid black',
marginTop: '-1px',
borderRight: '1px solid black',
marginRight: '-1px',
borderBottom: '1px solid black',
},
tableFooter: {
flexDirection: 'row',
},
tableFooterQr: {
width: '50px',
marginLeft: '-50px',
transform: 'translate(50px, 0)',
},
tableFooterLeft: {
flex: 1,
fontSize: fontSizes.main,
borderLeft: '1px solid black',
paddingLeft: '50px',
marginLeft: '-1px',
borderTop: '1px solid black',
marginTop: '-1px',
borderBottom: '1px solid black',
marginBottom: '-1px',
},
tableFooterRight: {
flex: 1,
fontSize: fontSizes.main,
border: '1px solid black',
paddingRight: '50px',
margin: '-1px',
},
sign: {
marginTop: '0px',
flexDirection: 'row',
},
signPart: {
flex: 1,
fontSize: fontSizes.main,
},
});
/**
*
* @param isDouble 01
@ -202,17 +14,204 @@ const PreviewDocument = ({
detail,
record,
priceRule,
isDouble,
printSetup,
printStyle,
}: {
imageUrl: string;
detail: any;
record: any[];
priceRule: any[];
isDouble: Number;
printSetup: String;
printStyle: any;
}) => {
isDouble = Number(isDouble);
const fontSizes = {
title: '13px',
subTitle: '11px',
main: printStyle.fontSize + 'px',
side: '8px',
};
const styles = StyleSheet.create({
page: {
flexDirection: 'column',
backgroundColor: '#FFF',
fontFamily: 'source-han-sans',
padding: `${printStyle.margin[0]} ${printStyle.margin[3]} ${printStyle.margin[1]} ${printStyle.margin[2]}`,
},
title: {
textAlign: 'center',
fontSize: fontSizes.title,
},
subTitle: {
textAlign: 'center',
fontSize: fontSizes.subTitle,
},
content: {
flexDirection: 'row',
marginLeft: '10pt',
marginRight: '10pt',
},
main: {
flex: 1,
},
side: {
width: '11px',
fontSize: fontSizes.side,
paddingLeft: '2px',
},
tableHeader: {
fontSize: fontSizes.main,
flexDirection: 'row',
},
headerLeft: {
width: '205px',
},
headerMiddle: {
flex: 1,
},
headerLeftLeft: {
flex: 2,
},
headerLeftRight: {
flex: 1,
},
headerRight: {
width: '205px',
},
tableContentTitle: {
fontSize: fontSizes.main,
flexDirection: 'row',
},
tableCellLargeTitle: {
flex: 2,
textAlign: 'center',
borderLeft: '1px solid black',
marginLeft: '-1px',
borderTop: '1px solid black',
marginTop: '-1px',
},
tableCellTitle: {
flex: 1,
textAlign: 'center',
borderLeft: '1px solid black',
marginLeft: '-1px',
borderTop: '1px solid black',
marginTop: '-1px',
},
tableCell2Title: {
flex: 2,
textAlign: 'center',
borderLeft: '1px solid black',
marginLeft: '-1px',
borderTop: '1px solid black',
marginTop: '-1px',
},
tableCellTitleLast: {
flex: 1,
textAlign: 'center',
borderLeft: '1px solid black',
marginLeft: '-1px',
borderTop: '1px solid black',
marginTop: '-1px',
borderRight: '1px solid black',
marginRight: '-1px',
},
tableCell2TitleLast: {
flex: 2,
textAlign: 'center',
borderLeft: '1px solid black',
marginLeft: '-1px',
borderTop: '1px solid black',
marginTop: '-1px',
borderRight: '1px solid black',
marginRight: '-1px',
},
tableContent: {
fontSize: fontSizes.main,
flexDirection: 'row',
},
tableCell: {
flex: 1,
textAlign: 'right',
borderLeft: '1px solid black',
marginLeft: '-1px',
borderTop: '1px solid black',
marginTop: '-1px',
borderBottom: '1px solid black',
},
tableCellNoLeft: {
flex: 1,
textAlign: 'right',
borderTop: '1px solid black',
marginTop: '-1px',
borderBottom: '1px solid black',
},
tableCell2: {
flex: 2,
textAlign: 'right',
borderLeft: '1px solid black',
marginLeft: '-1px',
borderTop: '1px solid black',
marginTop: '-1px',
borderBottom: '1px solid black',
},
tableCellLast: {
flex: 1,
textAlign: 'right',
borderLeft: '1px solid black',
marginLeft: '-1px',
borderTop: '1px solid black',
marginTop: '-1px',
borderRight: '1px solid black',
marginRight: '-1px',
borderBottom: '1px solid black',
},
tableCell2Last: {
flex: 2,
textAlign: 'right',
borderLeft: '1px solid black',
marginLeft: '-1px',
borderTop: '1px solid black',
marginTop: '-1px',
borderRight: '1px solid black',
marginRight: '-1px',
borderBottom: '1px solid black',
},
tableFooter: {
flexDirection: 'row',
},
tableFooterQr: {
width: '50px',
marginLeft: '-50px',
transform: 'translate(50px, 0)',
},
tableFooterLeft: {
flex: 1,
fontSize: fontSizes.main,
borderLeft: '1px solid black',
paddingLeft: '50px',
marginLeft: '-1px',
borderTop: '1px solid black',
marginTop: '-1px',
borderBottom: '1px solid black',
marginBottom: '-1px',
},
tableFooterRight: {
flex: 1,
fontSize: fontSizes.main,
border: '1px solid black',
paddingRight: '50px',
margin: '-1px',
},
sign: {
marginTop: '0px',
flexDirection: 'row',
},
signPart: {
flex: 1,
fontSize: fontSizes.main,
},
});
const isDouble = printStyle.column === 'double';
const date = detail.date;
const number = detail.number;
const origin = detail.original_number;
@ -383,7 +382,7 @@ const PreviewDocument = ({
return (
<Document>
<Page size="A4" style={{ ...styles.page, marginTop: detail.margingTop }}>
<Page orientation={printStyle.orientation} size={printStyle.size} style={{ ...styles.page }}>
<Text style={styles.title}>{recordsName}</Text>
<Text style={styles.subTitle}>{detail.category === RecordCategory.inventory ? '盘点' : outOfStorage}</Text>
<View style={styles.content}>
@ -518,6 +517,7 @@ export const renderItV2 = async (rent: {
priceRule: any[];
isDouble: Number;
printSetup: String;
printStyle: any;
}) => {
const url = 'https://shcx.daoyoucloud.com/admin';
const imageUrl = await QRCode.toDataURL(url);

View File

@ -10,7 +10,12 @@ export class RecordPdfService {
@Db()
private db: Database;
async transformPdfV2(recordData: any, lease_data: any, fee_data: any, options: RecordPdfOptions) {
const { isDouble, printSetup } = options;
const { isDouble, printSetup, styleId } = options;
let printStyle = await this.db.getRepository('printStyles').findById(styleId);
if (!printStyle) {
printStyle = (await this.db.getRepository('printStyles').find())[0];
}
// 直发单不需要打印预览
if (recordData.category === RecordCategory.purchase2lease || recordData.category === RecordCategory.lease2lease)
@ -332,6 +337,7 @@ export class RecordPdfService {
priceRule: make_price,
isDouble,
printSetup,
printStyle,
});
}
}