Archiv: Datei-Badge, Bestellungen: Preiskategorie als Festpreis übernehmen

This commit is contained in:
2026-05-28 13:12:01 +02:00
parent a3cf805f0b
commit cab9659709
3 changed files with 48 additions and 10 deletions

View File

@@ -5,7 +5,27 @@ const { authenticate } = require('../../middleware/auth');
const router = express.Router();
router.get('/', authenticate, (req, res) => {
res.json(db.prepare('SELECT * FROM calculations WHERE user_id=? ORDER BY created_at DESC').all(req.user.id));
const uid = req.user.id;
const items = db.prepare('SELECT * FROM calculations WHERE user_id=? ORDER BY created_at DESC').all(uid);
// Prüfen welche Modelle Dateien haben: Unterordner von "3D-Modelle" mit Dateien
const baseFolder = db.prepare(
"SELECT id FROM folders WHERE user_id=? AND name='3D-Modelle' AND parent_id IS NULL"
).get(uid);
let filesMap = {};
if (baseFolder) {
const rows = db.prepare(`
SELECT f.name, COUNT(fi.id) AS cnt
FROM folders f
LEFT JOIN files fi ON fi.folder_id = f.id
WHERE f.parent_id = ? AND f.user_id = ?
GROUP BY f.id
`).all(baseFolder.id, uid);
for (const r of rows) filesMap[r.name] = r.cnt > 0;
}
res.json(items.map(i => ({ ...i, has_files: !!filesMap[i.name] })));
});
router.post('/', authenticate, (req, res) => {

View File

@@ -375,15 +375,25 @@ function BestellungDetail({ id, toast, onBack }) {
<div style={{...S.card,marginBottom:10}}>
<div style={S.head}>GESAMTSUMME</div>
<div style={{display:'grid',gridTemplateColumns:'1fr 1fr 1fr',gap:8,marginBottom:totals.has_any_custom||order.custom_price?12:0}}>
{PREISE.map(p=>(
<div key={p.key} style={{background:`${p.c}10`,border:`1px solid ${p.c}30`,borderRadius:9,padding:'10px 8px',textAlign:'center'}}>
{PREISE.map(p=>{
const canSelect = !order.bezahlt && order.custom_price == null && !totals.has_any_custom;
return (
<div key={p.key}
onClick={() => canSelect && api(`/tools/bestellungen/${id}`,{method:'PUT',body:{custom_price:totals[p.key]}}).then(u=>{setOrder(u);setForm(f=>({...f,custom_price:totals[p.key].toFixed(2)}));toast(`${p.label}-Preis übernommen`);}).catch(e=>toast(e.message,'error'))}
title={canSelect ? `${p.label}-Preis als Festpreis übernehmen` : undefined}
style={{background:`${p.c}10`,border:`1px solid ${p.c}30`,borderRadius:9,padding:'10px 8px',textAlign:'center',
cursor:canSelect?'pointer':'default',
transition:'background 0.15s',
...(canSelect?{':hover':{background:`${p.c}20`}}:{})}}>
<div style={{fontSize:16,marginBottom:2}}>{p.emoji}</div>
<div style={{color:'rgba(255,255,255,0.6)',fontSize:9,fontFamily:'monospace',marginBottom:3}}>{p.label}</div>
<div style={{color:p.c,fontFamily:"'Space Mono',monospace",fontSize:16,fontWeight:700}}>
{totals[p.key].toFixed(2)}
</div>
{canSelect && <div style={{color:`${p.c}80`,fontSize:8,fontFamily:'monospace',marginTop:3}}> übernehmen</div>}
</div>
))}
);
})}
</div>
{totals.has_any_custom && (
<div style={{padding:'10px 14px',background:'rgba(255,255,255,0.04)',border:'1px solid rgba(255,255,255,0.1)',borderRadius:8,display:'flex',justifyContent:'space-between',alignItems:'center',marginBottom:8}}>

View File

@@ -633,7 +633,15 @@ export function SavedList({ toast, mobile }) {
<div style={{ flex:1, minWidth:0 }}>
{/* Name + Datum */}
<div style={{ display:'flex', justifyContent:'space-between', alignItems:'flex-start', marginBottom:4 }}>
<div style={{ display:'flex', alignItems:'center', gap:6 }}>
<div style={{ color:'#fff', fontFamily:'monospace', fontSize:13, fontWeight:700 }}>{item.name}</div>
{item.has_files && (
<span title="3D-Dateien vorhanden"
style={{ fontSize:11, background:'rgba(78,205,196,0.12)', border:'1px solid rgba(78,205,196,0.25)',
borderRadius:5, padding:'1px 5px', color:'#4ecdc4', fontFamily:'monospace', fontSize:9,
letterSpacing:0.5, flexShrink:0 }}>🖨 Dateien</span>
)}
</div>
<div style={{ color:'rgba(255,255,255,0.5)', fontFamily:'monospace', fontSize:10, flexShrink:0, marginLeft:8 }}>
{new Date(item.created_at).toLocaleDateString('de-DE')}
</div>