Produktion+neuauftrag: Neu generieren, Einzelfelder, Formate je Produkt + getrennt aktivierbar
- orders: /regenerate (Schriftstueck+Kuvert neu generieren). - produktion: 'Neu generieren'-Button im Empfaenger-Dialog + Massenauswahl. - neuauftrag: Adressmodus 'Einzelfelder' (Vorname..Land) inkl. Excel-Import; Formate nach gewaehltem Produkt gefiltert + nur show_manual. - bootstrap: formats.show_manual (getrennt von active=Konfigurator). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
1b2541e307
commit
de612b713f
4 files changed
+70
-11
No files matched your search
@@ -93,7 +93,7 @@ const NeuAuftrag = defineComponent({
|
||||
try {
|
||||
const [p, f, ps, mt, mtx, sg] = await Promise.all([
|
||||
api.get('/items/products', { params: { limit: -1, filter: { active: { _eq: true }, type: { _in: ['letter', 'postcard'] } }, fields: 'key,name,type' } }),
|
||||
api.get('/items/formats', { params: { limit: -1, filter: { active: { _eq: true } }, fields: 'key,name,product.key' } }),
|
||||
api.get('/items/formats', { params: { limit: -1, fields: '*,product.key' } }),
|
||||
api.get('/items/pricing_settings', { params: { fields: 'char_whitelist' } }).catch(() => ({ data: { data: {} } })),
|
||||
api.get('/items/muster_settings', { params: { fields: 'text_du,text_sie' } }).catch(() => ({ data: { data: {} } })),
|
||||
api.get('/items/muster_texts', { params: { limit: -1, filter: { active: { _eq: true } }, sort: 'sort', fields: 'id,label,text' } }).catch(() => ({ data: { data: [] } })),
|
||||
@@ -158,9 +158,10 @@ const NeuAuftrag = defineComponent({
|
||||
setTimeout(() => { if (neu.hinweis.includes(einmalig)) neu.hinweis = ''; }, 4000);
|
||||
return String(v).replace(verbotenRe.value, '');
|
||||
};
|
||||
// Alle aktiven Formate zur Auswahl (nicht aufs Produkt eingeschränkt) –
|
||||
// so lassen sich auch freie/eigene Formate direkt wählen.
|
||||
const neuFormate = () => formate.value;
|
||||
// Nur im manuellen Druck sichtbare Formate (show_manual) und passend zum
|
||||
// gewählten Produkt (Formate ohne Produktbindung gelten für alle).
|
||||
const neuFormate = () => formate.value.filter((f) =>
|
||||
f.show_manual !== false && (!f.product?.key || f.product.key === neu.product));
|
||||
// Wie viele Adresszeilen je Empfänger: 5 („5 Zeilen") bzw. 1 („Individueller Text").
|
||||
const zeilenAnzahl = () => (neu.adressModus === 'individuell' ? 1 : 5);
|
||||
const freitext = (e, z) => (String(e.free_text || '').split('\n')[z] ?? '');
|
||||
@@ -172,6 +173,12 @@ const NeuAuftrag = defineComponent({
|
||||
neu.rows[i].free_text = zeilen.slice(0, max).join('\n').replace(/\n+$/, '');
|
||||
neu.previewSession = null;
|
||||
};
|
||||
// Einzelfeld-Modus: strukturierte Adressfelder je Empfänger (statt freier Zeilen).
|
||||
const FELDER = [['first_name', 'Vorname'], ['last_name', 'Nachname'], ['street', 'Straße'], ['house_no', 'Nr.'], ['zip', 'PLZ'], ['city', 'Stadt'], ['country', 'Land']];
|
||||
const setFeld = (i, key, v) => {
|
||||
neu.rows[i] = { ...neu.rows[i], [key]: saeubere(String(v).replace(/[\r\n]/g, '')) };
|
||||
neu.previewSession = null;
|
||||
};
|
||||
// Individuelle Platzhalter je Empfänger (z. B. [[Gutschein]]).
|
||||
const setPlatzhalter = (i, name, v) => {
|
||||
neu.rows[i].placeholders = { ...(neu.rows[i].placeholders || {}), [name]: saeubere(v) };
|
||||
@@ -201,8 +208,10 @@ const NeuAuftrag = defineComponent({
|
||||
};
|
||||
const addZeile = () => neu.rows.push(leereZeile());
|
||||
const delZeile = (i) => { neu.rows.splice(i, 1); if (!neu.rows.length) neu.rows.push(leereZeile()); };
|
||||
// Empfänger zählt, wenn eine Adresszeile ODER ein Platzhalterwert gefüllt ist.
|
||||
// Empfänger zählt, wenn eine Adresszeile/ein Feld ODER ein Platzhalterwert gefüllt ist.
|
||||
const felderGefuellt = (e) => FELDER.some(([k]) => String(e[k] || '').trim());
|
||||
const entries = () => neu.rows.filter((e) => String(e.free_text || '').trim()
|
||||
|| felderGefuellt(e)
|
||||
|| (e.placeholders && Object.values(e.placeholders).some((v) => String(v || '').trim())));
|
||||
|
||||
// Aus Excel/CSV eingefügte Zeilen übernehmen. Erst die individuellen
|
||||
@@ -216,7 +225,12 @@ const NeuAuftrag = defineComponent({
|
||||
const zellen = z.split(/\t|;|,/).map((c) => saeubere(c.trim()));
|
||||
const row = leereZeile();
|
||||
ph.forEach((name, i) => { row.placeholders = { ...row.placeholders, [name]: zellen[i] || '' }; });
|
||||
row.free_text = zellen.slice(ph.length, ph.length + max).join('\n');
|
||||
if (neu.adressModus === 'felder') {
|
||||
// Spalten nach den Platzhaltern → Vorname, Nachname, Straße, Nr., PLZ, Stadt, Land.
|
||||
FELDER.forEach(([key], i) => { row[key] = zellen[ph.length + i] || ''; });
|
||||
} else {
|
||||
row.free_text = zellen.slice(ph.length, ph.length + max).join('\n');
|
||||
}
|
||||
return row;
|
||||
});
|
||||
neu.rows = rows;
|
||||
@@ -460,8 +474,11 @@ const NeuAuftrag = defineComponent({
|
||||
const zeile = (e, i) => [
|
||||
...customPlaceholders().map((name) => feld(name, e.placeholders?.[name] || '', (ev) => setPlatzhalter(i, name, ev.target.value), '',
|
||||
(ev) => { if (spalteEinfuegen(i, (ri, v) => setPlatzhalter(ri, name, v), ev.clipboardData && ev.clipboardData.getData('text'))) ev.preventDefault(); })),
|
||||
...Array.from({ length: zeilenAnzahl() }, (_, z) => feld('Zeile ' + (z + 1), freitext(e, z), (ev) => setFreitext(i, z, ev.target.value), '',
|
||||
(ev) => { if (spalteEinfuegen(i, (ri, v) => setFreitext(ri, z, v), ev.clipboardData && ev.clipboardData.getData('text'))) ev.preventDefault(); })),
|
||||
...(neu.adressModus === 'felder'
|
||||
? FELDER.map(([key, lbl]) => feld(lbl, e[key] || '', (ev) => setFeld(i, key, ev.target.value), '',
|
||||
(ev) => { if (spalteEinfuegen(i, (ri, v) => setFeld(ri, key, v), ev.clipboardData && ev.clipboardData.getData('text'))) ev.preventDefault(); }))
|
||||
: Array.from({ length: zeilenAnzahl() }, (_, z) => feld('Zeile ' + (z + 1), freitext(e, z), (ev) => setFreitext(i, z, ev.target.value), '',
|
||||
(ev) => { if (spalteEinfuegen(i, (ri, v) => setFreitext(ri, z, v), ev.clipboardData && ev.clipboardData.getData('text'))) ev.preventDefault(); }))),
|
||||
];
|
||||
|
||||
// Bereich 1 – Produkt
|
||||
@@ -497,7 +514,7 @@ const NeuAuftrag = defineComponent({
|
||||
const b2 = h('div', { style: BEREICH }, [
|
||||
h('div', { style: 'display:flex;justify-content:space-between;align-items:center;gap:10px;flex-wrap:wrap;margin-bottom:14px;' }, [
|
||||
bereichKopf('✉ Kuvert'),
|
||||
h('div', { style: 'width:300px;' }, [segToggle(neu.adressModus, [{ key: '5zeilen', label: '5 Zeilen' }, { key: 'individuell', label: 'Individueller Text' }], (k) => { neu.adressModus = k; neu.previewSession = null; })]),
|
||||
h('div', { style: 'width:420px;max-width:100%;' }, [segToggle(neu.adressModus, [{ key: '5zeilen', label: '5 Zeilen' }, { key: 'felder', label: 'Einzelfelder' }, { key: 'individuell', label: 'Ind. Text' }], (k) => { neu.adressModus = k; neu.previewSession = null; })]),
|
||||
]),
|
||||
h('div', { style: 'display:flex;flex-direction:column;gap:8px;max-height:34vh;overflow:auto;' },
|
||||
neu.rows.map((e, i) => h('div', { style: 'display:flex;gap:8px;align-items:center;' }, [
|
||||
|
||||
Reference in new issue
Block a user