u
This commit is contained in:
@@ -12,20 +12,15 @@ import CheckCircleIcon from '@mui/icons-material/CheckCircle';
|
|||||||
import CancelScheduleSendOutlinedIcon from '@mui/icons-material/CancelScheduleSendOutlined';
|
import CancelScheduleSendOutlinedIcon from '@mui/icons-material/CancelScheduleSendOutlined';
|
||||||
import { enqueueSnackbar } from 'notistack';
|
import { enqueueSnackbar } from 'notistack';
|
||||||
|
|
||||||
import { labeltemplate, printer, article } from '../../../api';
|
import { labeltemplate, article } from '../../../api';
|
||||||
import { companyAutomat } from '../../../automats';
|
import { companyAutomat } from '../../../automats';
|
||||||
import { notifyError } from '../../../utils/notify';
|
import { notifyError } from '../../../utils/notify';
|
||||||
import BackendError from '../../BackendError';
|
import BackendError from '../../BackendError';
|
||||||
|
|
||||||
function filterZplPrinters(agentprinters, fallbackPrinters = []) {
|
function filterZplPrinters(agentprinters) {
|
||||||
const filteredAgent = (Array.isArray(agentprinters) ? agentprinters : []).filter(
|
return (Array.isArray(agentprinters) ? agentprinters : []).filter(
|
||||||
(p) => p.enabled !== false && (!p.type || p.type.toLowerCase() === 'zpl'),
|
(p) => p.enabled !== false && (!p.type || p.type.toLowerCase() === 'zpl'),
|
||||||
);
|
);
|
||||||
if (filteredAgent.length > 0) return filteredAgent;
|
|
||||||
|
|
||||||
return (Array.isArray(fallbackPrinters) ? fallbackPrinters : []).filter(
|
|
||||||
(p) => !p.type || p.type.toLowerCase() === 'zpl',
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPrinterLabel(p) {
|
function getPrinterLabel(p) {
|
||||||
@@ -52,6 +47,20 @@ function getPrinterLabel(p) {
|
|||||||
return label;
|
return label;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getPrinterLabelLength(printer, livePrinters = []) {
|
||||||
|
if (!printer) return null;
|
||||||
|
const live = (livePrinters || []).find(
|
||||||
|
(lp) =>
|
||||||
|
(lp.agentprinterId && lp.agentprinterId === printer.id) ||
|
||||||
|
(lp.id && lp.id === printer.id) ||
|
||||||
|
(printer.serial && lp.serial && String(printer.serial).toLowerCase() === String(lp.serial).toLowerCase()),
|
||||||
|
);
|
||||||
|
const raw = printer.labelLength ?? live?.labelLength;
|
||||||
|
if (raw == null) return null;
|
||||||
|
const num = Number(raw);
|
||||||
|
return Number.isFinite(num) && num > 0 ? num : null;
|
||||||
|
}
|
||||||
|
|
||||||
export default class ArticleLabelTab extends PureComponent {
|
export default class ArticleLabelTab extends PureComponent {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
@@ -59,20 +68,23 @@ export default class ArticleLabelTab extends PureComponent {
|
|||||||
this.state = {
|
this.state = {
|
||||||
templates: null,
|
templates: null,
|
||||||
printers: initialPrinters,
|
printers: initialPrinters,
|
||||||
|
livePrinters: Array.isArray(companyAutomat.state.livePrinters)
|
||||||
|
? companyAutomat.state.livePrinters
|
||||||
|
: [],
|
||||||
selectedTemplateId: '',
|
selectedTemplateId: '',
|
||||||
selectedPrinterId: initialPrinters.length > 0 ? initialPrinters[0].id : '',
|
selectedPrinterId: initialPrinters.length > 0 ? initialPrinters[0].id : '',
|
||||||
quantity: 1,
|
quantity: 1,
|
||||||
loading: true,
|
loading: true,
|
||||||
error: null,
|
error: null,
|
||||||
};
|
};
|
||||||
this.legacyPrinters = [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.unsub = companyAutomat.subscribe(this, (state) => {
|
this.unsub = companyAutomat.subscribe(this, (state) => {
|
||||||
const zplPrinters = filterZplPrinters(state.agentprinters, this.legacyPrinters);
|
const zplPrinters = filterZplPrinters(state.agentprinters);
|
||||||
this.setState((prev) => ({
|
this.setState((prev) => ({
|
||||||
printers: zplPrinters,
|
printers: zplPrinters,
|
||||||
|
livePrinters: Array.isArray(state.livePrinters) ? state.livePrinters : [],
|
||||||
selectedPrinterId:
|
selectedPrinterId:
|
||||||
prev.selectedPrinterId && zplPrinters.some((p) => p.id === prev.selectedPrinterId)
|
prev.selectedPrinterId && zplPrinters.some((p) => p.id === prev.selectedPrinterId)
|
||||||
? prev.selectedPrinterId
|
? prev.selectedPrinterId
|
||||||
@@ -101,27 +113,16 @@ export default class ArticleLabelTab extends PureComponent {
|
|||||||
this.setState({ loading: true, error: null });
|
this.setState({ loading: true, error: null });
|
||||||
const sku = this.props.article?.sku;
|
const sku = this.props.article?.sku;
|
||||||
try {
|
try {
|
||||||
const [resTemplates] = await Promise.all([
|
const resTemplates = await labeltemplate.list(sku ? { sku } : undefined);
|
||||||
labeltemplate.list(sku ? { sku } : undefined),
|
|
||||||
companyAutomat.actions.loadAgentPrinters().catch(() => companyAutomat.state.agentprinters),
|
|
||||||
]);
|
|
||||||
|
|
||||||
const templates = resTemplates.labeltemplates || [];
|
const templates = resTemplates.labeltemplates || [];
|
||||||
let zplPrinters = filterZplPrinters(companyAutomat.state.agentprinters);
|
const zplPrinters = filterZplPrinters(companyAutomat.state.agentprinters);
|
||||||
|
|
||||||
if (zplPrinters.length === 0) {
|
|
||||||
try {
|
|
||||||
const resPrinters = await printer.list();
|
|
||||||
this.legacyPrinters = (resPrinters.printers || []).filter((p) => p.type === 'zpl');
|
|
||||||
zplPrinters = filterZplPrinters(companyAutomat.state.agentprinters, this.legacyPrinters);
|
|
||||||
} catch {
|
|
||||||
// ignore legacy fallback error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState((prev) => ({
|
this.setState((prev) => ({
|
||||||
templates,
|
templates,
|
||||||
printers: zplPrinters,
|
printers: zplPrinters,
|
||||||
|
livePrinters: Array.isArray(companyAutomat.state.livePrinters)
|
||||||
|
? companyAutomat.state.livePrinters
|
||||||
|
: prev.livePrinters,
|
||||||
selectedTemplateId:
|
selectedTemplateId:
|
||||||
templates.length > 0
|
templates.length > 0
|
||||||
? prev.selectedTemplateId && templates.some((t) => t.id === prev.selectedTemplateId)
|
? prev.selectedTemplateId && templates.some((t) => t.id === prev.selectedTemplateId)
|
||||||
@@ -152,7 +153,6 @@ export default class ArticleLabelTab extends PureComponent {
|
|||||||
await article.printLabel(articleData.sku, {
|
await article.printLabel(articleData.sku, {
|
||||||
templateId: selectedTemplateId,
|
templateId: selectedTemplateId,
|
||||||
agentprinterId: selectedPrinterId,
|
agentprinterId: selectedPrinterId,
|
||||||
printerId: selectedPrinterId,
|
|
||||||
quantity,
|
quantity,
|
||||||
});
|
});
|
||||||
enqueueSnackbar('Druckauftrag erfolgreich gesendet', { variant: 'success' });
|
enqueueSnackbar('Druckauftrag erfolgreich gesendet', { variant: 'success' });
|
||||||
@@ -178,6 +178,7 @@ export default class ArticleLabelTab extends PureComponent {
|
|||||||
const {
|
const {
|
||||||
templates,
|
templates,
|
||||||
printers,
|
printers,
|
||||||
|
livePrinters,
|
||||||
selectedTemplateId,
|
selectedTemplateId,
|
||||||
selectedPrinterId,
|
selectedPrinterId,
|
||||||
quantity,
|
quantity,
|
||||||
@@ -185,6 +186,9 @@ export default class ArticleLabelTab extends PureComponent {
|
|||||||
error,
|
error,
|
||||||
} = this.state;
|
} = this.state;
|
||||||
|
|
||||||
|
const currentPrinter = (printers || []).find((p) => p.id === selectedPrinterId);
|
||||||
|
const printerLabelLength = getPrinterLabelLength(currentPrinter, livePrinters);
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<Box sx={{ p: 4, display: 'flex', justifyContent: 'center' }}>
|
<Box sx={{ p: 4, display: 'flex', justifyContent: 'center' }}>
|
||||||
@@ -227,6 +231,16 @@ export default class ArticleLabelTab extends PureComponent {
|
|||||||
<Grid container spacing={2}>
|
<Grid container spacing={2}>
|
||||||
{templates.map((t) => {
|
{templates.map((t) => {
|
||||||
const isSelected = t.id === selectedTemplateId;
|
const isSelected = t.id === selectedTemplateId;
|
||||||
|
const dpi = t.dpi === 300 ? 300 : 203;
|
||||||
|
const tmplHeight = t.height || 200;
|
||||||
|
const tmplWidth = t.width || 448;
|
||||||
|
const hasPrinterLength = printerLabelLength != null && printerLabelLength > 0;
|
||||||
|
const totalHeight = hasPrinterLength ? Math.max(tmplHeight, printerLabelLength) : tmplHeight;
|
||||||
|
const isCutoff = hasPrinterLength && printerLabelLength < tmplHeight;
|
||||||
|
const outlineColor = isCutoff ? '#d32f2f' : '#1976d2';
|
||||||
|
const tmplHeightPercent = (tmplHeight / totalHeight) * 100;
|
||||||
|
const printerHeightPercent = hasPrinterLength ? (printerLabelLength / totalHeight) * 100 : 100;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid size={{ xs: 12, sm: 6, md: 4 }} key={t.id}>
|
<Grid size={{ xs: 12, sm: 6, md: 4 }} key={t.id}>
|
||||||
<Paper
|
<Paper
|
||||||
@@ -272,18 +286,81 @@ export default class ArticleLabelTab extends PureComponent {
|
|||||||
bgcolor: 'background.default',
|
bgcolor: 'background.default',
|
||||||
borderRadius: 1,
|
borderRadius: 1,
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
|
position: 'relative',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t.thumb ? (
|
{t.thumb ? (
|
||||||
<img
|
<Box
|
||||||
src={`data:image/png;base64,${t.thumb}`}
|
sx={{
|
||||||
alt={t.name}
|
position: 'relative',
|
||||||
style={{
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
alignItems: 'center',
|
||||||
maxWidth: '100%',
|
maxWidth: '100%',
|
||||||
maxHeight: '100%',
|
maxHeight: '100%',
|
||||||
objectFit: 'contain',
|
aspectRatio: `${tmplWidth} / ${totalHeight}`,
|
||||||
|
boxSizing: 'border-box',
|
||||||
|
bgcolor: '#fff',
|
||||||
|
borderRadius: 0.5,
|
||||||
|
boxShadow: '0 1px 2px rgba(0,0,0,0.1)',
|
||||||
}}
|
}}
|
||||||
/>
|
>
|
||||||
|
{/* Template preview image */}
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
width: '100%',
|
||||||
|
height: `${tmplHeightPercent}%`,
|
||||||
|
position: 'relative',
|
||||||
|
display: 'flex',
|
||||||
|
overflow: 'hidden',
|
||||||
|
borderRadius: 0.5,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src={`data:image/png;base64,${t.thumb}`}
|
||||||
|
alt={t.name}
|
||||||
|
style={{
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
objectFit: 'contain',
|
||||||
|
display: 'block',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{/* If template exceeds printer label length, shade the cutoff overflow */}
|
||||||
|
{isCutoff && (
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
position: 'absolute',
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
top: `${(printerLabelLength / tmplHeight) * 100}%`,
|
||||||
|
bottom: 0,
|
||||||
|
bgcolor: 'rgba(211, 47, 47, 0.22)',
|
||||||
|
zIndex: 1,
|
||||||
|
pointerEvents: 'none',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* Dotted outline for printer label length */}
|
||||||
|
{hasPrinterLength && (
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
position: 'absolute',
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
height: `${printerHeightPercent}%`,
|
||||||
|
border: `2px dotted ${outlineColor}`,
|
||||||
|
borderRadius: 0.5,
|
||||||
|
pointerEvents: 'none',
|
||||||
|
boxSizing: 'border-box',
|
||||||
|
zIndex: 2,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
) : (
|
) : (
|
||||||
<Typography variant="caption" color="text.disabled">
|
<Typography variant="caption" color="text.disabled">
|
||||||
Keine Vorschau
|
Keine Vorschau
|
||||||
@@ -295,7 +372,7 @@ export default class ArticleLabelTab extends PureComponent {
|
|||||||
{t.name}
|
{t.name}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="caption" color="text.secondary">
|
<Typography variant="caption" color="text.secondary">
|
||||||
{t.width}x{t.height} ({t.dpi} dpi)
|
{t.width}x{t.height} ({dpi} dpi)
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
</Paper>
|
</Paper>
|
||||||
@@ -314,11 +391,14 @@ export default class ArticleLabelTab extends PureComponent {
|
|||||||
onChange={(e) => this.setState({ selectedPrinterId: e.target.value })}
|
onChange={(e) => this.setState({ selectedPrinterId: e.target.value })}
|
||||||
sx={{ minWidth: 200 }}
|
sx={{ minWidth: 200 }}
|
||||||
>
|
>
|
||||||
{printers.map((p) => (
|
{printers.map((p) => {
|
||||||
<MenuItem key={p.id} value={p.id}>
|
const len = getPrinterLabelLength(p, livePrinters);
|
||||||
{getPrinterLabel(p)}
|
return (
|
||||||
</MenuItem>
|
<MenuItem key={p.id} value={p.id}>
|
||||||
))}
|
{getPrinterLabel(p)}{len != null ? ` (${len} px)` : ''}
|
||||||
|
</MenuItem>
|
||||||
|
);
|
||||||
|
})}
|
||||||
</TextInput>
|
</TextInput>
|
||||||
|
|
||||||
<TextInput
|
<TextInput
|
||||||
|
|||||||
@@ -30,22 +30,17 @@ import { backendErrorFrom } from '../../utils/backendError';
|
|||||||
import { notifyError } from '../../utils/notify';
|
import { notifyError } from '../../utils/notify';
|
||||||
import { setLastArticleSku } from '../../automats/navigationAutomat';
|
import { setLastArticleSku } from '../../automats/navigationAutomat';
|
||||||
import companyAutomat from '../../automats/companyAutomat';
|
import companyAutomat from '../../automats/companyAutomat';
|
||||||
import { labeltemplate, printer } from '../../api';
|
import { labeltemplate } from '../../api';
|
||||||
import { enqueueSnackbar } from 'notistack';
|
import { enqueueSnackbar } from 'notistack';
|
||||||
import {
|
import {
|
||||||
BLUE_BG,
|
BLUE_BG,
|
||||||
SURFACE_BASE,
|
SURFACE_BASE,
|
||||||
} from '../../colors';
|
} from '../../colors';
|
||||||
|
|
||||||
function filterZplPrinters(agentprinters, fallbackPrinters = []) {
|
function filterZplPrinters(agentprinters) {
|
||||||
const filteredAgent = (Array.isArray(agentprinters) ? agentprinters : []).filter(
|
return (Array.isArray(agentprinters) ? agentprinters : []).filter(
|
||||||
(p) => p.enabled !== false && (!p.type || p.type.toLowerCase() === 'zpl'),
|
(p) => p.enabled !== false && (!p.type || p.type.toLowerCase() === 'zpl'),
|
||||||
);
|
);
|
||||||
if (filteredAgent.length > 0) return filteredAgent;
|
|
||||||
|
|
||||||
return (Array.isArray(fallbackPrinters) ? fallbackPrinters : []).filter(
|
|
||||||
(p) => !p.type || p.type.toLowerCase() === 'zpl',
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPrinterLabel(p) {
|
function getPrinterLabel(p) {
|
||||||
@@ -134,7 +129,6 @@ class ArtikelVorlagenPage extends PureComponent {
|
|||||||
};
|
};
|
||||||
this._cancelled = false;
|
this._cancelled = false;
|
||||||
this._currentEditId = null;
|
this._currentEditId = null;
|
||||||
this._legacyPrinters = [];
|
|
||||||
this.handleRetry = this.handleRetry.bind(this);
|
this.handleRetry = this.handleRetry.bind(this);
|
||||||
this.handleOpenNew = this.handleOpenNew.bind(this);
|
this.handleOpenNew = this.handleOpenNew.bind(this);
|
||||||
this.handleOpenEdit = this.handleOpenEdit.bind(this);
|
this.handleOpenEdit = this.handleOpenEdit.bind(this);
|
||||||
@@ -154,10 +148,8 @@ class ArtikelVorlagenPage extends PureComponent {
|
|||||||
this._cancelled = false;
|
this._cancelled = false;
|
||||||
void this.loadTemplates();
|
void this.loadTemplates();
|
||||||
this.unsubPrinters = companyAutomat.subscribe(this, (state) => ({
|
this.unsubPrinters = companyAutomat.subscribe(this, (state) => ({
|
||||||
printers: filterZplPrinters(state.agentprinters, this._legacyPrinters),
|
printers: filterZplPrinters(state.agentprinters),
|
||||||
}));
|
}));
|
||||||
void companyAutomat.actions.loadAgentPrinters().catch(() => {});
|
|
||||||
void this.loadFallbackPrinters();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
@@ -165,21 +157,6 @@ class ArtikelVorlagenPage extends PureComponent {
|
|||||||
this.unsubPrinters?.();
|
this.unsubPrinters?.();
|
||||||
}
|
}
|
||||||
|
|
||||||
async loadFallbackPrinters() {
|
|
||||||
try {
|
|
||||||
const resPrinters = await printer.list();
|
|
||||||
this._legacyPrinters = (resPrinters.printers || []).filter(
|
|
||||||
(p) => !p.type || p.type.toLowerCase() === 'zpl',
|
|
||||||
);
|
|
||||||
if (this._cancelled) return;
|
|
||||||
this.setState({
|
|
||||||
printers: filterZplPrinters(companyAutomat.state.agentprinters, this._legacyPrinters),
|
|
||||||
});
|
|
||||||
} catch {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async loadTemplates() {
|
async loadTemplates() {
|
||||||
this.setState({ status: 'loading', error: null });
|
this.setState({ status: 'loading', error: null });
|
||||||
try {
|
try {
|
||||||
@@ -358,8 +335,7 @@ class ArtikelVorlagenPage extends PureComponent {
|
|||||||
this.setState({ printing: true });
|
this.setState({ printing: true });
|
||||||
try {
|
try {
|
||||||
const payload = {
|
const payload = {
|
||||||
printerId: targetPrinter.id,
|
agentprinterId: targetPrinter.id,
|
||||||
agentprinterId: targetPrinter.printeragentId || targetPrinter.id,
|
|
||||||
templateId: editorTemplate?.id,
|
templateId: editorTemplate?.id,
|
||||||
name: editorName,
|
name: editorName,
|
||||||
width: editorWidth,
|
width: editorWidth,
|
||||||
|
|||||||
Reference in New Issue
Block a user