6.22.0: Авторасчёт сроков товаров по истории
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 1m23s

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
poignatov
2026-03-19 11:37:39 +03:00
parent 664adcfaa5
commit f1c12fd81a
13 changed files with 716 additions and 323 deletions

View File

@@ -10,7 +10,8 @@ function ShoppingItemDetail({ itemId, onClose, onRefresh, onItemCompleted, onNav
const [item, setItem] = useState(null)
const [loading, setLoading] = useState(true)
const [error, setError] = useState(null)
const [volumeValue, setVolumeValue] = useState('')
const [volumeRemaining, setVolumeRemaining] = useState('')
const [volumePurchased, setVolumePurchased] = useState('')
const [isCompleting, setIsCompleting] = useState(false)
const [toastMessage, setToastMessage] = useState(null)
@@ -38,7 +39,8 @@ function ShoppingItemDetail({ itemId, onClose, onRefresh, onItemCompleted, onNav
setItem(null)
setLoading(true)
setError(null)
setVolumeValue('')
setVolumeRemaining('')
setVolumePurchased('')
}
}, [itemId, fetchItem])
@@ -48,13 +50,21 @@ function ShoppingItemDetail({ itemId, onClose, onRefresh, onItemCompleted, onNav
setIsCompleting(true)
try {
const payload = {}
if (volumeValue.trim()) {
payload.volume = parseFloat(volumeValue)
if (isNaN(payload.volume)) {
throw new Error('Неверное значение объёма')
if (volumeRemaining.trim()) {
payload.volume_remaining = parseFloat(volumeRemaining)
if (isNaN(payload.volume_remaining)) {
throw new Error('Неверное значение остатка')
}
} else {
payload.volume = item.last_volume ?? item.volume_base
payload.volume_remaining = item.estimated_remaining ?? 0
}
if (volumePurchased.trim()) {
payload.volume_purchased = parseFloat(volumePurchased)
if (isNaN(payload.volume_purchased)) {
throw new Error('Неверное значение докупки')
}
} else {
payload.volume_purchased = item.median_purchased ?? item.volume_base ?? 1
}
const response = await authFetch(`/api/shopping/items/${itemId}/complete`, {
@@ -169,42 +179,78 @@ function ShoppingItemDetail({ itemId, onClose, onRefresh, onItemCompleted, onNav
</button>
</div>
<div className="shopping-item-complete-row">
<label className="progression-label">Объём</label>
<div className="progression-input-wrapper">
<input
type="number"
step="any"
value={volumeValue}
onChange={(e) => setVolumeValue(e.target.value)}
placeholder={(item.last_volume ?? item.volume_base)?.toString() || '1'}
className="progression-input"
/>
<div className="progression-controls-capsule">
<button
type="button"
className="progression-control-btn progression-control-minus"
onClick={() => {
const base = item.last_volume ?? item.volume_base ?? 1
const current = volumeValue.trim() ? parseFloat(volumeValue) : base
const step = item.volume_base || 1
setVolumeValue((current - step).toString())
}}
>
</button>
<button
type="button"
className="progression-control-btn progression-control-plus"
onClick={() => {
const base = item.last_volume ?? item.volume_base ?? 1
const current = volumeValue.trim() ? parseFloat(volumeValue) : base
const step = item.volume_base || 1
setVolumeValue((current + step).toString())
}}
>
+
</button>
<div style={{ display: 'flex', gap: '0.5rem', alignItems: 'flex-end', marginBottom: '0.75rem' }}>
<div style={{ flex: 1 }}>
<label className="progression-label">Остаток</label>
<div className="progression-input-wrapper">
<input
type="number"
step="any"
value={volumeRemaining}
onChange={(e) => setVolumeRemaining(e.target.value)}
placeholder={item.estimated_remaining != null ? Math.round(item.estimated_remaining * 10) / 10 + '' : '0'}
className="progression-input"
/>
{volumeRemaining && (
<button
type="button"
onClick={() => setVolumeRemaining('')}
style={{
position: 'absolute',
right: '8px',
top: '50%',
transform: 'translateY(-50%)',
background: 'none',
border: 'none',
color: '#9ca3af',
cursor: 'pointer',
fontSize: '1.1rem',
padding: '4px',
lineHeight: 1,
}}
>
</button>
)}
</div>
</div>
<div style={{ flex: 1 }}>
<label className="progression-label">Докуплено</label>
<div className="progression-input-wrapper">
<input
type="number"
step="any"
value={volumePurchased}
onChange={(e) => setVolumePurchased(e.target.value)}
placeholder={(item.median_purchased ?? item.volume_base ?? 1).toString()}
className="progression-input"
/>
<div className="progression-controls-capsule">
<button
type="button"
className="progression-control-btn progression-control-minus"
onClick={() => {
const base = item.median_purchased ?? item.volume_base ?? 1
const current = volumePurchased.trim() ? parseFloat(volumePurchased) : base
const step = item.volume_base || 1
setVolumePurchased(Math.max(0, current - step).toString())
}}
>
</button>
<button
type="button"
className="progression-control-btn progression-control-plus"
onClick={() => {
const base = item.median_purchased ?? item.volume_base ?? 1
const current = volumePurchased.trim() ? parseFloat(volumePurchased) : base
const step = item.volume_base || 1
setVolumePurchased((current + step).toString())
}}
>
+
</button>
</div>
</div>
</div>
</div>