運搬計画: グループ単位の回間移動・未割当戻し機能を追加
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -547,6 +547,47 @@ export default function DeliveryEditPage({ planId }: Props) {
|
|||||||
removeFieldFromTrip(fieldId, tripTempId);
|
removeFieldFromTrip(fieldId, tripTempId);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// グループの全圃場を別のtripに移動
|
||||||
|
const moveGroupToTrip = (groupFieldIds: number[], fromTripTempId: string, toTripTempId: string) => {
|
||||||
|
setTrips(prev => {
|
||||||
|
const fromTrip = prev.find(t => t.tempId === fromTripTempId);
|
||||||
|
if (!fromTrip) return prev;
|
||||||
|
const fieldIdSet = new Set(groupFieldIds);
|
||||||
|
const movingItems = fromTrip.items.filter(item => fieldIdSet.has(item.fieldId));
|
||||||
|
if (movingItems.length === 0) return prev;
|
||||||
|
|
||||||
|
return prev.map(t => {
|
||||||
|
if (t.tempId === fromTripTempId) {
|
||||||
|
return { ...t, items: t.items.filter(item => !fieldIdSet.has(item.fieldId)) };
|
||||||
|
}
|
||||||
|
if (t.tempId === toTripTempId) {
|
||||||
|
const newItems = [...t.items];
|
||||||
|
for (const moving of movingItems) {
|
||||||
|
const existing = newItems.find(
|
||||||
|
item => item.fieldId === moving.fieldId && item.fertilizerId === moving.fertilizerId
|
||||||
|
);
|
||||||
|
if (existing) {
|
||||||
|
existing.bags += moving.bags;
|
||||||
|
} else {
|
||||||
|
newItems.push({ ...moving });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return { ...t, items: newItems };
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// グループの全圃場をtripから未割り当てに戻す
|
||||||
|
const returnGroupToUnassigned = (groupFieldIds: number[], tripTempId: string) => {
|
||||||
|
const fieldIdSet = new Set(groupFieldIds);
|
||||||
|
setTrips(prev => prev.map(t => {
|
||||||
|
if (t.tempId !== tripTempId) return t;
|
||||||
|
return { ...t, items: t.items.filter(item => !fieldIdSet.has(item.fieldId)) };
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
// tripのグループ小計
|
// tripのグループ小計
|
||||||
const getTripGroupFertTotal = useCallback((trip: LocalTrip, fieldIds: number[], fertilizerId: number): number => {
|
const getTripGroupFertTotal = useCallback((trip: LocalTrip, fieldIds: number[], fertilizerId: number): number => {
|
||||||
return trip.items
|
return trip.items
|
||||||
@@ -958,11 +999,34 @@ export default function DeliveryEditPage({ planId }: Props) {
|
|||||||
{/* グループ小計行 */}
|
{/* グループ小計行 */}
|
||||||
<div className="flex items-center gap-2 bg-green-50 px-2 py-1 rounded text-sm font-medium text-green-800">
|
<div className="flex items-center gap-2 bg-green-50 px-2 py-1 rounded text-sm font-medium text-green-800">
|
||||||
<span>★ {groupName}</span>
|
<span>★ {groupName}</span>
|
||||||
<span className="text-xs text-green-600 ml-auto">
|
<span className="text-xs text-green-600 flex-1 text-right">
|
||||||
{groupFertTotals.map((f, i) => (
|
{groupFertTotals.map((f, i) => (
|
||||||
<span key={f.id}>{i > 0 ? ' ' : ''}{f.name}: {f.total.toFixed(2)}</span>
|
<span key={f.id}>{i > 0 ? ' ' : ''}{f.name}: {f.total.toFixed(2)}</span>
|
||||||
))}
|
))}
|
||||||
</span>
|
</span>
|
||||||
|
{fieldIds.length > 1 && (
|
||||||
|
<select
|
||||||
|
value=""
|
||||||
|
onChange={e => {
|
||||||
|
const val = e.target.value;
|
||||||
|
if (val === '__unassigned__') {
|
||||||
|
returnGroupToUnassigned(fieldIds, trip.tempId);
|
||||||
|
} else if (val) {
|
||||||
|
moveGroupToTrip(fieldIds, trip.tempId, val);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
className="border border-gray-300 rounded px-1.5 py-0.5 text-xs font-normal text-gray-600 focus:outline-none focus:ring-1 focus:ring-blue-500 flex-shrink-0"
|
||||||
|
>
|
||||||
|
<option value="">移動...</option>
|
||||||
|
{trips.filter(t => t.tempId !== trip.tempId).map(t => {
|
||||||
|
const displayIdx = trips.indexOf(t) + 1;
|
||||||
|
return (
|
||||||
|
<option key={t.tempId} value={t.tempId}>→ {displayIdx}回目{t.name ? ` (${t.name})` : ''}</option>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
<option value="__unassigned__">← 戻す</option>
|
||||||
|
</select>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
{/* 圃場行 */}
|
{/* 圃場行 */}
|
||||||
{fieldIds.map(fId => {
|
{fieldIds.map(fId => {
|
||||||
|
|||||||
Reference in New Issue
Block a user