feat(WEB): 작업자 화면 부서/담당자/생산일자 API 연동 및 사원관리 날짜필터 개선
- 작업자 화면 작업정보 부서: 하드코딩 → 테넌트 부서 목록 동적 로드 (getDepartments API) - 작업자 화면 작업정보 생산담당자: 선택된 부서별 사용자 목록 연동 (getDepartmentUsers API) - 작업자 화면 작업정보 생산일자: scheduled_date 필드 조회 연동 - 작업지시 선택 시 공정 담당부서(process.department) 기반 부서 자동 세팅 - 사이드바 자동 선택 시 API 작업지시 우선 선택 (목업보다 우선) - 사원관리 초기 진입 시 날짜 필터 기본값 제거 (전체 기간 조회)
This commit is contained in:
@@ -40,8 +40,8 @@ import { Button } from '@/components/ui/button';
|
||||
import { PageLayout } from '@/components/organisms/PageLayout';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { toast } from 'sonner';
|
||||
import { getMyWorkOrders, completeWorkOrder, saveItemInspection, getWorkOrderInspectionData, saveInspectionDocument, getInspectionTemplate, getStepProgress, toggleStepProgress, deleteMaterialInput, updateMaterialInput } from './actions';
|
||||
import type { StepProgressItem } from './actions';
|
||||
import { getMyWorkOrders, completeWorkOrder, saveItemInspection, getWorkOrderInspectionData, saveInspectionDocument, getInspectionTemplate, getStepProgress, toggleStepProgress, deleteMaterialInput, updateMaterialInput, getDepartments, getDepartmentUsers } from './actions';
|
||||
import type { StepProgressItem, DepartmentOption, DepartmentUser } from './actions';
|
||||
import type { InspectionTemplateData } from './types';
|
||||
import { getProcessList } from '@/components/process-management/actions';
|
||||
import type { InspectionSetting, Process } from '@/types/process';
|
||||
@@ -320,6 +320,8 @@ export default function WorkerScreen() {
|
||||
const [departmentId, setDepartmentId] = useState('');
|
||||
const [productionManagerId, setProductionManagerId] = useState('');
|
||||
const [productionDate, setProductionDate] = useState('');
|
||||
const [departmentList, setDepartmentList] = useState<DepartmentOption[]>([]);
|
||||
const [departmentUsers, setDepartmentUsers] = useState<DepartmentUser[]>([]);
|
||||
|
||||
// 좌측 사이드바
|
||||
const [selectedSidebarOrderId, setSelectedSidebarOrderId] = useState<string>('');
|
||||
@@ -352,8 +354,29 @@ export default function WorkerScreen() {
|
||||
|
||||
useEffect(() => {
|
||||
loadData();
|
||||
// 부서 목록 로드
|
||||
getDepartments().then((res) => {
|
||||
if (res.success) setDepartmentList(res.data);
|
||||
});
|
||||
}, [loadData]);
|
||||
|
||||
// 부서 선택 시 해당 부서 사용자 목록 로드
|
||||
useEffect(() => {
|
||||
if (!departmentId) {
|
||||
setDepartmentUsers([]);
|
||||
setProductionManagerId('');
|
||||
return;
|
||||
}
|
||||
getDepartmentUsers(Number(departmentId)).then((res) => {
|
||||
if (res.success) {
|
||||
setDepartmentUsers(res.data);
|
||||
} else {
|
||||
setDepartmentUsers([]);
|
||||
}
|
||||
setProductionManagerId('');
|
||||
});
|
||||
}, [departmentId]);
|
||||
|
||||
// PC에서 사이드바 sticky 동작을 위해 main의 overflow 임시 해제
|
||||
useEffect(() => {
|
||||
const mainEl = document.querySelector('main');
|
||||
@@ -531,12 +554,24 @@ export default function WorkerScreen() {
|
||||
return;
|
||||
}
|
||||
|
||||
// 우선순위 순서: urgent → priority → normal
|
||||
// API 작업지시 우선 선택 (부서/담당자 연동을 위해)
|
||||
if (apiSidebarOrders.length > 0) {
|
||||
const firstApi = apiSidebarOrders[0];
|
||||
setSelectedSidebarOrderId(firstApi.id);
|
||||
if (activeProcessTabKey === 'slat') {
|
||||
setSlatSubMode(firstApi.subType === 'jointbar' ? 'jointbar' : 'normal');
|
||||
}
|
||||
if (activeProcessTabKey === 'bending') {
|
||||
setBendingSubMode(firstApi.subType === 'wip' ? 'wip' : 'normal');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// API 작업지시 없으면 목업에서 우선순위 순서: urgent → priority → normal
|
||||
for (const group of PRIORITY_GROUPS) {
|
||||
const first = allOrders.find((o) => o.priority === group.key);
|
||||
if (first) {
|
||||
setSelectedSidebarOrderId(first.id);
|
||||
// subType에 따라 서브모드도 설정
|
||||
if (activeProcessTabKey === 'slat') {
|
||||
setSlatSubMode(first.subType === 'jointbar' ? 'jointbar' : 'normal');
|
||||
}
|
||||
@@ -796,6 +831,29 @@ export default function WorkerScreen() {
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [selectedSidebarOrderId, workItems.length]);
|
||||
|
||||
// ===== 작업지시 변경 시 작업 정보 자동 세팅 =====
|
||||
useEffect(() => {
|
||||
const apiOrder = filteredWorkOrders.find((wo) => wo.id === selectedSidebarOrderId);
|
||||
if (apiOrder) {
|
||||
// 부서 세팅: 1순위 work_orders.team_id → 2순위 process.department(부서명 매칭)
|
||||
if (apiOrder.teamId) {
|
||||
setDepartmentId(String(apiOrder.teamId));
|
||||
} else if (apiOrder.processDepartment && departmentList.length > 0) {
|
||||
const matched = departmentList.find((d) => d.name === apiOrder.processDepartment);
|
||||
setDepartmentId(matched ? String(matched.id) : '');
|
||||
} else {
|
||||
setDepartmentId('');
|
||||
}
|
||||
// 생산일자 세팅
|
||||
setProductionDate(apiOrder.scheduledDate || '');
|
||||
} else {
|
||||
setDepartmentId('');
|
||||
setProductionManagerId('');
|
||||
setProductionDate('');
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [selectedSidebarOrderId, filteredWorkOrders, departmentList]);
|
||||
|
||||
// ===== 수주 정보 (사이드바 선택 항목 기반) =====
|
||||
const orderInfo = useMemo(() => {
|
||||
// 1. 선택된 API 작업지시에서 찾기
|
||||
@@ -1427,7 +1485,7 @@ export default function WorkerScreen() {
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* 작업 정보 - 부서 필드 추가 */}
|
||||
{/* 작업 정보 - API 연동 */}
|
||||
<Card>
|
||||
<CardContent className="p-4">
|
||||
<h3 className="text-sm font-semibold text-gray-900 mb-3">작업 정보</h3>
|
||||
@@ -1435,6 +1493,7 @@ export default function WorkerScreen() {
|
||||
<div className="space-y-1.5">
|
||||
<Label className="text-sm text-gray-600">부서</Label>
|
||||
<Select
|
||||
key={`dept-${departmentId}`}
|
||||
value={departmentId}
|
||||
onValueChange={setDepartmentId}
|
||||
>
|
||||
@@ -1442,28 +1501,29 @@ export default function WorkerScreen() {
|
||||
<SelectValue placeholder="선택" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="production">생산부서</SelectItem>
|
||||
<SelectItem value="quality">품질관리부</SelectItem>
|
||||
{departmentList.map((dept) => (
|
||||
<SelectItem key={dept.id} value={String(dept.id)}>
|
||||
{dept.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div className="space-y-1.5">
|
||||
<Label className="text-sm text-gray-600">생산 담당자</Label>
|
||||
<Select
|
||||
key={`manager-${departmentId}-${productionManagerId}`}
|
||||
value={productionManagerId}
|
||||
onValueChange={setProductionManagerId}
|
||||
disabled={!departmentId}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="선택" />
|
||||
<SelectValue placeholder={departmentId ? '선택' : '부서를 먼저 선택'} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{Array.from(
|
||||
new Set(
|
||||
filteredWorkOrders.flatMap((o) => o.assignees || []).filter(Boolean)
|
||||
)
|
||||
).map((name) => (
|
||||
<SelectItem key={name} value={name}>
|
||||
{name}
|
||||
{departmentUsers.map((user) => (
|
||||
<SelectItem key={user.id} value={String(user.id)}>
|
||||
{user.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
|
||||
Reference in New Issue
Block a user