u
This commit is contained in:
@@ -17,6 +17,7 @@ export { posterminal } from './posterminal.js';
|
||||
export { printer } from './printer.js';
|
||||
export { printeragent } from './printeragent.js';
|
||||
export { agentprinter } from './agentprinter.js';
|
||||
export { printerjob } from './printerjob.js';
|
||||
export { propertyname } from './propertyname.js';
|
||||
export { quote } from './quote.js';
|
||||
export { retoure } from './retoure.js';
|
||||
|
||||
100
src/api/printerjob.js
Normal file
100
src/api/printerjob.js
Normal file
@@ -0,0 +1,100 @@
|
||||
import { http } from './http.js';
|
||||
|
||||
export const printerjob = {
|
||||
/**
|
||||
* POST /api/zpljob
|
||||
* @param {{ agentprinterId: number, data: string, copiescount?: number }} payload
|
||||
* → { printerjob: PrinterJob }
|
||||
*/
|
||||
createZplJob({ agentprinterId, data, copiescount = 1 }) {
|
||||
return http('/api/zpljob', {
|
||||
method: 'POST',
|
||||
body: {
|
||||
agentprinterId: Number(agentprinterId),
|
||||
data: String(data),
|
||||
copiescount: Number(copiescount) || 1,
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Sends a minimal ZPL test label to a specific agent printer.
|
||||
* @param {number} agentprinterId
|
||||
* @param {{ model?: string }} [options]
|
||||
* → { printerjob: PrinterJob }
|
||||
*/
|
||||
sendTestZpl(agentprinterId, { model = 'Zebra' } = {}) {
|
||||
const timeStr = new Date().toLocaleTimeString('de-DE');
|
||||
const safeModel = String(model || 'Drucker').replace(/[\^~]/g, '');
|
||||
const zpl = [
|
||||
'^XA',
|
||||
'^FO40,40^ADN,36,20^FDTestdruck OK^FS',
|
||||
`^FO40,85^ADN,18,10^FD${safeModel}^FS`,
|
||||
`^FO40,115^ADN,18,10^FDID: ${agentprinterId} - ${timeStr}^FS`,
|
||||
'^XZ',
|
||||
].join('\n');
|
||||
return this.createZplJob({
|
||||
agentprinterId,
|
||||
data: zpl,
|
||||
copiescount: 1,
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* GET /api/printerjob
|
||||
* @param {{ agentprinterId?: number, state?: string }} [query]
|
||||
* → { printerjobs: PrinterJob[] }
|
||||
*/
|
||||
list(query = {}) {
|
||||
const params = new URLSearchParams();
|
||||
if (query.agentprinterId != null) params.set('agentprinterId', String(query.agentprinterId));
|
||||
if (query.state != null) params.set('state', String(query.state));
|
||||
const qs = params.toString();
|
||||
return http(qs ? `/api/printerjob?${qs}` : '/api/printerjob');
|
||||
},
|
||||
|
||||
/**
|
||||
* GET /api/printerjob/:id
|
||||
* → { printerjob: PrinterJob }
|
||||
*/
|
||||
get(id) {
|
||||
return http(`/api/printerjob/${id}`);
|
||||
},
|
||||
|
||||
/**
|
||||
* POST /api/printerjob
|
||||
* @param {{ agentprinterId: number, type?: 'zpl'|'pdf'|'epos', data: string }} payload
|
||||
* → { printerjob: PrinterJob }
|
||||
*/
|
||||
create({ agentprinterId, type = 'zpl', data }) {
|
||||
return http('/api/printerjob', {
|
||||
method: 'POST',
|
||||
body: {
|
||||
agentprinterId: Number(agentprinterId),
|
||||
type,
|
||||
data,
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* POST /api/printerjob/:id/cancel
|
||||
* → { success: true, printerjob: PrinterJob }
|
||||
*/
|
||||
cancel(id) {
|
||||
return http(`/api/printerjob/${id}/cancel`, {
|
||||
method: 'POST',
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* DELETE /api/printerjob/:id
|
||||
* → { success: true, deletedJob: PrinterJob }
|
||||
*/
|
||||
delete(id) {
|
||||
return http(`/api/printerjob/${id}`, {
|
||||
method: 'DELETE',
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
@@ -28,6 +28,7 @@ import {
|
||||
printer as printerApi,
|
||||
printeragent as printeragentApi,
|
||||
agentprinter as agentprinterApi,
|
||||
printerjob as printerjobApi,
|
||||
supplier as supplierApi,
|
||||
unit as unitApi,
|
||||
warehouse as warehouseApi,
|
||||
@@ -876,6 +877,14 @@ const actions = {
|
||||
});
|
||||
},
|
||||
|
||||
async sendTestPrint(agentprinterId, options = {}) {
|
||||
return printerjobApi.sendTestZpl(agentprinterId, options);
|
||||
},
|
||||
|
||||
async createZplJob(payload) {
|
||||
return printerjobApi.createZplJob(payload);
|
||||
},
|
||||
|
||||
async loadLivePrinters() {
|
||||
const companyId =
|
||||
authAutomat.state.user?.selectedCompanyId ?? companyAutomat.state.current?.id;
|
||||
|
||||
@@ -120,7 +120,14 @@ class AgentQrCode extends PureComponent {
|
||||
}
|
||||
|
||||
function renderPrinterDiagnostics(printer, live) {
|
||||
if (!live) {
|
||||
const isOnline = printer?.online ?? (live ? !live.unreachable && live.status !== 'offline' : false);
|
||||
const isOpen = printer?.open ?? (live?.errors?.headOpen || live?.headOpen || false);
|
||||
const isPaused = printer?.pause ?? (live?.errors?.pause || live?.pause || false);
|
||||
const isError = printer?.error ?? (live?.errors?.other || live?.error || false);
|
||||
const isUnreachable = !isOnline || (live?.errors?.unreachable || false);
|
||||
const labelLength = printer?.labelLength ?? live?.labelLength;
|
||||
|
||||
if (!isOnline) {
|
||||
return (
|
||||
<Chip
|
||||
label="Offline"
|
||||
@@ -132,9 +139,8 @@ function renderPrinterDiagnostics(printer, live) {
|
||||
);
|
||||
}
|
||||
|
||||
const errors = live.errors || {};
|
||||
const errorChips = [];
|
||||
if (errors.headOpen) {
|
||||
if (isOpen) {
|
||||
errorChips.push(
|
||||
<Chip
|
||||
key="headOpen"
|
||||
@@ -145,7 +151,7 @@ function renderPrinterDiagnostics(printer, live) {
|
||||
/>,
|
||||
);
|
||||
}
|
||||
if (errors.pause) {
|
||||
if (isPaused) {
|
||||
errorChips.push(
|
||||
<Chip
|
||||
key="pause"
|
||||
@@ -156,7 +162,7 @@ function renderPrinterDiagnostics(printer, live) {
|
||||
/>,
|
||||
);
|
||||
}
|
||||
if (errors.unreachable) {
|
||||
if (isUnreachable) {
|
||||
errorChips.push(
|
||||
<Chip
|
||||
key="unreachable"
|
||||
@@ -167,7 +173,7 @@ function renderPrinterDiagnostics(printer, live) {
|
||||
/>,
|
||||
);
|
||||
}
|
||||
if (errors.other) {
|
||||
if (isError) {
|
||||
errorChips.push(
|
||||
<Chip
|
||||
key="other"
|
||||
@@ -192,9 +198,9 @@ function renderPrinterDiagnostics(printer, live) {
|
||||
variant="outlined"
|
||||
sx={{ fontSize: '0.7rem', height: 20, fontWeight: 600 }}
|
||||
/>
|
||||
{live.labelLength != null ? (
|
||||
{labelLength != null ? (
|
||||
<Chip
|
||||
label={`Etikett: ${live.labelLength} px`}
|
||||
label={`Etikett: ${labelLength} px`}
|
||||
size="small"
|
||||
variant="outlined"
|
||||
sx={{ fontSize: '0.7rem', height: 20 }}
|
||||
@@ -227,6 +233,7 @@ export default class PrinterAgentSettingsPanel extends PureComponent {
|
||||
editingId: null,
|
||||
editNameDraft: '',
|
||||
sortDrafts: {},
|
||||
testingPrinterId: null,
|
||||
};
|
||||
this.handleRetry = this.handleRetry.bind(this);
|
||||
this.handleCreateAgent = this.handleCreateAgent.bind(this);
|
||||
@@ -241,6 +248,7 @@ export default class PrinterAgentSettingsPanel extends PureComponent {
|
||||
this.handleTogglePrinterEnabled = this.handleTogglePrinterEnabled.bind(this);
|
||||
this.handleMovePrinter = this.handleMovePrinter.bind(this);
|
||||
this.handleDeletePrinter = this.handleDeletePrinter.bind(this);
|
||||
this.handleTestPrint = this.handleTestPrint.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
@@ -467,6 +475,24 @@ export default class PrinterAgentSettingsPanel extends PureComponent {
|
||||
}
|
||||
}
|
||||
|
||||
async handleTestPrint(printer) {
|
||||
if (!printer?.id) return;
|
||||
this.setState({ testingPrinterId: printer.id });
|
||||
try {
|
||||
await companyAutomat.actions.sendTestPrint(printer.id, {
|
||||
model: printer.model || printer.type || 'Zebra',
|
||||
});
|
||||
enqueueSnackbar(
|
||||
`Testdruck für ${printer.model || 'Drucker'} (#${printer.id}) an Drucker-Warteschlange gesendet.`,
|
||||
{ variant: 'success' },
|
||||
);
|
||||
} catch (err) {
|
||||
notifyError(err);
|
||||
} finally {
|
||||
this.setState({ testingPrinterId: null });
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
error,
|
||||
@@ -479,6 +505,7 @@ export default class PrinterAgentSettingsPanel extends PureComponent {
|
||||
patchingAgentId,
|
||||
editingId,
|
||||
editNameDraft,
|
||||
testingPrinterId,
|
||||
} = this.state;
|
||||
|
||||
if (error && printeragents.length === 0) {
|
||||
@@ -564,8 +591,6 @@ export default class PrinterAgentSettingsPanel extends PureComponent {
|
||||
const isEditing = editingId === agent.id;
|
||||
const isPaired = agent.pairedAt != null;
|
||||
const isEnabled = agent.enabled !== false;
|
||||
const clientState = agent.clientstate;
|
||||
const isOnline = clientState === 'online';
|
||||
const pairedDateText = formatDateTime(agent.pairedAt);
|
||||
const lastseenText = formatDateTime(agent.lastseenAt) ?? 'Nie';
|
||||
const updatedText = formatDateTime(agent.updatedAt) ?? '—';
|
||||
@@ -700,17 +725,6 @@ export default class PrinterAgentSettingsPanel extends PureComponent {
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Live connection state */}
|
||||
{clientState ? (
|
||||
<Chip
|
||||
label={isOnline ? 'Online' : 'Offline'}
|
||||
size="small"
|
||||
variant="outlined"
|
||||
color={isOnline ? 'success' : 'default'}
|
||||
sx={{ fontSize: '0.75rem', fontWeight: 600 }}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{/* Agent version */}
|
||||
{agent.agentversion ? (
|
||||
<Tooltip title="Agent Software-Version">
|
||||
@@ -931,6 +945,30 @@ export default class PrinterAgentSettingsPanel extends PureComponent {
|
||||
</Box>
|
||||
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
|
||||
{/* Test print button */}
|
||||
<Tooltip title="Test-Etikett an Drucker senden (ZPL)">
|
||||
<span>
|
||||
<Button
|
||||
size="small"
|
||||
variant="outlined"
|
||||
color="primary"
|
||||
startIcon={<PrintOutlinedIcon sx={{ fontSize: 15 }} />}
|
||||
disabled={testingPrinterId === p.id}
|
||||
onClick={() => void this.handleTestPrint(p)}
|
||||
sx={{
|
||||
textTransform: 'none',
|
||||
fontSize: '0.75rem',
|
||||
py: 0.25,
|
||||
px: 1,
|
||||
minHeight: 26,
|
||||
fontWeight: 600,
|
||||
}}
|
||||
>
|
||||
{testingPrinterId === p.id ? 'Druckt…' : 'Testdruck'}
|
||||
</Button>
|
||||
</span>
|
||||
</Tooltip>
|
||||
|
||||
{/* Enabled toggle switch */}
|
||||
<FormControlLabel
|
||||
control={
|
||||
|
||||
Reference in New Issue
Block a user