스마트서비스 최종완료보고 버전

This commit is contained in:
CodeTempla
2026-05-19 20:58:19 +09:00
commit d26eb50875
405 changed files with 46755 additions and 0 deletions
@@ -0,0 +1,202 @@
"use client";
import React, { useEffect, useState } from "react";
import Label from '@/components/form/Label2';
import Input from '@/components/form/input/InputField2';
import Select from '@/components/form/Select2';
import CtModal from "@/components/CtModal";
import { useMultiState } from "@/hooks/useMultiState";
import api from '@/lib/_AG';
import Button from "@/components/ui/button/Button2";
import { PlusIcon, TrashBinIcon } from "@/icons";
interface DeviceGooodsItem {
slot: string;
goods_id: number;
price?: number;
inventory?: number;
}
export interface GoodsModalProps {
biz_group_name?: string; // internal use
biz_reg_num?: string; // internal use
device_name?: string; // internal use
optGoodsList: { label: string; value: string; }[];
//
device_id: string;
prev_device_goods: DeviceGooodsItem[];
new_device_goods: DeviceGooodsItem[];
}
interface ManageGoodsModalProps {
multiState: ReturnType<typeof useMultiState<GoodsModalProps>>;
onOk: () => void;
isOpen: boolean;
closeModal: () => void;
}
export default function ManageGoodsModal({ multiState, onOk, isOpen, closeModal }: ManageGoodsModalProps) {
function computeGoods(modal: GoodsModalProps): GoodsModalProps {
// 1 & 2. 우선 slot이 빈 문자열("")이 아닌 아이템들만 추출 (1차 필터링)
const filteredPrev = modal.prev_device_goods.filter(item => item.slot !== "");
const filteredNew = modal.new_device_goods.filter(item => item.slot !== "");
// 3. slot이 같으면서 goods_id까지 같은 아이템은 양쪽에서 제거
// 즉, "상대방 배열에 나랑 똑같은(slot & goods_id) 애가 없는" 것들만 남깁니다.
// device_goods 정제
const final_device_goods = filteredPrev.filter(prevItem =>
!filteredNew.find(newItem =>
newItem.slot === prevItem.slot && newItem.goods_id === prevItem.goods_id
)
);
// new_device_goods 정제
const final_new_device_goods = filteredNew.filter(newItem =>
!filteredPrev.find(prevItem =>
prevItem.slot === newItem.slot && prevItem.goods_id === newItem.goods_id
)
);
// 결과 저장
return {
...modal,
prev_device_goods: final_device_goods,
new_device_goods: final_new_device_goods,
};
}
/*
const handleSelectGoods = (goods_id: number, newValue: string) => {
setGoodsList((prev) =>
prev.map((item) => (item.goods_id === id ? { ...item, value: newValue } : item))
);
};
*/
const handleClickAddOrModify = () => {
//if (multiState.values.name == "") {
// alert("기기 명칭을 입력하셔야 합니다.");
// return;
//}
console.log("1 - ", multiState.values.prev_device_goods);
console.log("2 - ", multiState.values.new_device_goods);
//const { biz_group_name, biz_reg_num, device_name, optGoodsList, ...params } = multiState.values;
const { biz_group_name, biz_reg_num, device_name, optGoodsList, ...params } = computeGoods(multiState.values);
console.log("5 - ", params.prev_device_goods);
console.log("6 - ", params.new_device_goods);
//console.log(params);
api.post('/api/manage-device-goods.do', params).then((resp) => {
console.log(resp);
if (resp.data.errCode == 0) {
alert("저장되었습니다.");
onOk();
}
else if (resp.data.errCode == -11) {
alert("컬럼번호는 중복될 수 없습니다.");
}
else {
alert("일시적으로 사용할 수 없습니다 : " + resp.data.errCode);
}
})
.catch((err) => console.error(err))
}
const handleClickAdd = () => {
if (multiState.values.optGoodsList.length == 0) {
//alert("등록된 상품이 없습니다. 좌측 '상품관리' 메뉴에서 상품목록을 등록하세요.");
return;
}
const newItem: DeviceGooodsItem = { slot: "", goods_id: parseInt(multiState.values.optGoodsList[0].value) }
const newArray: DeviceGooodsItem[] = [...multiState.values.new_device_goods, newItem];
multiState.set("new_device_goods", newArray);
}
const handleClickDel = (row: number) => {
const newArray: DeviceGooodsItem[] =
multiState.values.new_device_goods.filter((_, index) => index !== row);
multiState.set("new_device_goods", newArray);
}
const handleChangeSlot = (index: number, newValue: string) => {
const newArray: DeviceGooodsItem[] = [...multiState.values.new_device_goods];
newArray[index].slot = newValue;
multiState.set("new_device_goods", newArray);
};
const handleChangeInventory = (index: number, newValue: string) => {
const newArray: DeviceGooodsItem[] = [...multiState.values.new_device_goods];
newArray[index].inventory = Number(newValue);
multiState.set("new_device_goods", newArray);
};
const handleChangeGoods = (index: number, newValue: string) => {
const newArray: DeviceGooodsItem[] = [...multiState.values.new_device_goods];
newArray[index].goods_id = Number(newValue);
multiState.set("new_device_goods", newArray);
};
return (
// <div className="rounded-2xl border border-gray-200 bg-white dark:border-gray-800 dark:bg-white/[0.03]">
<CtModal
title={"기기에 상품 등록 또는 수정"}
description={"등록 또는 수정할 상품 정보를 입력하세요."}
okBtnText={"저장"}
onClickOk={handleClickAddOrModify}
isOpen={isOpen}
closeModal={closeModal}
className="max-w-[700px] p-6 lg:p-10"
>
<div>
<Label></Label>
<Input type="text" value={multiState.values.biz_group_name + "(" + multiState.values.biz_reg_num + ")"} disabled />
</div>
<div>
<Label> </Label>
<Input type="text" placeholder="" value={multiState.values.device_name} disabled />
</div>
{multiState.values.new_device_goods.map((item, index) => (
<div key={index}>
<Label> {index + 1}</Label>
<div className="flex gap-2">
<div className={"w-34"}>
<Input type="text" placeholder="컬럼번호2" value={multiState.values.new_device_goods[index].slot} onChange={(e) => handleChangeSlot(index, e.target.value)} />
</div>
<div className="flex-1">
<Select
placeholder="상품을 선택하세요"
options={multiState.values.optGoodsList}
defaultValue={String(multiState.values.new_device_goods[index].goods_id)}
onChange={(value) => handleChangeGoods(index, value)}
className="dark:bg-dark-900" />
</div>
<div className={"w-34"}>
<Input type="number" placeholder="수량" value={multiState.values.new_device_goods[index].inventory} onChange={(e) => handleChangeInventory(index, e.target.value)} />
</div>
<Button size="sm" variant="outline" startIcon={<TrashBinIcon />} onClick={() => handleClickDel(index)}></Button>
</div>
</div>
))}
<div>
<Button size="sm" variant="primary" startIcon={<PlusIcon />} onClick={handleClickAdd}> </Button>
</div>
</CtModal>
// </div>
);
};