運搬計画: グループ一括割り当て機能を追加

各回の追加ドロップダウンに「+ グループを追加...」を追加。
グループ内の全圃場の未割り当て分を一括で回に追加できるようにした。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Akira
2026-03-16 16:53:32 +09:00
parent 287a1ebb59
commit bba04f24c2

View File

@@ -433,6 +433,32 @@ export default function DeliveryEditPage({ planId }: Props) {
]); ]);
}; };
// グループの全圃場をtripに一括割り当て
const assignGroupToTrip = (groupTempId: string, tripTempId: string) => {
const group = groups.find(g => g.tempId === groupTempId);
if (!group) return;
setTrips(prev => prev.map(t => {
if (t.tempId !== tripTempId) return t;
const newItems = [...t.items];
for (const fieldId of group.fieldIds) {
for (const fert of selectedFertilizers) {
const remaining = getUnassignedBags(fieldId, fert.id);
if (remaining > 0) {
const existing = newItems.find(
item => item.fieldId === fieldId && item.fertilizerId === fert.id
);
if (existing) {
existing.bags += remaining;
} else {
newItems.push({ fieldId, fertilizerId: fert.id, bags: remaining });
}
}
}
}
return { ...t, items: newItems };
}));
};
// tripの中の圃場IDを取得表示用・重複なし // tripの中の圃場IDを取得表示用・重複なし
const getTripFieldIds = useCallback((trip: LocalTrip): number[] => { const getTripFieldIds = useCallback((trip: LocalTrip): number[] => {
const seen = new Set<number>(); const seen = new Set<number>();
@@ -989,9 +1015,31 @@ export default function DeliveryEditPage({ planId }: Props) {
</div> </div>
)} )}
{/* このtripに圃場を追加 */} {/* このtripに追加 */}
{hasUnassignedBags && ( {hasUnassignedBags && (
<div className="mt-2 pt-2 border-t border-gray-100"> <div className="mt-2 pt-2 border-t border-gray-100 flex gap-2 flex-wrap">
{/* グループ一括追加 */}
<select
value=""
onChange={e => {
if (e.target.value) {
assignGroupToTrip(e.target.value, trip.tempId);
}
}}
className="border border-gray-300 rounded px-2 py-1 text-xs focus:outline-none focus:ring-1 focus:ring-green-500"
>
<option value="">+ ...</option>
{groups.map(g => {
const hasRemaining = g.fieldIds.some(fId =>
selectedFertilizers.some(f => getUnassignedBags(fId, f.id) > 0)
);
if (!hasRemaining) return null;
return (
<option key={g.tempId} value={g.tempId}> {g.name}{g.fieldIds.length}</option>
);
})}
</select>
{/* 圃場単体追加 */}
<select <select
value="" value=""
onChange={e => { onChange={e => {
@@ -1002,7 +1050,6 @@ export default function DeliveryEditPage({ planId }: Props) {
className="border border-gray-300 rounded px-2 py-1 text-xs focus:outline-none focus:ring-1 focus:ring-green-500" className="border border-gray-300 rounded px-2 py-1 text-xs focus:outline-none focus:ring-1 focus:ring-green-500"
> >
<option value="">+ ...</option> <option value="">+ ...</option>
{/* グループごとにまとめて表示 */}
{groups.map(g => { {groups.map(g => {
const fieldsWithRemaining = g.fieldIds.filter(fId => const fieldsWithRemaining = g.fieldIds.filter(fId =>
selectedFertilizers.some(f => getUnassignedBags(fId, f.id) > 0) selectedFertilizers.some(f => getUnassignedBags(fId, f.id) > 0)
@@ -1016,7 +1063,6 @@ export default function DeliveryEditPage({ planId }: Props) {
</optgroup> </optgroup>
); );
})} })}
{/* 未グループ */}
{unassignedFields.filter(fi => {unassignedFields.filter(fi =>
selectedFertilizers.some(f => getUnassignedBags(fi.id, f.id) > 0) selectedFertilizers.some(f => getUnassignedBags(fi.id, f.id) > 0)
).length > 0 && ( ).length > 0 && (