2196 lines
85 KiB
JavaScript
2196 lines
85 KiB
JavaScript
'use client'
|
|
|
|
import { useEffect, useState, useContext } from 'react'
|
|
import { useRecoilValue } from 'recoil'
|
|
import { floorPlanObjectState } from '@/store/floorPlanObjectAtom'
|
|
import { useMessage } from '@/hooks/useMessage'
|
|
import SingleDatePicker from '../common/datepicker/SingleDatePicker'
|
|
import EstimateFileUploader from './EstimateFileUploader'
|
|
import { useAxios } from '@/hooks/useAxios'
|
|
import { globalLocaleStore } from '@/store/localeAtom'
|
|
import { isEmptyArray, isNotEmptyArray, isObjectNotEmpty, queryStringFormatter } from '@/util/common-utils'
|
|
import dayjs from 'dayjs'
|
|
import { useCommonCode } from '@/hooks/common/useCommonCode'
|
|
import { useEstimateController } from '@/hooks/floorPlan/estimate/useEstimateController'
|
|
import { SessionContext } from '@/app/SessionProvider'
|
|
import Select, { components } from 'react-select'
|
|
import { convertNumberToPriceDecimal, convertNumberToPriceDecimalToFixed } from '@/util/common-utils'
|
|
import ProductFeaturesPop from './popup/ProductFeaturesPop'
|
|
import { v4 as uuidv4 } from 'uuid'
|
|
import { useSearchParams } from 'next/navigation'
|
|
import { usePlan } from '@/hooks/usePlan'
|
|
import { usePopup } from '@/hooks/usePopup'
|
|
import { useSwal } from '@/hooks/useSwal'
|
|
import { QcastContext } from '@/app/QcastProvider'
|
|
import { useCanvasMenu } from '@/hooks/common/useCanvasMenu'
|
|
import {normalizeDigits, normalizeDecimal} from '@/util/input-utils'
|
|
export default function Estimate({}) {
|
|
const [uniqueData, setUniqueData] = useState([])
|
|
const [handlePricingFlag, setHandlePricingFlag] = useState(false)
|
|
const [specialNoteFirstFlg, setSpecialNoteFirstFlg] = useState(false)
|
|
const [itemChangeYn, setItemChangeYn] = useState(false)
|
|
const { session } = useContext(SessionContext)
|
|
const [objectNo, setObjectNo] = useState('') //물건번호
|
|
const [planNo, setPlanNo] = useState('') //플랜번호
|
|
|
|
const { swalFire } = useSwal()
|
|
|
|
const [files, setFiles] = useState([]) // 보내는 첨부파일
|
|
const [originFiles, setOriginFiles] = useState([]) //기존 첨부파일
|
|
|
|
const [showPriceCd, setShowPriceCd] = useState('')
|
|
|
|
const [showContentCode, setShowContentCode] = useState('ATTR001')
|
|
|
|
const [productFeaturesPopupOpen, setProductFeaturesPopupOpen] = useState(false) //견적특이사항 팝업
|
|
const [showProductFeatureData, setShowProductFeatureData] = useState([]) //팝업에 보여줄 견적특이사항 데이터
|
|
|
|
const [selection, setSelection] = useState(new Set())
|
|
//견적특이사항 접고 펼치기
|
|
const [hidden, setHidden] = useState(true)
|
|
|
|
//아이템 자동완성 리스트
|
|
const [originDisplayItemList, setOriginDisplayItemList] = useState([])
|
|
const [displayItemList, setDisplayItemList] = useState([])
|
|
|
|
//공통코드
|
|
const { findCommonCode } = useCommonCode()
|
|
const [honorificCodeList, setHonorificCodeList] = useState([]) //경칭 공통코드
|
|
|
|
const [storePriceList, setStorePriceList] = useState([]) //가격표시 option
|
|
|
|
const [cableItemList, setCableItemList] = useState([]) //케이블 리스트
|
|
const [cableItem, setCableItem] = useState('') //케이블 선택값
|
|
const [cableDbItem, setCableDbItem] = useState('') //케이블 선택값
|
|
const [startDate, setStartDate] = useState(new Date())
|
|
const singleDatePickerProps = {
|
|
startDate,
|
|
setStartDate,
|
|
}
|
|
/**
|
|
* objectNo 셋팅
|
|
* url로 넘어온 objectNo을 리코일에 세팅
|
|
*/
|
|
const searchParams = useSearchParams()
|
|
const objectRecoil = useRecoilValue(floorPlanObjectState)
|
|
const currentObjectNo = searchParams.get('objectNo')
|
|
const currentPid = searchParams.get('pid')
|
|
//견적서 상세데이터
|
|
const { estimateContextState, setEstimateContextState, addItem, handleEstimateFileDownload } = useEstimateController(currentPid, false)
|
|
|
|
const { selectedPlan } = usePlan()
|
|
|
|
//견적특이사항 List
|
|
const [specialNoteList, setSpecialNoteList] = useState([])
|
|
const [popShowSpecialNoteList, setPopShowSpecialNoteList] = useState([])
|
|
|
|
const { setIsGlobalLoading } = useContext(QcastContext)
|
|
const globalLocaleState = useRecoilValue(globalLocaleStore)
|
|
const { get, post, promisePost } = useAxios(globalLocaleState)
|
|
|
|
const { getMessage } = useMessage()
|
|
|
|
const { closeAll } = usePopup()
|
|
const { setSelectedMenu } = useCanvasMenu()
|
|
//새로 추가한 첨부파일 props
|
|
const fileUploadProps = {
|
|
uploadFiles: files,
|
|
setUploadFiles: setFiles,
|
|
}
|
|
|
|
const initEstimate = (currPid = currentPid) => {
|
|
// console.log('🚀 ~ initEstimate ~ currPid:', currPid)
|
|
closeAll()
|
|
setObjectNo(objectRecoil.floorPlanObjectNo)
|
|
|
|
setPlanNo(currPid)
|
|
|
|
// 공통코드
|
|
const code1 = findCommonCode(200800)
|
|
if (code1 != null) {
|
|
setHonorificCodeList(code1)
|
|
}
|
|
|
|
// 케이블제품 공통코드
|
|
const code2 = findCommonCode(117900)
|
|
if (code2 != null) {
|
|
code2.map((item) => {
|
|
item.value = item.clRefChr1
|
|
item.label = item.clRefChr2
|
|
})
|
|
// console.log(code2)
|
|
setCableItemList(code2)
|
|
}
|
|
|
|
//아이템 자동완성 목록 가져오기
|
|
const param = {
|
|
saleStoreId: session.storeId,
|
|
}
|
|
const apiUrl = `/api/display-item/item-list?${queryStringFormatter(param)}`
|
|
post({ url: apiUrl, data: param }).then((res) => {
|
|
if (res.length > 0) {
|
|
let tempList = []
|
|
let updatedRes = []
|
|
if (estimateContextState?.itemList.length > 0) {
|
|
tempList = estimateContextState.itemList.filter((item) => !res.some((resItem) => resItem.itemId === item.itemId))
|
|
updatedRes = [...res, ...tempList]
|
|
} else {
|
|
updatedRes = [...res]
|
|
}
|
|
|
|
const groupByItemGroup = (items) => {
|
|
const grouped = items.reduce((acc, item) => {
|
|
const group = item.itemGroup || '기타';
|
|
if (!acc[group]) {
|
|
acc[group] = {
|
|
label: group,
|
|
options: []
|
|
};
|
|
}
|
|
acc[group].options.push({
|
|
value: item.itemId,
|
|
label: `${item.itemNo} - ${item.itemName}`,
|
|
...item
|
|
});
|
|
return acc;
|
|
}, {});
|
|
|
|
return Object.values(grouped);
|
|
};
|
|
const groupedItems = groupByItemGroup(res);
|
|
setOriginDisplayItemList(groupedItems)
|
|
setDisplayItemList(updatedRes)
|
|
}
|
|
})
|
|
//견적특이사항 API호출
|
|
//여러개 선택하면 구분자로 (、)
|
|
//제품영역 팝업용
|
|
let url = '/api/estimate/special-note-list'
|
|
get({ url: url }).then((res) => {
|
|
if (isNotEmptyArray(res)) {
|
|
setPopShowSpecialNoteList(res)
|
|
}
|
|
})
|
|
}
|
|
|
|
const groupStyles = {
|
|
groupHeading: (provided) => ({
|
|
...provided,
|
|
fontSize: '14px',
|
|
fontWeight: 'bold',
|
|
color: '#333',
|
|
backgroundColor: '#f5f5f5',
|
|
padding: '8px 12px',
|
|
marginBottom: '4px',
|
|
borderBottom: '2px solid #ddd'
|
|
})
|
|
};
|
|
|
|
useEffect(() => {
|
|
// console.log('🚀 ~ Estimate ~ selectedPlan:', selectedPlan)
|
|
if (selectedPlan) initEstimate(selectedPlan?.planNo?? currentPid)
|
|
}, [selectedPlan])
|
|
|
|
useEffect(() => {
|
|
setSelectedMenu('estimate')
|
|
initEstimate()
|
|
}, [])
|
|
|
|
useEffect(() => {
|
|
//견적특이사항 API호출
|
|
//여러개 선택하면 구분자로 (、)
|
|
//체크용
|
|
if (estimateContextState.resetFlag === 'Y') {
|
|
let url = `/api/estimate/special-note-title-list`
|
|
get({ url: url }).then((res) => {
|
|
if (isNotEmptyArray(res)) {
|
|
if (estimateContextState?.estimateOption) {
|
|
res.map((row) => {
|
|
let estimateOption = estimateContextState?.estimateOption?.split('、')
|
|
row.check = false
|
|
estimateOption.map((row2) => {
|
|
if (row.pkgYn === '0') {
|
|
// if (row2 === row.code) {
|
|
// row.check = true
|
|
// }
|
|
if (row.code.split('、').includes(row2)) {
|
|
row.check = true
|
|
}
|
|
} else {
|
|
if (row.code.includes(row2)) {
|
|
row.check = true
|
|
return
|
|
}
|
|
}
|
|
})
|
|
if (row.code === 'ATTR003') {
|
|
//row.check = true
|
|
}
|
|
if (row.code === 'ATTR007') {
|
|
//row.check = true
|
|
}
|
|
|
|
if (estimateContextState.estimateType === 'YJOD') {
|
|
if (row.code === 'ATTR002') {
|
|
row.check = true
|
|
}
|
|
}
|
|
})
|
|
|
|
setSpecialNoteList(res)
|
|
|
|
setSpecialNoteFirstFlg(true)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
if (!specialNoteFirstFlg) {
|
|
let url = `/api/estimate/special-note-title-list`
|
|
get({ url: url }).then((res) => {
|
|
if (isNotEmptyArray(res)) {
|
|
if (estimateContextState?.estimateOption) {
|
|
res.map((row) => {
|
|
let estimateOption = estimateContextState?.estimateOption?.split('、')
|
|
row.check = false
|
|
estimateOption.map((row2) => {
|
|
if (row.pkgYn === '0') {
|
|
// if (row2 === row.code) {
|
|
// row.check = true
|
|
// }
|
|
if (row.code.split('、').includes(row2)) {
|
|
row.check = true
|
|
}
|
|
} else {
|
|
if (row.code.includes(row2)) {
|
|
row.check = true
|
|
return
|
|
}
|
|
}
|
|
})
|
|
if (row.code === 'ATTR003') {
|
|
//row.check = true
|
|
}
|
|
if (row.code === 'ATTR007') {
|
|
//row.check = true
|
|
}
|
|
|
|
if (estimateContextState.estimateType === 'YJOD') {
|
|
if (row.code === 'ATTR002') {
|
|
row.check = true
|
|
}
|
|
}
|
|
})
|
|
setSpecialNoteList(res)
|
|
|
|
setSpecialNoteFirstFlg(true)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}, [estimateContextState?.estimateOption])
|
|
|
|
//API데이터로 견적일 셋팅
|
|
let begin = 1
|
|
useEffect(() => {
|
|
if (begin === 1) {
|
|
setStartDate(estimateContextState?.estimateDate)
|
|
begin++
|
|
}
|
|
}, [estimateContextState?.estimateDate])
|
|
|
|
//견적일 set
|
|
useEffect(() => {
|
|
let estimateDate
|
|
if (startDate) {
|
|
estimateDate = dayjs(startDate).format('YYYY-MM-DD')
|
|
if (begin === 1) {
|
|
setEstimateContextState({ estimateDate: estimateDate })
|
|
}
|
|
} else {
|
|
setEstimateContextState({ estimateDate: '' })
|
|
}
|
|
}, [startDate])
|
|
|
|
useEffect(() => {
|
|
//선택된 견적특이사항 setEstimateContextState
|
|
if (isNotEmptyArray(specialNoteList)) {
|
|
const liveCheckedData = specialNoteList.filter((row) => row.check === true)
|
|
|
|
const data = []
|
|
for (let ele of liveCheckedData) {
|
|
data.push(ele.code)
|
|
}
|
|
|
|
const newData = data.join('、')
|
|
//저장용 보내기
|
|
setEstimateContextState({ estimateOption: newData, specialNoteList: specialNoteList, uniqueData: uniqueData })
|
|
}
|
|
}, [specialNoteList])
|
|
|
|
// 견적특이사항 remark 보여주기
|
|
const settingShowContent = (code) => {
|
|
setShowContentCode(code)
|
|
}
|
|
|
|
// 추가한 첨부파일 estimateContextState에 넣기
|
|
useEffect(() => {
|
|
if (isNotEmptyArray(files)) {
|
|
let fileList = []
|
|
files.map((row) => {
|
|
fileList.push(row.data)
|
|
setEstimateContextState({ fileList: row.data, newFileList: fileList })
|
|
})
|
|
} else {
|
|
setEstimateContextState({ fileList: [], newFileList: [] })
|
|
}
|
|
}, [files])
|
|
|
|
//상세에서 내려온 첨부파일 set 만들기
|
|
useEffect(() => {
|
|
if (isNotEmptyArray(estimateContextState.fileList)) {
|
|
//드래그영역 비워주기
|
|
setFiles([])
|
|
setOriginFiles(estimateContextState.fileList)
|
|
} else {
|
|
if (estimateContextState?.resetFlag === 'Y') {
|
|
originReset()
|
|
} else {
|
|
if (originFiles.length > 0) {
|
|
if (isEmptyArray(files)) {
|
|
if (originFiles[0].planNo !== estimateContextState.planNo) {
|
|
setOriginFiles([])
|
|
} else {
|
|
let file
|
|
file = originFiles.filter((item) => item.delFlg === '0')
|
|
setEstimateContextState({
|
|
originFiles: file,
|
|
})
|
|
setOriginFiles(file)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}, [estimateContextState?.fileList])
|
|
|
|
const originReset = () => {
|
|
setOriginFiles([])
|
|
estimateContextState.resetFlag = 'N'
|
|
}
|
|
// 삭제누른 첨부파일 복원
|
|
const returnOriginFile = (no) => {
|
|
originFiles.map((file) => {
|
|
if (file.no === no) {
|
|
file.delFlg = '0'
|
|
}
|
|
})
|
|
setOriginFiles((prev) => {
|
|
return [...prev]
|
|
})
|
|
setEstimateContextState({
|
|
originFiles: originFiles,
|
|
})
|
|
}
|
|
// 기존첨부파일 삭제 (플래그값 추가?) 저장할때 플래그값에 따라 진짜 삭제
|
|
const deleteOriginFile = (no) => {
|
|
originFiles.map((file) => {
|
|
if (file.no === no) {
|
|
file.delFlg = '1'
|
|
}
|
|
})
|
|
|
|
setOriginFiles((prev) => {
|
|
return [...prev]
|
|
})
|
|
setEstimateContextState({
|
|
originFiles: originFiles,
|
|
})
|
|
|
|
swalFire({
|
|
text: getMessage('estimate.detail.alert.delFile'),
|
|
type: 'alert',
|
|
})
|
|
}
|
|
|
|
//가격표시 option 목록 최초세팅 && 주문분류 변경시
|
|
useEffect(() => {
|
|
if (estimateContextState.estimateType !== '') {
|
|
const param = {
|
|
saleStoreId: estimateContextState.sapSaleStoreId,
|
|
sapSalesStoreCd: estimateContextState.sapSalesStoreCd,
|
|
docTpCd: estimateContextState?.estimateType,
|
|
}
|
|
|
|
const apiUrl = `/api/estimate/price/store-price-list?${queryStringFormatter(param)}`
|
|
get({ url: apiUrl }).then((res) => {
|
|
if (isNotEmptyArray(res?.data)) {
|
|
setStorePriceList(res.data)
|
|
}
|
|
|
|
setItemChangeYn(true)
|
|
})
|
|
|
|
if (estimateContextState.estimateType === 'YJSS') {
|
|
if (specialNoteList.length > 0) {
|
|
specialNoteList.map((item) => {
|
|
if (item.code === 'ATTR002') {
|
|
item.check = false
|
|
}
|
|
})
|
|
}
|
|
|
|
//YJSS UNIT_PIRCE로 프라이싱 실행
|
|
if (handlePricingFlag) {
|
|
handlePricing('UNIT_PRICE')
|
|
}
|
|
} else {
|
|
if (specialNoteList.length > 0) {
|
|
specialNoteList.map((item) => {
|
|
if (item.code === 'ATTR002') {
|
|
item.check = true
|
|
}
|
|
})
|
|
}
|
|
|
|
//YJOD로 돌아가도 UNIT_PRICE로 프라이싱 실행해서 정가로 셋팅
|
|
if (handlePricingFlag) {
|
|
handlePricing('UNIT_PRICE')
|
|
}
|
|
}
|
|
}
|
|
}, [estimateContextState?.estimateType])
|
|
|
|
useEffect(() => {
|
|
if (estimateContextState?.priceCd) {
|
|
setShowPriceCd(estimateContextState.priceCd)
|
|
}
|
|
}, [estimateContextState?.priceCd])
|
|
|
|
//가격 표시 option 변경 이벤트
|
|
const onChangeStorePriceList = (priceCd) => {
|
|
//프라이싱 했을때 priceCd setEstimateContextState
|
|
//화면에 보여지는 값은 showPriceCd로 관리
|
|
setShowPriceCd(priceCd)
|
|
}
|
|
|
|
const makeUniqueSpecialNoteCd = (itemList) => {
|
|
let pushData = []
|
|
let uniquSet = new Set()
|
|
|
|
itemList.forEach((item) => {
|
|
if (item.delFlg === '0') {
|
|
if (item.specialNoteCd) {
|
|
let splitData = item.specialNoteCd.split('、')
|
|
splitData.forEach((note) => {
|
|
if (!uniquSet.has(note)) {
|
|
uniquSet.add(note)
|
|
pushData.push(note)
|
|
}
|
|
})
|
|
|
|
setSpecialNoteFirstFlg(false)
|
|
}
|
|
}
|
|
})
|
|
setUniqueData(pushData)
|
|
specialNoteList.map((item) => {
|
|
if (item.pkgYn === '1') {
|
|
let flg = '0'
|
|
let codes = item.code
|
|
for (let i = 0; i < pushData.length; i++) {
|
|
if (codes.indexOf(pushData[i]) > -1) {
|
|
flg = '1'
|
|
}
|
|
}
|
|
|
|
if (flg === '1') {
|
|
item.check = true
|
|
} else {
|
|
item.check = false
|
|
}
|
|
} else {
|
|
let codes = item.code.split('、')
|
|
let flg = '0'
|
|
if (codes.length > 1) {
|
|
for (let i = 0; i < pushData.length; i++) {
|
|
if (codes.indexOf(pushData[i]) > -1) {
|
|
flg = '1'
|
|
}
|
|
}
|
|
if (flg === '1') {
|
|
item.check = true
|
|
} else {
|
|
item.check = false
|
|
}
|
|
}
|
|
}
|
|
})
|
|
|
|
setEstimateContextState({
|
|
specialNoteList: specialNoteList,
|
|
uniqueData: uniqueData,
|
|
})
|
|
}
|
|
|
|
//Pricing 버튼클릭시 confirm 노출
|
|
const handlePricingBtn = (showPriceCd) => {
|
|
swalFire({
|
|
text: getMessage('estimate.detail.showPrice.pricingBtn.confirm'),
|
|
type: 'confirm',
|
|
icon: 'warning',
|
|
confirmFn: () => {
|
|
handlePricing(showPriceCd)
|
|
setEstimateContextState({ pricingFlag:true })
|
|
},
|
|
})
|
|
}
|
|
|
|
//Pricing 버튼
|
|
const handlePricing = async (showPriceCd) => {
|
|
const param = {
|
|
saleStoreId: estimateContextState.sapSaleStoreId,
|
|
sapSalesStoreCd: estimateContextState.sapSalesStoreCd,
|
|
docTpCd: estimateContextState.estimateType,
|
|
secSapSalesStoreCd:
|
|
estimateContextState.secSapSalesStoreCd?.length > 0 && showPriceCd === 'QSP_PRICE' ? estimateContextState.secSapSalesStoreCd : '',
|
|
priceCd: showPriceCd,
|
|
itemIdList: estimateContextState.itemList.filter((item) => item.delFlg === '0' && item.paDispOrder === null),
|
|
}
|
|
|
|
if (param.itemIdList.length > 0) {
|
|
let pass = true
|
|
|
|
param.itemIdList.map((item) => {
|
|
if (item.itemId === '') {
|
|
pass = false
|
|
}
|
|
})
|
|
|
|
if (!pass) {
|
|
//Pricing이 누락된 아이템이 있습니다. 제품 선택 후 Pricing을 진행해주세요.
|
|
return swalFire({
|
|
text: getMessage('estimate.detail.showPrice.pricingBtn.noItemId'),
|
|
type: 'alert',
|
|
icon: 'warning',
|
|
})
|
|
}
|
|
}
|
|
setIsGlobalLoading(true)
|
|
await promisePost({ url: '/api/estimate/price/item-price-list', data: param }).then((res) => {
|
|
let updateList = []
|
|
if (res) {
|
|
if (res.status === 200) {
|
|
const data = res.data
|
|
//기존itemList랑 프라이싱결과랑 비교해서 단가만 업뎃 서로 갯수가 안맞을 수 있음 없는 itemId면 unitPrice 0으로
|
|
//itemId로 비교해서 salePrice만 업데이트
|
|
if (data.result.code === 200) {
|
|
setEstimateContextState({
|
|
pkgAsp: data?.data?.pkgUnitPrice,
|
|
})
|
|
//주택PKG단가 체인지 이벤트 발생시키기
|
|
onChangePkgAsp(data.data.pkgUnitPrice)
|
|
|
|
if (isNotEmptyArray(data.data2)) {
|
|
estimateContextState.itemList.map((item) => {
|
|
let checkYn = false
|
|
for (let i = 0; i < data.data2.length; i++) {
|
|
if (data.data2[i]) {
|
|
if (data.data2[i].itemId === item.itemId) {
|
|
updateList.push({
|
|
...item,
|
|
openFlg: data.data2[i].unitPrice === '0.0' ? '1' : '0',
|
|
unitOpenFlg: (showPriceCd === 'QSP_PRICE' && item.openFlg === '1') ? '1' : '0',
|
|
salePrice: data.data2[i].unitPrice === null ? '0' : data.data2[i].unitPrice,
|
|
saleTotPrice: (item.amount * data.data2[i].unitPrice).toString(),
|
|
})
|
|
checkYn = true
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!checkYn) {
|
|
updateList.push({ ...item, salePrice: '0', saleTotPrice: '0' })
|
|
}
|
|
})
|
|
|
|
setEstimateContextState({
|
|
priceCd: showPriceCd,
|
|
itemList: updateList,
|
|
})
|
|
|
|
setItemChangeYn(true)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
setIsGlobalLoading(false)
|
|
})
|
|
}
|
|
|
|
const getAbledItems = (items) => {
|
|
return items.filter((items) => items.dispCableFlg !== '1' && items.paDispOrder === null)
|
|
}
|
|
|
|
const onChangeSelectAll = (e) => {
|
|
if (e.target.checked) {
|
|
const allCheckedSelection = new Set(getAbledItems(estimateContextState.itemList).map((item) => item.dispOrder))
|
|
|
|
setSelection(allCheckedSelection)
|
|
} else {
|
|
setSelection(new Set())
|
|
}
|
|
}
|
|
|
|
const isSelectedAll = () => {
|
|
return selection.size === getAbledItems(estimateContextState.itemList).length
|
|
}
|
|
|
|
//아이템row 체크박스 컨트롤
|
|
const onChangeSelect = (dispOrder) => {
|
|
const newSelection = new Set(selection)
|
|
if (newSelection.has(dispOrder)) {
|
|
newSelection.delete(dispOrder)
|
|
} else {
|
|
newSelection.add(dispOrder)
|
|
}
|
|
|
|
setSelection(newSelection)
|
|
}
|
|
|
|
//주택PKG input 변경
|
|
const onChangePkgAsp = (value) => {
|
|
if (estimateContextState.estimateType === 'YJSS') {
|
|
let newValue = (value || '0').replace(/[^0-9.]/g, '')
|
|
if (newValue.length > 1) {
|
|
newValue = newValue.replace(/(^0+)/, '')
|
|
if (newValue.length === 0) {
|
|
newValue = '0'
|
|
}
|
|
}
|
|
|
|
const parts = newValue.split('.')
|
|
if (parts.length > 2) {
|
|
newValue = parts[0] + '.' + parts.slice(1).join('')
|
|
}
|
|
|
|
if (parts[1] && parts[1].length > 2) {
|
|
newValue = parts[0] + '.' + parts[1].substring(0, 2)
|
|
}
|
|
|
|
let pkgAsp = normalizeDecimal(newValue || '0')
|
|
|
|
//현재 PKG용량값 가져오기
|
|
let totVolKw = estimateContextState.totVolKw * 1000
|
|
// let pkgTotPrice = parseFloat(pkgAsp?.replaceAll(',', '')) * totVolKw * 1000
|
|
|
|
const pkgAspNumber = Number(normalizeDecimal(pkgAsp))
|
|
const pkgTotPrice = pkgAspNumber * totVolKw * 1000
|
|
|
|
setEstimateContextState({
|
|
pkgAsp: pkgAsp,
|
|
pkgTotPrice: pkgTotPrice.toFixed(2),
|
|
})
|
|
//아이템들 중 조건에 맞는애들 뽑아서 상단 공급가액 부가세 총액 수정
|
|
setItemChangeYn(true)
|
|
}
|
|
}
|
|
|
|
// 수량 변경
|
|
const onChangeAmount = (value, dispOrder, index) => {
|
|
//itemChangeFlg = 1, partAdd = 0 셋팅
|
|
let amount = Number(normalizeDigits(value))
|
|
|
|
if (isNaN(amount)) {
|
|
amount = '0'
|
|
} else {
|
|
amount = amount.toLocaleString()
|
|
}
|
|
|
|
let updateList = []
|
|
let updates = {}
|
|
updates.amount = amount
|
|
updates.itemChangeFlg = '1'
|
|
updates.partAdd = '0'
|
|
updates.saleTotPrice = (Number(amount.replaceAll(',', '')) * estimateContextState.itemList[index].salePrice.replaceAll(',', '')).toLocaleString()
|
|
updates.showSaleTotPrice = (
|
|
Number(amount.replaceAll(',', '')) * estimateContextState.itemList[index].salePrice?.replaceAll(',', '')
|
|
).toLocaleString()
|
|
|
|
updateList = estimateContextState.itemList.map((item) => {
|
|
if (item.dispOrder === dispOrder) {
|
|
return { ...item, ...updates }
|
|
} else if (item.paDispOrder === dispOrder) {
|
|
return { ...item, ...updates, amount: (item.bomAmount * amount?.replaceAll(',', '')).toLocaleString(), saleTotPrice: '0' }
|
|
} else {
|
|
return item
|
|
}
|
|
})
|
|
|
|
setEstimateContextState({
|
|
itemList: updateList,
|
|
})
|
|
|
|
setItemChangeYn(true)
|
|
}
|
|
|
|
// 단가 변경
|
|
const onChangeSalePrice = (value, dispOrder, index) => {
|
|
//itemChangeFlg, partAdd 받아온 그대로
|
|
let salePrice = Number(normalizeDecimal(value))
|
|
|
|
if (isNaN(salePrice)) {
|
|
salePrice = 0
|
|
} else {
|
|
salePrice = salePrice.toLocaleString()
|
|
}
|
|
let updateList = []
|
|
let updates = {}
|
|
updates.salePrice = salePrice
|
|
updates.saleTotPrice = (Number(salePrice.replaceAll(',', '')) * estimateContextState.itemList[index].amount.replaceAll(',', '')).toLocaleString()
|
|
updates.showSalePrice = updates.salePrice
|
|
updates.showSaleTotPrice = updates.saleTotPrice
|
|
|
|
updateList = estimateContextState.itemList.map((item) => {
|
|
if (item.dispOrder === dispOrder) {
|
|
return { ...item, ...updates }
|
|
} else {
|
|
return item
|
|
}
|
|
})
|
|
|
|
setEstimateContextState({
|
|
itemList: updateList,
|
|
})
|
|
|
|
setItemChangeYn(true)
|
|
}
|
|
|
|
/* 케이블 select 변경시 */
|
|
const onChangeDisplayCableItem = (value, itemList) => {
|
|
itemList.map((item, index) => {
|
|
if (item.dispCableFlg === '1' && item.itemTpCd !== 'M12' && item.itemTpCd !== 'S13') {
|
|
if (value !== '') {
|
|
onChangeDisplayItem(value, item.dispOrder, index, true)
|
|
}
|
|
}
|
|
})
|
|
setCableItem(value)
|
|
}
|
|
|
|
/* 케이블 select 변경시 */
|
|
const onChangeDisplayDoubleCableItem = (value, itemList) => {
|
|
itemList.map((item, index) => {
|
|
if (item.dispCableFlg === '1' && (item.itemTpCd === 'M12' || item.itemTpCd === 'S13')) {
|
|
if (value !== '') {
|
|
onChangeDisplayItem(value, item.dispOrder, index, true)
|
|
}
|
|
}
|
|
})
|
|
setCableDbItem(value)
|
|
}
|
|
|
|
// 아이템 자동완성 검색시 아이템 추가/변경시
|
|
const onChangeDisplayItem = (itemId, dispOrder, index, flag) => {
|
|
const param = {
|
|
itemId: itemId,
|
|
coldZoneFlg: estimateContextState?.coldRegionFlg,
|
|
saltAffectedFlg: estimateContextState?.saltAreaFlg,
|
|
}
|
|
const apiUrl = `/api/display-item/item-detail?${queryStringFormatter(param)}`
|
|
let updateList = []
|
|
let updates = {}
|
|
get({ url: apiUrl }).then((res) => {
|
|
updates.objectNo = objectNo
|
|
updates.planNo = planNo
|
|
updates.itemId = res.itemId
|
|
updates.itemNo = res.itemNo
|
|
updates.itemName = res.itemName
|
|
updates.itemChangeFlg = '1' //무조건 1
|
|
updates.partAdd = '1' //무조건1 NEW
|
|
updates.fileUploadFlg = res.fileUploadFlg
|
|
updates.unit = res.unit
|
|
updates.unitPrice = res.salePrice //unitPrice도 salePrice로
|
|
updates.moduleFlg = res.moduleFlg
|
|
updates.pkgMaterialFlg = res.pkgMaterialFlg
|
|
updates.pnowW = res.pnowW
|
|
updates.salePrice = res.salePrice
|
|
updates.specification = res.specification
|
|
updates.unit = res.unit
|
|
updates.specialNoteCd = res.spnAttrCds
|
|
updates.itemGroup = res.itemGroup
|
|
updates.delFlg = '0' // 삭제플래그 0
|
|
updates.saleTotPrice = (res.salePrice * estimateContextState.itemList[index].amount).toString()
|
|
updates.amount = flag ? estimateContextState.itemList[index].amount : ''
|
|
updates.openFlg = res.openFlg
|
|
|
|
if (estimateContextState.estimateType === 'YJSS') {
|
|
if (res.pkgMaterialFlg === '0') {
|
|
updates.showSalePrice = '0'
|
|
updates.showSaleTotPrice = '0'
|
|
}
|
|
} else {
|
|
if (res.openFlg === '1') {
|
|
updates.showSalePrice = '0'
|
|
updates.showSaleTotPrice = '0'
|
|
}
|
|
}
|
|
|
|
//104671
|
|
let bomList = res.itemBomList
|
|
|
|
updateList = estimateContextState.itemList.map((item) => {
|
|
if (item.dispOrder === dispOrder) {
|
|
if (item?.addFlg) {
|
|
return { ...item, ...updates, saleTotPrice: '' }
|
|
} else {
|
|
if (estimateContextState.estimateType === 'YJSS') {
|
|
if (updates.pkgMaterialFlg === '1') {
|
|
return { ...item, ...updates, showSalePrice: updates.salePrice }
|
|
} else {
|
|
return { ...item, ...updates, salePrice: '', saleTotPrice: '' }
|
|
}
|
|
} else {
|
|
return { ...item, ...updates }
|
|
}
|
|
}
|
|
} else if (item.paDispOrder === dispOrder) {
|
|
return { ...item, delFlg: '1' }
|
|
} else {
|
|
return item
|
|
}
|
|
})
|
|
//paDispOrder
|
|
if (bomList) {
|
|
bomList.map((bomItem, index) => {
|
|
let maxItemDispOrder = Math.max(...estimateContextState.itemList.map((item) => item.dispOrder))
|
|
if (maxItemDispOrder == dispOrder) {
|
|
bomItem.dispOrder = (index + 1 + maxItemDispOrder).toString()
|
|
bomItem.paDispOrder = dispOrder
|
|
bomItem.salePrice = '0'
|
|
bomItem.saleTotPrice = '0'
|
|
bomItem.unitPrice = '0'
|
|
bomItem.showSalePrice = '0'
|
|
} else {
|
|
bomItem.dispOrder = (index + 1 + Number(dispOrder)).toString()
|
|
bomItem.paDispOrder = dispOrder
|
|
bomItem.salePrice = '0'
|
|
bomItem.saleTotPrice = '0'
|
|
bomItem.unitPrice = '0'
|
|
bomItem.showSalePrice = '0'
|
|
}
|
|
|
|
bomItem.delFlg = '0'
|
|
bomItem.objectNo = objectNo
|
|
bomItem.planNo = planNo
|
|
bomItem.addFlg = true //봄 추가시도 addFlg
|
|
bomItem.openFlg = '0' //봄 컴포넌트는 무조건 0으로
|
|
})
|
|
|
|
updateList = updateList.filter((item) => item.delFlg === '0')
|
|
setEstimateContextState({
|
|
itemList: [...updateList, ...bomList],
|
|
})
|
|
} else {
|
|
setEstimateContextState({
|
|
itemList: updateList,
|
|
})
|
|
}
|
|
|
|
setItemChangeYn(true)
|
|
})
|
|
}
|
|
|
|
//제품 삭제
|
|
const removeItem = () => {
|
|
const array = [...selection]
|
|
if (isEmptyArray(array)) {
|
|
return swalFire({
|
|
text: getMessage('estimate.detail.alert.selectDelItem'),
|
|
type: 'alert',
|
|
icon: 'warning',
|
|
})
|
|
}
|
|
let delList = []
|
|
estimateContextState.itemList.filter((row) => {
|
|
array.map((row2) => {
|
|
if (row2 === row.dispOrder) {
|
|
delList.push({ ...row })
|
|
}
|
|
if (row2 === row.paDispOrder) {
|
|
delList.push({ ...row })
|
|
}
|
|
})
|
|
})
|
|
|
|
const updateList = estimateContextState.itemList.map((item) => {
|
|
const isDeleted = delList.some((row) => item.delFlg === '1' || item.dispOrder === row.dispOrder)
|
|
return {
|
|
...item,
|
|
delFlg: isDeleted ? '1' : '0',
|
|
}
|
|
})
|
|
|
|
let delCnt = 0
|
|
updateList.map((item) => {
|
|
if (item.delFlg === '1') {
|
|
delCnt++
|
|
}
|
|
})
|
|
|
|
if (delCnt === updateList.length) {
|
|
return swalFire({
|
|
text: getMessage('estimate.detail.save.requiredItem'),
|
|
type: 'alert',
|
|
icon: 'warning',
|
|
})
|
|
}
|
|
|
|
setEstimateContextState({
|
|
itemList: updateList,
|
|
})
|
|
|
|
setSelection(new Set())
|
|
setItemChangeYn(true)
|
|
}
|
|
|
|
useEffect(() => {
|
|
if (estimateContextState.resetFlag === 'Y') {
|
|
makeUniqueSpecialNoteCd(estimateContextState.itemList)
|
|
}
|
|
if (itemChangeYn) {
|
|
let totals = {
|
|
totAmount: 0,
|
|
totVolKw: 0,
|
|
supplyPrice: 0,
|
|
vatPrice: 0,
|
|
totPrice: 0,
|
|
addSupplyPrice: 0,
|
|
pkgTotPrice: 0,
|
|
}
|
|
|
|
const calculateYJODTotals = (itemList) => {
|
|
itemList.sort((a, b) => a.dispOrder - b.dispOrder)
|
|
makeUniqueSpecialNoteCd(itemList)
|
|
|
|
itemList.forEach((item) => {
|
|
delete item.showSalePrice
|
|
delete item.showSaleTotPrice
|
|
if (item.delFlg === '0') {
|
|
let amount = Number(normalizeDigits(item.amount)) || 0
|
|
let price
|
|
if (amount === 0) {
|
|
price = 0
|
|
} else {
|
|
price = Number(item.saleTotPrice?.replaceAll(',', '')) || 0
|
|
}
|
|
|
|
if (item.moduleFlg === '1') {
|
|
const volKw = (item.pnowW * amount) / 1000
|
|
totals.totVolKw += volKw
|
|
}
|
|
totals.supplyPrice += price
|
|
totals.totAmount += amount
|
|
|
|
if (item.paDispOrder) {
|
|
item.showSalePrice = '0'
|
|
item.showSaleTotPrice = '0'
|
|
}
|
|
if (item.openFlg === '1') {
|
|
item.showSalePrice = '0'
|
|
item.showSaleTotPrice = '0'
|
|
}
|
|
}
|
|
})
|
|
|
|
totals.vatPrice = totals.supplyPrice * 0.1
|
|
totals.totPrice = totals.supplyPrice + totals.vatPrice
|
|
}
|
|
|
|
const calculateYJSSTotals = (itemList) => {
|
|
itemList.sort((a, b) => a.dispOrder - b.dispOrder)
|
|
makeUniqueSpecialNoteCd(itemList)
|
|
itemList.forEach((item) => {
|
|
if (item.delFlg === '0') {
|
|
let amount = Number(normalizeDigits(item.amount)) || 0
|
|
let salePrice
|
|
if (item.moduleFlg === '1') {
|
|
const volKw = (item.pnowW * amount) / 1000
|
|
totals.totVolKw += volKw
|
|
}
|
|
if (amount === 0) {
|
|
salePrice = 0
|
|
} else {
|
|
salePrice = Number(item.salePrice?.replaceAll(',', '')) || 0
|
|
}
|
|
|
|
totals.totAmount += amount
|
|
if (item.pkgMaterialFlg === '1') {
|
|
const saleTotPrice = amount * salePrice
|
|
totals.addSupplyPrice += saleTotPrice
|
|
}
|
|
|
|
if (!item.paDispOrder) {
|
|
if (item.pkgMaterialFlg === '0') {
|
|
item.showSalePrice = '0'
|
|
item.showSaleTotPrice = '0'
|
|
}
|
|
} else {
|
|
item.showSalePrice = '0'
|
|
item.showSaleTotPrice = '0'
|
|
}
|
|
|
|
if (item.openFlg === '1') {
|
|
item.showSalePrice = '0'
|
|
item.showSaleTotPrice = '0'
|
|
}
|
|
}
|
|
})
|
|
//let pkgAsp = estimateContextState.pkgAsp ? Number(estimateContextState.pkgAsp.replaceAll(',', '')) : 0
|
|
const pkgAsp = Number(normalizeDecimal(estimateContextState.pkgAsp))
|
|
totals.pkgTotPrice = pkgAsp * totals.totVolKw * 1000
|
|
totals.supplyPrice = totals.addSupplyPrice + totals.pkgTotPrice
|
|
totals.vatPrice = totals.supplyPrice * 0.1
|
|
totals.totPrice = totals.supplyPrice + totals.vatPrice
|
|
}
|
|
if (estimateContextState.estimateType === 'YJOD') {
|
|
calculateYJODTotals(estimateContextState.itemList)
|
|
setEstimateContextState({
|
|
totAmount: totals.totAmount,
|
|
totVolKw: totals.totVolKw.toFixed(2),
|
|
supplyPrice: totals.supplyPrice.toFixed(0), //소수첫자리에서 반올림
|
|
vatPrice: totals.vatPrice.toFixed(0), //소수첫자리에서 반올림
|
|
totPrice: totals.totPrice.toFixed(0), //소수첫자리에서 반올림
|
|
})
|
|
} else if (estimateContextState.estimateType === 'YJSS') {
|
|
calculateYJSSTotals(estimateContextState.itemList)
|
|
setEstimateContextState({
|
|
pkgTotPrice: totals.pkgTotPrice,
|
|
totAmount: totals.totAmount,
|
|
totVolKw: totals.totVolKw.toFixed(2),
|
|
supplyPrice: totals.supplyPrice.toFixed(0), //소수첫자리에서 반올림
|
|
vatPrice: totals.vatPrice.toFixed(0), //소수첫자리에서 반올림
|
|
totPrice: totals.totPrice.toFixed(0), //소수첫자리에서 반올림
|
|
})
|
|
}
|
|
|
|
setItemChangeYn(false)
|
|
} else {
|
|
let totals = {
|
|
totAmount: 0,
|
|
totVolKw: 0,
|
|
supplyPrice: 0,
|
|
vatPrice: 0,
|
|
totPrice: 0,
|
|
addSupplyPrice: 0,
|
|
pkgTotPrice: 0,
|
|
}
|
|
estimateContextState.itemList.sort((a, b) => a.dispOrder - b.dispOrder)
|
|
makeUniqueSpecialNoteCd(estimateContextState.itemList)
|
|
|
|
if (estimateContextState.estimateType === 'YJSS') {
|
|
estimateContextState.itemList.forEach((item) => {
|
|
if (estimateContextState.estimateType === 'YJSS' && !item.paDispOrder && item.pkgMaterialFlg === '0') {
|
|
item.showSalePrice = '0'
|
|
item.showSaleTotPrice = '0'
|
|
}
|
|
if (estimateContextState.estimateType === 'YJSS' && item.openFlg === '1') {
|
|
item.showSalePrice = '0'
|
|
item.showSaleTotPrice = '0'
|
|
}
|
|
if (estimateContextState.estimateType === 'YJSS' && item.paDispOrder) {
|
|
item.showSalePrice = '0'
|
|
item.showSaleTotPrice = '0'
|
|
}
|
|
})
|
|
let dispCableFlgCnt = 0
|
|
estimateContextState.itemList.forEach((item) => {
|
|
if (item.delFlg === '0') {
|
|
let amount = Number(normalizeDigits(item.amount)) || 0
|
|
let salePrice
|
|
if (item.moduleFlg === '1') {
|
|
const volKw = (item.pnowW * amount) / 1000
|
|
totals.totVolKw += volKw
|
|
}
|
|
if (amount === 0) {
|
|
salePrice = 0
|
|
} else {
|
|
salePrice = Number(item.salePrice?.replaceAll(',', '')) || 0
|
|
}
|
|
|
|
totals.totAmount += amount
|
|
if (item.pkgMaterialFlg === '1') {
|
|
const saleTotPrice = amount * salePrice
|
|
totals.addSupplyPrice += saleTotPrice
|
|
}
|
|
|
|
if (!item.paDispOrder) {
|
|
if (item.pkgMaterialFlg === '0') {
|
|
item.showSalePrice = '0'
|
|
item.showSaleTotPrice = '0'
|
|
}
|
|
} else {
|
|
item.showSalePrice = '0'
|
|
item.showSaleTotPrice = '0'
|
|
}
|
|
|
|
if (item.openFlg === '1') {
|
|
item.showSalePrice = '0'
|
|
item.showSaleTotPrice = '0'
|
|
}
|
|
|
|
if (item.dispCableFlg === '1') {
|
|
dispCableFlgCnt++
|
|
if(item.itemTpCd === 'M12' || item.itemTpCd === 'S13') {
|
|
setCableDbItem(item.itemId)
|
|
}else{
|
|
setCableItem(item.itemId)
|
|
}
|
|
}
|
|
}
|
|
})
|
|
|
|
if (dispCableFlgCnt === 0) {
|
|
setCableItem('100038')
|
|
setCableDbItem('100037')
|
|
}
|
|
|
|
// let pkgAsp = estimateContextState.pkgAsp ? Number(estimateContextState.pkgAsp.replaceAll(',', '')) : 0
|
|
const pkgAsp = Number(normalizeDecimal(estimateContextState.pkgAsp))
|
|
totals.pkgTotPrice = pkgAsp * totals.totVolKw * 1000
|
|
|
|
totals.supplyPrice = totals.addSupplyPrice + totals.pkgTotPrice
|
|
totals.vatPrice = totals.supplyPrice * 0.1
|
|
totals.totPrice = totals.supplyPrice + totals.vatPrice
|
|
|
|
setEstimateContextState({
|
|
pkgTotPrice: totals.pkgTotPrice,
|
|
totAmount: totals.totAmount,
|
|
totVolKw: totals.totVolKw.toFixed(2),
|
|
supplyPrice: totals.supplyPrice.toFixed(0), //소수첫자리에서 반올림
|
|
vatPrice: totals.vatPrice.toFixed(0), //소수첫자리에서 반올림
|
|
totPrice: totals.totPrice.toFixed(0), //소수첫자리에서 반올림
|
|
})
|
|
} else {
|
|
estimateContextState.itemList.forEach((item) => {
|
|
if (estimateContextState.estimateType === 'YJOD' && item.openFlg === '1') {
|
|
item.showSalePrice = '0'
|
|
item.showSaleTotPrice = '0'
|
|
}
|
|
if (estimateContextState.estimateType === 'YJOD' && item.paDispOrder) {
|
|
item.showSalePrice = '0'
|
|
item.showSaleTotPrice = '0'
|
|
}
|
|
})
|
|
|
|
let dispCableFlgCnt = 0
|
|
estimateContextState.itemList.forEach((item) => {
|
|
delete item.showSalePrice
|
|
delete item.showSaleTotPrice
|
|
if (item.delFlg === '0') {
|
|
let amount = Number(normalizeDigits(item.amount)) || 0
|
|
let price
|
|
if (amount === 0) {
|
|
price = 0
|
|
} else {
|
|
price = Number(item.saleTotPrice?.replaceAll(',', '')) || 0
|
|
}
|
|
|
|
if (item.moduleFlg === '1') {
|
|
const volKw = (item.pnowW * amount) / 1000
|
|
totals.totVolKw += volKw
|
|
}
|
|
totals.supplyPrice += price
|
|
totals.totAmount += amount
|
|
|
|
if (item.paDispOrder) {
|
|
item.showSalePrice = '0'
|
|
item.showSaleTotPrice = '0'
|
|
}
|
|
if (item.openFlg === '1') {
|
|
item.showSalePrice = '0'
|
|
item.showSaleTotPrice = '0'
|
|
}
|
|
|
|
if (item.dispCableFlg === '1') {
|
|
dispCableFlgCnt++
|
|
if(item.itemTpCd === 'M12' || item.itemTpCd === 'S13') {
|
|
setCableDbItem(item.itemId)
|
|
}else{
|
|
setCableItem(item.itemId)
|
|
}
|
|
}
|
|
}
|
|
})
|
|
|
|
if (dispCableFlgCnt === 0) {
|
|
setCableItem('100038')
|
|
setCableDbItem('100037')
|
|
}
|
|
|
|
totals.vatPrice = totals.supplyPrice * 0.1
|
|
totals.totPrice = totals.supplyPrice + totals.vatPrice
|
|
|
|
setEstimateContextState({
|
|
totAmount: totals.totAmount,
|
|
totVolKw: totals.totVolKw.toFixed(2),
|
|
supplyPrice: totals.supplyPrice.toFixed(0), //소수첫자리에서 반올림
|
|
vatPrice: totals.vatPrice.toFixed(0), //소수첫자리에서 반올림
|
|
totPrice: totals.totPrice.toFixed(0), //소수첫자리에서 반올림
|
|
})
|
|
}
|
|
}
|
|
}, [itemChangeYn, estimateContextState.itemList])
|
|
|
|
//안건명 인풋 변경
|
|
const handleBlurObjectName = (e) => {
|
|
setEstimateContextState({ objectName: e.target.value })
|
|
}
|
|
|
|
//담당자 인풋 변경
|
|
const handleBlurCharger = (e) => {
|
|
setEstimateContextState({ charger: e.target.value })
|
|
}
|
|
|
|
//비고 인풋 변경
|
|
const handleBlurRemarks = (e) => {
|
|
setEstimateContextState({ remarks: e.target.value })
|
|
}
|
|
|
|
useEffect(() => {
|
|
setSpecialNoteFirstFlg(false)
|
|
}, [estimateContextState.resetFlag])
|
|
|
|
useEffect(() => {
|
|
if (estimateContextState?.itemList.length > 0) {
|
|
const tempList = estimateContextState.itemList.filter((item) => !displayItemList.some((resItem) => resItem.itemId === item.itemId))
|
|
if (tempList.length > 0) {
|
|
setDisplayItemList((prevList) => [...prevList, ...tempList])
|
|
}
|
|
}
|
|
}, [estimateContextState])
|
|
|
|
useEffect(() => {
|
|
if (cableItemList.lenght > 0 || estimateContextState?.itemList.length > 0) {
|
|
let dispCableFlgCnt = 0
|
|
estimateContextState.itemList.map((item) => {
|
|
if (item.dispCableFlg === '1') {
|
|
dispCableFlgCnt++
|
|
cableItemList.map((cable) => {
|
|
if (item.itemId === cable.clRefChr1) {
|
|
cable.clRefChr3 = item.itemName
|
|
}
|
|
})
|
|
}
|
|
})
|
|
|
|
if (dispCableFlgCnt === 0) {
|
|
setCableItem('100038')
|
|
setCableDbItem('100037')
|
|
}
|
|
}
|
|
}, [estimateContextState?.itemList, cableItemList])
|
|
|
|
const [agencyCustList, setAgencyCustList] = useState([])
|
|
useEffect(() => {
|
|
// 952 - 2차점 특가 sapSalesStoreCd
|
|
if (estimateContextState?.sapSalesStoreCd && session?.storeLvl === '1') {
|
|
const param = {
|
|
sapSalesStoreCd: estimateContextState.sapSalesStoreCd,
|
|
}
|
|
const apiUrl = `api/estimate/agency-cust-list?${queryStringFormatter(param)}`
|
|
get({ url: apiUrl }).then((res) => {
|
|
if (isNotEmptyArray(res?.data)) {
|
|
setAgencyCustList(res?.data)
|
|
}
|
|
})
|
|
}
|
|
}, [estimateContextState?.sapSalesStoreCd])
|
|
return (
|
|
<div className="sub-content estimate">
|
|
<div className="sub-content-inner">
|
|
{/* 물건번호, 견적서번호, 등록일, 변경일시 시작 */}
|
|
<div className="sub-content-box">
|
|
<div className="sub-table-box">
|
|
<div className="estimate-list-wrap one">
|
|
<div className="estimate-box">
|
|
<div className="estimate-tit">{getMessage('estimate.detail.objectNo')}</div>
|
|
<div className="estimate-name">
|
|
{currentObjectNo} (Plan No: {currentPid})
|
|
</div>
|
|
</div>
|
|
<div className="estimate-box">
|
|
<div className="estimate-tit">{getMessage('estimate.detail.docNo')}</div>
|
|
<div className="estimate-name">{estimateContextState.docNo}</div>
|
|
</div>
|
|
<div className="estimate-box">
|
|
<div className="estimate-tit">{getMessage('estimate.detail.drawingEstimateCreateDate')}</div>
|
|
<div className="estimate-name">
|
|
{estimateContextState?.drawingEstimateCreateDate
|
|
? `${dayjs(estimateContextState.drawingEstimateCreateDate).format('YYYY.MM.DD')}`
|
|
: ''}
|
|
</div>
|
|
</div>
|
|
<div className="estimate-box">
|
|
<div className="estimate-tit">{getMessage('estimate.detail.lastEditDatetime')}</div>
|
|
<div className="estimate-name">
|
|
{estimateContextState?.lastEditDatetime ? `${dayjs(estimateContextState.lastEditDatetime).format('YYYY.MM.DD HH:mm')}` : ''}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{/* 물건번호, 견적서번호, 등록일, 변경일시 끝 */}
|
|
{/* 기본정보 시작 */}
|
|
<div className="sub-content-box">
|
|
<div className="sub-table-box">
|
|
<div className="table-box-title-wrap">
|
|
<div className="title-wrap">
|
|
<h3>{getMessage('estimate.detail.header.title')}</h3>
|
|
</div>
|
|
</div>
|
|
<div className="common-table bt-able">
|
|
<table>
|
|
<colgroup>
|
|
<col style={{ width: '160px' }} />
|
|
<col />
|
|
<col style={{ width: '160px' }} />
|
|
<col />
|
|
</colgroup>
|
|
<tbody>
|
|
<tr>
|
|
{/* 1차 판매점명 */}
|
|
<th>{getMessage('estimate.detail.saleStoreId')}</th>
|
|
<td>{estimateContextState?.firstSaleStoreName}</td>
|
|
{/* 견적일 */}
|
|
<th>
|
|
{getMessage('estimate.detail.estimateDate')} <span className="important">*</span>
|
|
</th>
|
|
<td>
|
|
<div className="date-picker" style={{ width: '350px' }}>
|
|
<SingleDatePicker {...singleDatePickerProps} />
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
{/* 2차 판매점명 */}
|
|
<th>{getMessage('estimate.detail.otherSaleStoreId')}</th>
|
|
<td>
|
|
{session?.storeLvl === '1' && estimateContextState?.saleStoreLevel === '1'
|
|
? getMessage('estimate.detail.noOtherSaleStoreId')
|
|
: estimateContextState?.agencySaleStoreName}
|
|
</td>
|
|
{/* 담당자 */}
|
|
<th>
|
|
{getMessage('estimate.detail.receiveUser')} <span className="important">*</span>
|
|
</th>
|
|
<td>
|
|
<div className="input-wrap" style={{ width: '350px' }}>
|
|
<input
|
|
type="text"
|
|
className="input-light"
|
|
value={estimateContextState?.charger || ''}
|
|
onBlur={handleBlurCharger}
|
|
onChange={handleBlurCharger}
|
|
/>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
{/* 안건명 */}
|
|
<th>
|
|
{getMessage('estimate.detail.objectName')} <span className="important">*</span>
|
|
</th>
|
|
<td colSpan={3}>
|
|
<div className="form-flex-wrap">
|
|
<div className="input-wrap mr5" style={{ width: '610px' }}>
|
|
<input
|
|
type="text"
|
|
className="input-light"
|
|
value={estimateContextState?.objectName || ''}
|
|
onBlur={handleBlurObjectName}
|
|
onChange={handleBlurObjectName}
|
|
/>
|
|
</div>
|
|
<div className="select-wrap" style={{ width: '200px' }}>
|
|
<Select
|
|
id="objectNameOmit"
|
|
instanceId="objectNameOmit"
|
|
className="react-select-custom"
|
|
classNamePrefix="custom"
|
|
placeholder="Select"
|
|
options={honorificCodeList}
|
|
onChange={(e) => {
|
|
if (isObjectNotEmpty(e)) {
|
|
setEstimateContextState({ objectNameOmit: e.clCodeNm })
|
|
} else {
|
|
setEstimateContextState({ objectNameOmit: '' })
|
|
}
|
|
}}
|
|
getOptionLabel={(x) => x.clCodeNm}
|
|
getOptionValue={(x) => x.clCode}
|
|
isClearable={true}
|
|
isSearchable={false}
|
|
value={honorificCodeList.filter(function (option) {
|
|
return option.clCodeNm === estimateContextState.objectNameOmit
|
|
})}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
{/* 물건정보에서 입력한 메모 */}
|
|
<th>{getMessage('estimate.detail.objectRemarks')}</th>
|
|
<td colSpan={3}>{estimateContextState?.objectRemarks}</td>
|
|
</tr>
|
|
<tr>
|
|
{/* 주문분류 */}
|
|
<th>
|
|
{getMessage('estimate.detail.estimateType')} <span className="important">*</span>
|
|
</th>
|
|
<td colSpan={3}>
|
|
<div className="form-flex-wrap">
|
|
<div className="radio-wrap">
|
|
{/*pkgRank is null, empty 인 경우 : 사용불가, 이전에 등록된 경우 사용가능, style로 제어*/}
|
|
<div
|
|
className="d-check-radio light mr10"
|
|
style={{
|
|
display:
|
|
(isNotEmptyArray(storePriceList) > 0 && storePriceList[0].pkgRank !== null && storePriceList[0].pkgRank !== '') ||
|
|
estimateContextState?.estimateType === 'YJSS'
|
|
? ''
|
|
: 'none',
|
|
}}
|
|
>
|
|
<input
|
|
type="radio"
|
|
name="estimateType"
|
|
id="YJSS"
|
|
value={'YJSS'}
|
|
checked={estimateContextState?.estimateType === 'YJSS' ? true : false}
|
|
onChange={(e) => {
|
|
//주문분류
|
|
setHandlePricingFlag(true)
|
|
setEstimateContextState({ estimateType: e.target.value, setEstimateContextState })
|
|
}}
|
|
/>
|
|
<label htmlFor="YJSS">{getMessage('estimate.detail.estimateType.yjss')}</label>
|
|
</div>
|
|
<div className="d-check-radio light">
|
|
<input
|
|
type="radio"
|
|
name="estimateType"
|
|
id="YJOD"
|
|
value={'YJOD'}
|
|
checked={estimateContextState?.estimateType === 'YJOD' ? true : false}
|
|
onChange={(e) => {
|
|
setHandlePricingFlag(true)
|
|
setEstimateContextState({ estimateType: e.target.value })
|
|
}}
|
|
/>
|
|
<label htmlFor="YJOD">{getMessage('estimate.detail.estimateType.yjod')}</label>
|
|
</div>
|
|
</div>
|
|
{session?.storeLvl === '100000' && agencyCustList.length > 0 ? ( //일시적으로 1 => 100000로 정리
|
|
<div className="form-flex-select ml10">
|
|
<label htmlFor="">{getMessage('estimate.detail.agency')}</label>
|
|
<div className="select-wrap" style={{ width: '400px' }}>
|
|
<Select
|
|
id="agencyName"
|
|
instanceId="agencyName"
|
|
className="react-select-custom"
|
|
classNamePrefix="custom"
|
|
placeholder="Select"
|
|
options={agencyCustList}
|
|
onChange={(e) => {
|
|
if (isObjectNotEmpty(e)) {
|
|
setEstimateContextState({ secSapSalesStoreCd: e.sapSalesStoreCd })
|
|
} else {
|
|
setEstimateContextState({ secSapSalesStoreCd: '' })
|
|
}
|
|
}}
|
|
getOptionLabel={(x) => x.sapSalesStoreNm}
|
|
getOptionValue={(x) => x.sapSalesStoreCd}
|
|
isClearable={true}
|
|
isSearchable={true}
|
|
value={agencyCustList.filter(function (option) {
|
|
return option.sapSalesStoreCd === estimateContextState.secSapSalesStoreCd
|
|
})}
|
|
/>
|
|
</div>
|
|
</div>
|
|
) : (
|
|
''
|
|
)}
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
{/* 지붕재・사양시공 최대4개*/}
|
|
<th>{getMessage('estimate.detail.roofCns')}</th>
|
|
<td colSpan={3}>
|
|
{estimateContextState?.roofMaterialIdMulti?.split('、').map((row, index) => {
|
|
//지붕재
|
|
let roofList = row
|
|
let roofListLength = estimateContextState?.roofMaterialIdMulti?.split('、').length
|
|
let style = 'mb5'
|
|
if (roofListLength == index + 1) {
|
|
style = ''
|
|
}
|
|
//사양시공
|
|
let constructSpecificationMulti = estimateContextState?.constructSpecificationMulti?.split('、')
|
|
return (
|
|
<div className={`form-flex-wrap ${style}`} key={`roof_${index}_${row}`}>
|
|
<div className="input-wrap mr5" style={{ width: '610px' }}>
|
|
<input type="text" className="input-light" value={roofList || ''} readOnly />
|
|
</div>
|
|
{constructSpecificationMulti ? (
|
|
<div className="input-wrap" style={{ width: '200px' }}>
|
|
<input type="text" className="input-light" value={constructSpecificationMulti[index] || ''} readOnly />
|
|
</div>
|
|
) : null}
|
|
</div>
|
|
)
|
|
})}
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
{/* 비고 */}
|
|
<th>{getMessage('estimate.detail.remarks')}</th>
|
|
<td colSpan={3}>
|
|
<div className="input-wrap">
|
|
<input
|
|
type="text"
|
|
className="input-light"
|
|
value={estimateContextState?.remarks || ''}
|
|
onBlur={handleBlurRemarks}
|
|
onChange={handleBlurRemarks}
|
|
/>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
{/* 파일첨부 시작 */}
|
|
<div className="table-box-title-wrap">
|
|
<div className="title-wrap">
|
|
<h3>{getMessage('estimate.detail.header.fileList1')}</h3>
|
|
<div className="d-check-box light mr5">
|
|
<input
|
|
type="checkbox"
|
|
id="next"
|
|
checked={estimateContextState?.fileFlg === '0' || estimateContextState?.fileFlg === null ? false : true}
|
|
onChange={(e) => {
|
|
setEstimateContextState({
|
|
fileFlg: e.target.checked ? '1' : '0',
|
|
})
|
|
if (e.target.checked) {
|
|
if (specialNoteList.length > 0) {
|
|
specialNoteList.map((item) => {
|
|
if (item.code === 'ATTR019') {
|
|
item.check = true
|
|
}
|
|
})
|
|
}
|
|
} else {
|
|
if (specialNoteList.length > 0) {
|
|
specialNoteList.map((item) => {
|
|
if (item.code === 'ATTR019') {
|
|
item.check = false
|
|
}
|
|
})
|
|
}
|
|
}
|
|
}}
|
|
/>
|
|
<label htmlFor="next" style={{ color: '#101010' }}>
|
|
{getMessage('estimate.detail.fileFlg')}
|
|
</label>
|
|
</div>
|
|
{estimateContextState?.northArrangement === '1' && (
|
|
<div className="drag-file-guide">{getMessage('estimate.detail.dragFileGuide')}</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
<div className="common-table mb10">
|
|
<table>
|
|
<colgroup>
|
|
<col style={{ width: '160px' }} />
|
|
<col />
|
|
</colgroup>
|
|
<tbody>
|
|
<tr>
|
|
<th>{getMessage('estimate.detail.header.fileList1')}</th>
|
|
<td>
|
|
<EstimateFileUploader {...fileUploadProps} />
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
{/* 첨부파일 목록 시작 */}
|
|
{originFiles.length > 0 && (
|
|
<div className="common-table bt-able">
|
|
<table>
|
|
<colgroup>
|
|
<col style={{ width: '160px' }} />
|
|
<col />
|
|
</colgroup>
|
|
<tbody>
|
|
<tr>
|
|
<th>{getMessage('estimate.detail.header.fileList2')}</th>
|
|
<td>
|
|
<div className="drag-file-box">
|
|
<ul className="file-list">
|
|
{originFiles.map((originFile) => {
|
|
return (
|
|
<li className="file-item" key={originFile.no}>
|
|
<div className="file-item-wrap">
|
|
<span
|
|
style={{ display: originFile.delFlg === '0' ? '' : 'none' }}
|
|
onClick={() => handleEstimateFileDownload(originFile)}
|
|
>
|
|
{originFile.faileName}
|
|
<button
|
|
type="button"
|
|
className="delete"
|
|
onClick={(e) => {
|
|
deleteOriginFile(originFile.no)
|
|
e.stopPropagation()
|
|
}}
|
|
></button>
|
|
</span>
|
|
<div className="return-wrap" style={{ display: originFile.delFlg !== '0' ? '' : 'none' }}>
|
|
<span className="return">{originFile.faileName}</span>
|
|
<button
|
|
type="button"
|
|
className="return-btn"
|
|
onClick={(e) => {
|
|
returnOriginFile(originFile.no)
|
|
e.stopPropagation()
|
|
}}
|
|
>
|
|
<i className="return-ico"></i>
|
|
{getMessage('estimate.detail.fileList2.btn.return')}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</li>
|
|
)
|
|
})}
|
|
</ul>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
)}
|
|
{/* 첨부파일 목록 끝 */}
|
|
{/* 파일첨부 끝 */}
|
|
{/* 견적특이사항 시작 */}
|
|
<div className="table-box-title-wrap">
|
|
{/*<div className="title-wrap">*/}
|
|
{/* <h3 className="product">{getMessage('estimate.detail.header.specialEstimate')}</h3>*/}
|
|
{/* <div className="estimate-check-btn">*/}
|
|
{/* <button className={`estimate-arr-btn down mr5 ${hidden ? '' : 'on'}`} onClick={() => setHidden(false)}></button>*/}
|
|
{/* <button className={`estimate-arr-btn up ${hidden ? 'on' : ''}`} onClick={() => setHidden(true)}></button>*/}
|
|
{/* </div>*/}
|
|
{/*</div>*/}
|
|
</div>
|
|
{/* 견적 특이사항 코드영역시작 */}
|
|
<div className={`estimate-check-wrap ${hidden ? 'hide' : ''}`}>
|
|
<div className="estimate-check-inner">
|
|
<div className="special-note-check-wrap">
|
|
{/* SpecialNoteList반복문 */}
|
|
{specialNoteList.length > 0 &&
|
|
specialNoteList.map((row) => {
|
|
return (
|
|
<div key={row.code} className="special-note-check-item">
|
|
<div className="special-note-check-box">
|
|
<div className="d-check-box light">
|
|
<input
|
|
type="checkbox"
|
|
id={row.code}
|
|
checked={!!row.check}
|
|
disabled={row.code === 'ATTR001' || row.pkgYn === '1' ? true : false}
|
|
onChange={() => {
|
|
setSpecialNoteList((specialNote) =>
|
|
specialNote.map((temp) => (temp.code === row.code ? { ...temp, check: !temp.check } : temp)),
|
|
)
|
|
}}
|
|
/>
|
|
<label htmlFor={row.code}></label>
|
|
</div>
|
|
<span
|
|
className="check-name"
|
|
onClick={() => {
|
|
settingShowContent(row.code)
|
|
}}
|
|
>
|
|
{row.codeNm}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
)
|
|
})}
|
|
</div>
|
|
{/* 견적특이사항 선택한 내용 영역시작 */}
|
|
<div className="calculation-estimate">
|
|
{specialNoteList.map((row) => {
|
|
if (row.code === showContentCode) {
|
|
let showcontent = popShowSpecialNoteList.find((item) => {
|
|
return item.code === showContentCode
|
|
})
|
|
|
|
if (isObjectNotEmpty(showcontent)) {
|
|
return (
|
|
<dl key={row.code}>
|
|
<dt>{showcontent.codeNm}</dt>
|
|
<dd dangerouslySetInnerHTML={{ __html: showcontent.remarks }} style={{ whiteSpace: 'pre-wrap' }}></dd>
|
|
</dl>
|
|
)
|
|
} else {
|
|
let pushData = []
|
|
popShowSpecialNoteList.map((item) => {
|
|
let option = showContentCode.split('、')
|
|
option.map((item2) => {
|
|
if (item.code === item2) {
|
|
pushData.push(item)
|
|
}
|
|
})
|
|
})
|
|
//제품에 있는 특이사항만 보여주기 제품에 특이사항이 없으면 전부
|
|
let filterData = pushData.filter((item) => uniqueData.includes(item.code))
|
|
if (filterData.length > 0) {
|
|
return filterData.map((item) => (
|
|
<dl key={item.code}>
|
|
<dt>{item.codeNm}</dt>
|
|
<dd dangerouslySetInnerHTML={{ __html: item.remarks }} style={{ whiteSpace: 'pre-wrap' }}></dd>
|
|
</dl>
|
|
))
|
|
} else {
|
|
return pushData.map((item) => (
|
|
<dl key={item.code}>
|
|
<dt>{item.codeNm}</dt>
|
|
<dd dangerouslySetInnerHTML={{ __html: item.remarks }} style={{ whiteSpace: 'pre-wrap' }}></dd>
|
|
</dl>
|
|
))
|
|
}
|
|
}
|
|
}
|
|
})}
|
|
</div>
|
|
{/* 견적특이사항 선택한 내용 영역끝 */}
|
|
</div>
|
|
</div>
|
|
{/* 견적 특이사항 코드영역 끝 */}
|
|
{/* 견적특이사항 영역끝 */}
|
|
{/* 제품정보 시작 */}
|
|
<div className="table-box-title-wrap">
|
|
<div className="title-wrap">
|
|
<h3>{getMessage('estimate.detail.header.specialEstimateProductInfo')}</h3>
|
|
</div>
|
|
</div>
|
|
<div className="esimate-wrap">
|
|
<div className="estimate-list-wrap one">
|
|
<div className="estimate-box">
|
|
<div className="estimate-tit">{getMessage('estimate.detail.sepcialEstimateProductInfo.totVolKw')}</div>
|
|
<div className="estimate-name blue">{convertNumberToPriceDecimalToFixed(estimateContextState?.totVolKw, 2)}</div>
|
|
</div>
|
|
<div className="estimate-box">
|
|
<div className="estimate-tit">{getMessage('estimate.detail.sepcialEstimateProductInfo.supplyPrice')}</div>
|
|
<div className="estimate-name blue">{convertNumberToPriceDecimalToFixed(estimateContextState?.supplyPrice, 0)}</div>
|
|
</div>
|
|
<div className="estimate-box">
|
|
<div className="estimate-tit">{getMessage('estimate.detail.sepcialEstimateProductInfo.vatPrice')}</div>
|
|
<div className="estimate-name blue">{convertNumberToPriceDecimalToFixed(estimateContextState?.vatPrice, 0)}</div>
|
|
</div>
|
|
<div className="estimate-box">
|
|
<div className="estimate-tit">{getMessage('estimate.detail.sepcialEstimateProductInfo.totPrice')}</div>
|
|
<div className="estimate-name red">{convertNumberToPriceDecimalToFixed(estimateContextState?.totPrice, 0)}</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{/* YJOD면 아래영역 숨김 */}
|
|
<div className="common-table bt-able" style={{ display: estimateContextState?.estimateType === 'YJSS' ? '' : 'none' }}>
|
|
<table>
|
|
<colgroup>
|
|
<col style={{ width: '160px' }} />
|
|
<col />
|
|
<col style={{ width: '160px' }} />
|
|
<col />
|
|
<col style={{ width: '160px' }} />
|
|
<col />
|
|
</colgroup>
|
|
<tbody>
|
|
<tr>
|
|
<th>
|
|
{getMessage('estimate.detail.sepcialEstimateProductInfo.pkgUnitPrice')}
|
|
<span className="important">*</span>
|
|
</th>
|
|
<td>
|
|
<div className="input-wrap">
|
|
<input
|
|
type="text"
|
|
className="input-light"
|
|
value={estimateContextState?.estimateType === 'YJSS' ? estimateContextState?.pkgAsp : '0'}
|
|
onChange={(e) => {
|
|
onChangePkgAsp(e.target.value)
|
|
}}
|
|
/>
|
|
</div>
|
|
</td>
|
|
<th>{getMessage('estimate.detail.sepcialEstimateProductInfo.pkgWeight')}</th>
|
|
<td>{convertNumberToPriceDecimalToFixed(estimateContextState?.totVolKw, 2)}</td>
|
|
<th>{getMessage('estimate.detail.sepcialEstimateProductInfo.pkgPrice')}</th>
|
|
<td>{convertNumberToPriceDecimal(estimateContextState?.pkgTotPrice)}</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
{/* 제품정보 끝 */}
|
|
{/* 가격표시영역시작 */}
|
|
<div className="estimate-product-option">
|
|
<div className="product-price-wrap">
|
|
<div className="product-price-tit">{getMessage('estimate.detail.header.showPrice')}</div>
|
|
<div className="select-wrap">
|
|
{session?.storeLvl === '1' ? (
|
|
<select
|
|
className="select-light"
|
|
onChange={(e) => {
|
|
onChangeStorePriceList(e.target.value)
|
|
}}
|
|
value={showPriceCd}
|
|
>
|
|
{storePriceList.length > 0 &&
|
|
storePriceList.map((row) => (
|
|
<option key={row.priceCd} value={row.priceCd}>
|
|
{row.priceNm}
|
|
</option>
|
|
))}
|
|
</select>
|
|
) : (
|
|
<select key={uuidv4()} className="select-light">
|
|
<option value="UNIT_PRICE">{getMessage('estimate.detail.header.unitPrice')}</option>
|
|
</select>
|
|
)}
|
|
</div>
|
|
<button
|
|
type="button"
|
|
className="btn-origin grey ml5"
|
|
onClick={(event) => {
|
|
|
|
setHandlePricingFlag(true)
|
|
handlePricingBtn(showPriceCd)
|
|
}}
|
|
>
|
|
{getMessage('estimate.detail.showPrice.pricingBtn')}
|
|
</button>
|
|
</div>
|
|
<div className="product-price-wrap ml10">
|
|
<div className="product-price-tit">{getMessage('estimate.detail.header.singleCable')}</div>
|
|
<div className="select-wrap">
|
|
<select
|
|
className="select-light"
|
|
onChange={(e) => {
|
|
onChangeDisplayCableItem(e.target.value, estimateContextState.itemList)
|
|
}}
|
|
value={cableItem}
|
|
>
|
|
{cableItemList.length > 0 &&
|
|
cableItemList.map((row) => {
|
|
if(!row.clRefChr2.includes('S')){
|
|
return <option key={row.clRefChr1} value={row.clRefChr1}>
|
|
{row.clRefChr2}
|
|
</option>
|
|
}
|
|
})}
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div className="product-price-wrap ml10">
|
|
<div className="product-price-tit">{getMessage('estimate.detail.header.doubleCable')}</div>
|
|
<div className="select-wrap">
|
|
<select
|
|
className="select-light"
|
|
onChange={(e) => {
|
|
onChangeDisplayDoubleCableItem(e.target.value, estimateContextState.itemList)
|
|
}}
|
|
value={cableDbItem}
|
|
>
|
|
{cableItemList.length > 0 &&
|
|
cableItemList.map((row) => {
|
|
if(row.clRefChr2.includes('S')){
|
|
return <option key={row.clRefChr1} value={row.clRefChr1}>
|
|
{row.clRefChr2.replace('S','')}
|
|
</option>
|
|
}
|
|
})}
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div className="product-edit-wrap">
|
|
<ul className="product-edit-explane">
|
|
<li className="explane-item item01">
|
|
<span className="ico"></span>
|
|
{getMessage('estimate.detail.showPrice.description1')}
|
|
</li>
|
|
<li className="explane-item item02">
|
|
<span className="ico"></span>
|
|
{getMessage('estimate.detail.showPrice.description2')}
|
|
</li>
|
|
<li className="explane-item item03">
|
|
<span className="ico"></span>
|
|
{getMessage('estimate.detail.showPrice.description3')}
|
|
</li>
|
|
<li className="explane-item item04">
|
|
<span className="ico"></span>
|
|
{getMessage('estimate.detail.showPrice.description4')}
|
|
</li>
|
|
</ul>
|
|
<div className="product-edit-btn">
|
|
<button
|
|
className="btn-origin navy mr5"
|
|
type="button"
|
|
onClick={() => {
|
|
addItem()
|
|
}}
|
|
>
|
|
<span className="plus"></span>
|
|
{getMessage('estimate.detail.showPrice.addItem')}
|
|
</button>
|
|
<button className="btn-origin grey" type="button" onClick={removeItem}>
|
|
<span className="minus"></span>
|
|
{getMessage('estimate.detail.showPrice.delItem')}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{/* 가격표시영역끝 */}
|
|
{/* html테이블시작 */}
|
|
<div className="esimate-table">
|
|
<table>
|
|
<colgroup>
|
|
<col width={50} />
|
|
<col width={70} />
|
|
<col />
|
|
<col width={300} />
|
|
<col width={90} />
|
|
<col width={80} />
|
|
<col width={170} />
|
|
<col width={190} />
|
|
</colgroup>
|
|
<thead>
|
|
<tr>
|
|
<th>
|
|
<div className="d-check-box pop no-text">
|
|
<input type="checkbox" id="ch97" checked={isSelectedAll()} onChange={onChangeSelectAll} />
|
|
<label htmlFor="ch97"></label>
|
|
</div>
|
|
</th>
|
|
<th>{getMessage('estimate.detail.itemTableHeader.dispOrder')}</th>
|
|
<th>{getMessage('estimate.detail.itemTableHeader.itemId')}</th>
|
|
<th>{getMessage('estimate.detail.itemTableHeader.itemNo')}</th>
|
|
<th>{getMessage('estimate.detail.itemTableHeader.amount')}</th>
|
|
<th>{getMessage('estimate.detail.itemTableHeader.unit')}</th>
|
|
<th>{getMessage('estimate.detail.itemTableHeader.salePrice')}</th>
|
|
<th>{getMessage('estimate.detail.itemTableHeader.saleTotPrice')}</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{estimateContextState?.itemList.length > 0 &&
|
|
estimateContextState.itemList.map((item, index) => {
|
|
if (item.delFlg === '0') {
|
|
return (
|
|
<tr key={item?.dispOrder || index}>
|
|
<td className="al-c">
|
|
<div className="d-check-box light no-text">
|
|
<input
|
|
type="checkbox"
|
|
id={item?.dispOrder}
|
|
disabled={!!item?.paDispOrder || item.dispCableFlg === '1X'}
|
|
onChange={() => onChangeSelect(item.dispOrder)}
|
|
checked={!!selection.has(item.dispOrder)}
|
|
/>
|
|
<label htmlFor={item?.dispOrder}></label>
|
|
</div>
|
|
</td>
|
|
<td className="al-r">{item?.dispOrder}</td>
|
|
<td>
|
|
<div className="form-flex-wrap">
|
|
<div className="select-wrap mr5">
|
|
{item.dispCableFlg !== '1' ? (
|
|
<Select
|
|
name="long-value-select1"
|
|
instanceId="long-value-select1"
|
|
className="react-select-custom"
|
|
classNamePrefix="custom"
|
|
placeholder="Select"
|
|
options={originDisplayItemList}
|
|
styles={groupStyles}
|
|
onChange={(e) => {
|
|
if (isObjectNotEmpty(e)) {
|
|
onChangeDisplayItem(e.itemId, item.dispOrder, index, false)
|
|
}
|
|
}}
|
|
menuPlacement={'auto'}
|
|
getOptionLabel={(x) => x.itemName + ' (' + x.itemNo + ')'}
|
|
getOptionValue={(x) => x.itemNo}
|
|
components={{
|
|
SingleValue: ({ children, ...props }) => {
|
|
return <components.SingleValue {...props}>{props.data.itemName}</components.SingleValue>
|
|
},
|
|
}}
|
|
isClearable={false}
|
|
isDisabled={!!item?.paDispOrder}
|
|
value={displayItemList.filter(function (option) {
|
|
if (item.itemNo === '') {
|
|
return false
|
|
} else {
|
|
return option.itemId === item.itemId
|
|
}
|
|
})}
|
|
/>
|
|
) : (
|
|
<Select
|
|
name="long-value-select11"
|
|
instanceId="long-value-select11"
|
|
className="react-select-custom"
|
|
classNamePrefix="custom"
|
|
placeholder="Select"
|
|
options={cableItemList}
|
|
menuPlacement={'auto'}
|
|
getOptionLabel={(x) => x.clRefChr3 + ' (' + x.clRefChr1 + ')'}
|
|
getOptionValue={(x) => x.clRefChr1}
|
|
components={{
|
|
SingleValue: ({ children, ...props }) => {
|
|
return <components.SingleValue {...props}>{(item.itemTpCd === 'M12' || item.itemTpCd === 'S13')? item.itemName : props.data.clRefChr3}</components.SingleValue>
|
|
},
|
|
}}
|
|
isClearable={false}
|
|
isDisabled={true}
|
|
value={cableItemList.filter(function (option) {
|
|
return (item.itemTpCd === 'M12' || item.itemTpCd === 'S13' )? item.itemId : option.clRefChr1 === item.itemId
|
|
})}
|
|
/>
|
|
)}
|
|
</div>
|
|
{item?.itemChangeFlg === '1' && (
|
|
<div className="btn-area">
|
|
<span className="tb_ico change_check"></span>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<div className="form-flex-wrap">
|
|
<div className="name">{item?.itemNo}</div>
|
|
<div className="icon-wrap">
|
|
{item?.fileUploadFlg === '1' && <span className="tb_ico file_check"></span>}
|
|
{item?.specialNoteCd && (
|
|
<button
|
|
type="button"
|
|
className="grid-tip"
|
|
onClick={() => {
|
|
setProductFeaturesPopupOpen(true)
|
|
setShowProductFeatureData(item?.specialNoteCd)
|
|
}}
|
|
></button>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<div className="input-wrap" style={{ width: '100%' }}>
|
|
<input
|
|
type="text"
|
|
className="input-light al-r"
|
|
value={convertNumberToPriceDecimal(item?.amount?.replaceAll(',', ''))}
|
|
disabled={item.itemId === '' || !!item?.paDispOrder}
|
|
onChange={(e) => {
|
|
onChangeAmount(e.target.value, item.dispOrder, index)
|
|
}}
|
|
maxLength={6}
|
|
/>
|
|
</div>
|
|
</td>
|
|
<td>{item.unit}</td>
|
|
<td>
|
|
<div className="form-flex-wrap">
|
|
<div className="input-wrap mr5">
|
|
<input
|
|
type="text"
|
|
className="input-light al-r"
|
|
value={
|
|
item.openFlg === '1'
|
|
? 'OPEN'
|
|
: convertNumberToPriceDecimal(item?.showSalePrice === '0' ? null : item?.salePrice?.replaceAll(',', ''))
|
|
}
|
|
disabled={
|
|
item.openFlg === '1'
|
|
? true
|
|
: estimateContextState?.estimateType === 'YJSS'
|
|
? item?.paDispOrder
|
|
? true
|
|
: item.pkgMaterialFlg !== '1'
|
|
: item.itemId === '' || !!item?.paDispOrder
|
|
? true
|
|
: item.openFlg === '1'
|
|
? true
|
|
: false
|
|
}
|
|
onChange={(e) => {
|
|
onChangeSalePrice(e.target.value, item.dispOrder, index)
|
|
}}
|
|
maxLength={12}
|
|
/>
|
|
</div>
|
|
{item.openFlg === '1' && (
|
|
<div className="btn-area">
|
|
<span className="tb_ico open_check"></span>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</td>
|
|
<td className="al-r">
|
|
{item?.openFlg === '1'
|
|
? 'OPEN'
|
|
: convertNumberToPriceDecimal(
|
|
item?.showSaleTotPrice === '0'
|
|
? null
|
|
: item?.amount === ''
|
|
? null
|
|
: item?.saleTotPrice === '0'
|
|
? null
|
|
: item?.saleTotPrice?.replaceAll(',', ''),
|
|
)}
|
|
</td>
|
|
</tr>
|
|
)
|
|
} else {
|
|
return null
|
|
}
|
|
})}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
{/* html테이블끝 */}
|
|
</div>
|
|
</div>
|
|
{/* 기본정보끝 */}
|
|
</div>
|
|
{productFeaturesPopupOpen && (
|
|
<ProductFeaturesPop
|
|
popShowSpecialNoteList={popShowSpecialNoteList}
|
|
showProductFeatureData={showProductFeatureData}
|
|
setProductFeaturesPopupOpen={setProductFeaturesPopupOpen}
|
|
/>
|
|
)}
|
|
</div>
|
|
)
|
|
}
|