feat: COMPANY_29 부서 등록 및 사용자 관리 페이지 개선
- 부서 등록 시 자동 생성 부서코드 기능 추가 - 사용자 관리에서 부서 필수 입력 검증 추가 - 품목 정보 페이지에서 입력 필드에 placeholder 추가 - 고객 관리 페이지에서 원본 카테고리 코드 보관 및 빈 문자열을 null로 변환하는 로직 추가 - 판매 주문 페이지에서 품목 검색 필터에 관리품목 선택 기능 추가 이 커밋은 부서 및 사용자 관리 기능을 개선하고, 사용자 경험을 향상시키기 위한 여러 변경 사항을 포함합니다.
This commit is contained in:
@@ -12,7 +12,7 @@
|
||||
* - 납품처 등록 (delivery_destination)
|
||||
*/
|
||||
|
||||
import React, { useState, useEffect, useCallback } from "react";
|
||||
import React, { useState, useEffect, useCallback, useRef } from "react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
|
||||
@@ -56,6 +56,7 @@ const LEFT_COLUMNS: DataGridColumn[] = [
|
||||
{ key: "contact_phone", label: "전화번호", width: "w-[110px]" },
|
||||
{ key: "business_number", label: "사업자번호", width: "w-[110px]" },
|
||||
{ key: "email", label: "이메일", width: "w-[130px]" },
|
||||
{ key: "address", label: "주소", minWidth: "min-w-[150px]" },
|
||||
{ key: "status", label: "상태", width: "w-[60px]" },
|
||||
];
|
||||
|
||||
@@ -79,6 +80,7 @@ export default function CustomerManagementPage() {
|
||||
|
||||
// 좌측: 거래처 목록
|
||||
const [customers, setCustomers] = useState<any[]>([]);
|
||||
const [rawCustomers, setRawCustomers] = useState<any[]>([]);
|
||||
const [customerLoading, setCustomerLoading] = useState(false);
|
||||
const [customerCount, setCustomerCount] = useState(0);
|
||||
const [searchFilters, setSearchFilters] = useState<FilterValue[]>([]);
|
||||
@@ -96,6 +98,7 @@ export default function CustomerManagementPage() {
|
||||
|
||||
// 품목 편집 데이터 (더블클릭 시 — 상세 입력 모달 재활용)
|
||||
const [editItemData, setEditItemData] = useState<any>(null);
|
||||
const savingRef = useRef(false);
|
||||
const [deliveryLoading, setDeliveryLoading] = useState(false);
|
||||
|
||||
// 모달
|
||||
@@ -192,6 +195,8 @@ export default function CustomerManagementPage() {
|
||||
autoFilter: true,
|
||||
});
|
||||
const raw = res.data?.data?.data || res.data?.data?.rows || [];
|
||||
// raw 데이터 보관 (수정 시 원본 카테고리 코드 사용)
|
||||
setRawCustomers(raw);
|
||||
// 카테고리 코드→라벨 변환
|
||||
const resolve = (col: string, code: string) => {
|
||||
if (!code) return "";
|
||||
@@ -334,7 +339,9 @@ export default function CustomerManagementPage() {
|
||||
|
||||
const openCustomerEdit = () => {
|
||||
if (!selectedCustomer) return;
|
||||
setCustomerForm({ ...selectedCustomer });
|
||||
// raw 데이터에서 원본 카테고리 코드 가져오기 (라벨 변환 전 데이터)
|
||||
const rawData = rawCustomers.find((c) => c.id === selectedCustomerId);
|
||||
setCustomerForm({ ...(rawData || selectedCustomer) });
|
||||
setFormErrors({});
|
||||
setCustomerEditMode(true);
|
||||
setCustomerModalOpen(true);
|
||||
@@ -365,13 +372,18 @@ export default function CustomerManagementPage() {
|
||||
setSaving(true);
|
||||
try {
|
||||
const { id, created_date, updated_date, writer, company_code, ...fields } = customerForm;
|
||||
// 빈 문자열을 null로 변환 (DB 타입 호환)
|
||||
const cleanFields: Record<string, any> = {};
|
||||
for (const [key, value] of Object.entries(fields)) {
|
||||
cleanFields[key] = value === "" ? null : value;
|
||||
}
|
||||
if (customerEditMode && id) {
|
||||
await apiClient.put(`/table-management/tables/${CUSTOMER_TABLE}/edit`, {
|
||||
originalData: { id }, updatedData: fields,
|
||||
originalData: { id }, updatedData: cleanFields,
|
||||
});
|
||||
toast.success("수정되었습니다.");
|
||||
} else {
|
||||
await apiClient.post(`/table-management/tables/${CUSTOMER_TABLE}/add`, fields);
|
||||
await apiClient.post(`/table-management/tables/${CUSTOMER_TABLE}/add`, cleanFields);
|
||||
toast.success("등록되었습니다.");
|
||||
}
|
||||
setCustomerModalOpen(false);
|
||||
@@ -569,6 +581,8 @@ export default function CustomerManagementPage() {
|
||||
|
||||
const handleItemDetailSave = async () => {
|
||||
if (!selectedCustomer) return;
|
||||
if (savingRef.current) return;
|
||||
savingRef.current = true;
|
||||
const isEditingExisting = !!editItemData;
|
||||
setSaving(true);
|
||||
try {
|
||||
@@ -641,9 +655,16 @@ export default function CustomerManagementPage() {
|
||||
});
|
||||
}
|
||||
|
||||
const priceRows = (itemPrices[itemKey] || []).filter((p) =>
|
||||
const allPriceRows = itemPrices[itemKey] || [];
|
||||
const priceRows = allPriceRows.filter((p) =>
|
||||
(p.base_price && Number(p.base_price) > 0) || p.start_date
|
||||
);
|
||||
if (allPriceRows.length > 0 && priceRows.length === 0) {
|
||||
toast.error("단가 정보를 입력해주세요. (기준가 또는 적용시작일 필수)");
|
||||
setSaving(false);
|
||||
savingRef.current = false;
|
||||
return;
|
||||
}
|
||||
for (const price of priceRows) {
|
||||
await apiClient.post(`/table-management/tables/${PRICE_TABLE}/add`, {
|
||||
mapping_id: mappingId || "", customer_id: selectedCustomer.customer_code, item_id: itemKey,
|
||||
@@ -669,6 +690,7 @@ export default function CustomerManagementPage() {
|
||||
toast.error(err.response?.data?.message || "저장에 실패했습니다.");
|
||||
} finally {
|
||||
setSaving(false);
|
||||
savingRef.current = false;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -773,9 +795,10 @@ export default function CustomerManagementPage() {
|
||||
|
||||
// 셀렉트 렌더링
|
||||
const renderSelect = (field: string, value: string, onChange: (v: string) => void, placeholder: string) => (
|
||||
<Select value={value || ""} onValueChange={onChange}>
|
||||
<Select value={value || "__none__"} onValueChange={(v) => onChange(v === "__none__" ? "" : v)}>
|
||||
<SelectTrigger className="h-9"><SelectValue placeholder={placeholder} /></SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="__none__">선택 안 함</SelectItem>
|
||||
{(categoryOptions[field] || []).map((o) => <SelectItem key={o.code} value={o.code}>{o.label}</SelectItem>)}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
|
||||
Reference in New Issue
Block a user