견적서 상세
This commit is contained in:
parent
ed8a981631
commit
6f0f0883f8
@ -9,12 +9,13 @@ import SingleDatePicker from '../common/datepicker/SingleDatePicker'
|
||||
import EstimateFileUploader from './EstimateFileUploader'
|
||||
import { useAxios } from '@/hooks/useAxios'
|
||||
import { globalLocaleStore } from '@/store/localeAtom'
|
||||
import { isNotEmptyArray, isObjectNotEmpty } from '@/util/common-utils'
|
||||
import { isNotEmptyArray, isObjectNotEmpty, queryStringFormatter } from '@/util/common-utils'
|
||||
import dayjs from 'dayjs'
|
||||
import { useCommonCode } from '@/hooks/common/useCommonCode'
|
||||
import Select from 'react-select'
|
||||
import { useEstimateController } from '@/hooks/floorPlan/estimate/useEstimateController'
|
||||
import { SessionContext } from '@/app/SessionProvider'
|
||||
import Select, { components } from 'react-select'
|
||||
// import EstimateItemTable from './EstimateItemTable'
|
||||
|
||||
export default function Estimate({ params }) {
|
||||
const { session } = useContext(SessionContext)
|
||||
@ -33,6 +34,8 @@ export default function Estimate({ params }) {
|
||||
const { findCommonCode } = useCommonCode()
|
||||
const [honorificCodeList, setHonorificCodeList] = useState([]) //경칭 공통코드
|
||||
|
||||
const [storePriceList, setStorePriceList] = useState([]) //가격표시 option
|
||||
|
||||
const [startDate, setStartDate] = useState(new Date())
|
||||
const singleDatePickerProps = {
|
||||
startDate,
|
||||
@ -44,7 +47,7 @@ export default function Estimate({ params }) {
|
||||
//견적서 상세데이터
|
||||
const { state, setState } = useEstimateController(params.pid)
|
||||
|
||||
//견적특이사항 상세 데이터 LIST
|
||||
const [itemList, setItemList] = useState([])
|
||||
|
||||
//견적특이사항 List
|
||||
const [specialNoteList, setSpecialNoteList] = useState([])
|
||||
@ -155,6 +158,46 @@ export default function Estimate({ params }) {
|
||||
})
|
||||
}
|
||||
|
||||
//아이템 목록
|
||||
useEffect(() => {
|
||||
if (isNotEmptyArray(state.itemList)) {
|
||||
setItemList(state.itemList)
|
||||
}
|
||||
}, [state?.itemList])
|
||||
|
||||
//가격표시 option 세팅
|
||||
useEffect(() => {
|
||||
const param = {
|
||||
saleStoreId: session.storeId,
|
||||
sapSalesStoreCd: session.custCd,
|
||||
docTpCd: state?.estimateType,
|
||||
}
|
||||
const apiUrl = `/api/estimate/price/store-price-list?${queryStringFormatter(param)}`
|
||||
get({ url: apiUrl }).then((res) => {
|
||||
if (isNotEmptyArray(res?.data)) {
|
||||
setStorePriceList(res.data)
|
||||
}
|
||||
})
|
||||
}, [state?.estimateType])
|
||||
|
||||
//Pricing 버튼
|
||||
const handlePricing = async (priceCd) => {
|
||||
const param = {
|
||||
saleStoreId: session.storeId,
|
||||
sapSalesStoreCd: session.custCd,
|
||||
docTpCd: state.estimateType,
|
||||
priceCd: priceCd,
|
||||
itemIdList: [], //아이템
|
||||
}
|
||||
|
||||
console.log('param::', param)
|
||||
return
|
||||
await promisePost({ url: '/api/estimate/price/item-price-list', data: param }).then((res) => {
|
||||
console.log('프라이싱결과::::::', res)
|
||||
//아이템쪽 다 새로고침............SUCK!!!
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="sub-content estimate">
|
||||
<div className="sub-content-inner">
|
||||
@ -304,6 +347,7 @@ export default function Estimate({ params }) {
|
||||
value={'YJSS'}
|
||||
checked={state?.estimateType === 'YJSS' ? true : false}
|
||||
onChange={(e) => {
|
||||
//주문분류
|
||||
setState({ estimateType: e.target.value })
|
||||
}}
|
||||
/>
|
||||
@ -380,9 +424,18 @@ export default function Estimate({ params }) {
|
||||
<div className="title-wrap">
|
||||
<h3>{getMessage('estimate.detail.header.fileList1')}</h3>
|
||||
<div className="d-check-box light mr5">
|
||||
<input type="checkbox" id="next" />
|
||||
<input
|
||||
type="checkbox"
|
||||
id="next"
|
||||
checked={state?.fileFlg === '0' ? false : true}
|
||||
onChange={(e) => {
|
||||
setState({
|
||||
fileFlg: e.target.checked ? '1' : '0',
|
||||
})
|
||||
}}
|
||||
/>
|
||||
<label htmlFor="next" style={{ color: '#101010' }}>
|
||||
{getMessage('estimate.detail.nextSubmit')}
|
||||
{getMessage('estimate.detail.fileFlg')}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
@ -416,7 +469,7 @@ export default function Estimate({ params }) {
|
||||
<td>
|
||||
<div className="drag-file-box">
|
||||
<ul className="file-list">
|
||||
{isNotEmptyArray(originFiles) &&
|
||||
{originFiles.length > 0 &&
|
||||
originFiles.map((originFile) => {
|
||||
return (
|
||||
<li className="file-item">
|
||||
@ -492,7 +545,7 @@ export default function Estimate({ params }) {
|
||||
}
|
||||
})}
|
||||
</div>
|
||||
{/* 견적특이사항 선택한 내용?영역끝 */}
|
||||
{/* 견적특이사항 선택한 내용 영역끝 */}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -565,12 +618,30 @@ export default function Estimate({ params }) {
|
||||
<div className="product-price-wrap">
|
||||
<div className="product-price-tit">{getMessage('estimate.detail.header.showPrice')}</div>
|
||||
<div className="select-wrap">
|
||||
<select className="select-light" name="" id="">
|
||||
<option value="">111</option>
|
||||
<option value="">222</option>
|
||||
</select>
|
||||
{session?.storeLvl === '1' ? (
|
||||
<select
|
||||
className="select-light"
|
||||
onChange={(e) => {
|
||||
setState({ priceCd: e.target.value })
|
||||
}}
|
||||
>
|
||||
{storePriceList.length > 0 && storePriceList.map((row) => <option value={row.priceCd}>{row.priceNm}</option>)}
|
||||
</select>
|
||||
) : (
|
||||
<select className="select-light">
|
||||
<option value="UNIT_PRICE">{getMessage('estimate.detail.header.unitPrice')}</option>
|
||||
</select>
|
||||
)}
|
||||
</div>
|
||||
<button className="btn-origin grey ml5">{getMessage('estimate.detail.showPrice.btn1')}</button>
|
||||
<button
|
||||
className="btn-origin grey ml5"
|
||||
onClick={() => {
|
||||
// console.log('priceCd::', state.priceCd)
|
||||
handlePricing(state.priceCd)
|
||||
}}
|
||||
>
|
||||
{getMessage('estimate.detail.showPrice.pricingBtn')}
|
||||
</button>
|
||||
</div>
|
||||
<div className="product-edit-wrap">
|
||||
<ul className="product-edit-explane">
|
||||
@ -605,7 +676,83 @@ export default function Estimate({ params }) {
|
||||
</div>
|
||||
{/* 가격표시영역끝 */}
|
||||
{/* html테이블시작 */}
|
||||
<div className="q-grid no-cols"></div>
|
||||
<div className="esimate-table">
|
||||
<table>
|
||||
<colgroup>
|
||||
<col width={50} />
|
||||
<col width={100} />
|
||||
<col />
|
||||
<col width={200} />
|
||||
<col width={100} />
|
||||
<col width={100} />
|
||||
<col width={200} />
|
||||
<col width={240} />
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
<div className="d-check-box pop no-text" style={{ display: 'none' }}>
|
||||
<input type="checkbox" id="ch97" />
|
||||
<label htmlFor="ch97"></label>
|
||||
</div>
|
||||
</th>
|
||||
<th>{getMessage('estimate.detail.itemTableHeader.col1')}</th>
|
||||
<th>{getMessage('estimate.detail.itemTableHeader.col2')}</th>
|
||||
<th>{getMessage('estimate.detail.itemTableHeader.col3')}</th>
|
||||
<th>{getMessage('estimate.detail.itemTableHeader.col4')}</th>
|
||||
<th>{getMessage('estimate.detail.itemTableHeader.col5')}</th>
|
||||
<th>{getMessage('estimate.detail.itemTableHeader.col6')}</th>
|
||||
<th>{getMessage('estimate.detail.itemTableHeader.col7')}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td className="al-c">
|
||||
<div className="d-check-box light no-text">
|
||||
<input type="checkbox" id="ch98" />
|
||||
<label htmlFor="ch98"></label>
|
||||
</div>
|
||||
</td>
|
||||
<td className="al-r">100</td>
|
||||
<td>
|
||||
<div className="form-flex-wrap">
|
||||
<div className="select-wrap mr5">{/* <Select /> */}</div>
|
||||
<div className="btn-area">
|
||||
<span className="tb_ico change_check"></span>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div className="form-flex-wrap">
|
||||
<div className="name">HNW-MC4-CHN30</div>
|
||||
<div className="icon-wrap">
|
||||
<span className="tb_ico file_check"></span>
|
||||
<button className="grid-tip"></button>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div className="input-wrap" style={{ width: '100%' }}>
|
||||
<input type="text" className="input-light al-r" defaultValue={'20'} />
|
||||
</div>
|
||||
</td>
|
||||
<td>セット</td>
|
||||
<td>
|
||||
<div className="form-flex-wrap">
|
||||
<div className="input-wrap mr5">
|
||||
<input type="text" className="input-light al-r" defaultValue={'278,050'} />
|
||||
</div>
|
||||
<div className="btn-area">
|
||||
<span className="tb_ico open_check"></span>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="al-r">5,561,000</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{/* html테이블끝 */}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -5,6 +5,7 @@ import { globalLocaleStore } from '@/store/localeAtom'
|
||||
import { estimateState, floorPlanObjectState } from '@/store/floorPlanObjectAtom'
|
||||
import { isObjectNotEmpty } from '@/util/common-utils'
|
||||
import { SessionContext } from '@/app/SessionProvider'
|
||||
import { useMessage } from '@/hooks/useMessage'
|
||||
|
||||
const reducer = (prevState, nextState) => {
|
||||
return { ...prevState, ...nextState }
|
||||
@ -21,35 +22,33 @@ const defaultEstimateData = {
|
||||
estimateType: 'YJOD', //주문분류
|
||||
remarks: '', //비고
|
||||
estimateOption: '', //견적특이사항
|
||||
// itemList: [{ id: 1, name: '' }],
|
||||
//아이템에 필요없는거 빼기
|
||||
itemList: [
|
||||
{
|
||||
amount: '',
|
||||
fileUploadFlg: '',
|
||||
itemChangeFlg: '',
|
||||
itemGroup: '',
|
||||
itemId: '', //키값??
|
||||
itemName: '',
|
||||
itemNo: '',
|
||||
moduleFlg: '',
|
||||
objectNo: '',
|
||||
pkgMaterialFlg: '',
|
||||
planNo: '',
|
||||
pnowW: '',
|
||||
salePrice: '',
|
||||
saleTotPrice: '',
|
||||
specification: '',
|
||||
unit: '',
|
||||
},
|
||||
// {
|
||||
// amount: '',
|
||||
// fileUploadFlg: '',
|
||||
// itemChangeFlg: '',
|
||||
// itemGroup: '',
|
||||
// itemId: '', //키값??
|
||||
// itemName: '',
|
||||
// itemNo: '',
|
||||
// moduleFlg: '',
|
||||
// objectNo: '',
|
||||
// pkgMaterialFlg: '',
|
||||
// planNo: '',
|
||||
// pnowW: '',
|
||||
// salePrice: '',
|
||||
// saleTotPrice: '',
|
||||
// specification: '',
|
||||
// unit: '',
|
||||
// },
|
||||
],
|
||||
fileList: [],
|
||||
fileFlg: '0', //후일 자료 제출 (체크 1 노체크 0)
|
||||
}
|
||||
|
||||
// Helper functions
|
||||
// const updateItemInList = (itemList, id, updates) => {
|
||||
const updateItemInList = (itemList, itemId, updates) => {
|
||||
// return itemList.map((item) => (item.id === id ? { ...item, ...updates } : item))
|
||||
return itemList.map((item) => (item.itemId === itemId ? { ...item, ...updates } : item))
|
||||
}
|
||||
|
||||
@ -59,6 +58,8 @@ export const useEstimateController = (planNo) => {
|
||||
const objectRecoil = useRecoilValue(floorPlanObjectState)
|
||||
const [estimateData, setEstimateData] = useRecoilState(estimateState)
|
||||
|
||||
const { getMessage } = useMessage()
|
||||
|
||||
const { get, post, promisePost } = useAxios(globalLocaleState)
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
@ -87,20 +88,15 @@ export const useEstimateController = (planNo) => {
|
||||
}
|
||||
}
|
||||
|
||||
// const updateItem = (id, updates) => {
|
||||
const updateItem = (itemId, updates) => {
|
||||
setState({
|
||||
// itemList: updateItemInList(state.itemList, id, updates),
|
||||
itemList: updateItemInList(state.itemList, itemId, updates),
|
||||
})
|
||||
}
|
||||
|
||||
const addItem = () => {
|
||||
// const newId = Math.max(...state.itemList.map((item) => item.id)) + 1
|
||||
const newItemId = Math.max(...state.itemList.map((item) => item.itemId)) + 1
|
||||
setState({
|
||||
// itemList: [...state.itemList, { id: newId, name: '' }],
|
||||
//셋팅할필요없는거 빼기
|
||||
itemList: [
|
||||
...state.itemList,
|
||||
{
|
||||
@ -126,42 +122,55 @@ export const useEstimateController = (planNo) => {
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
setEstimateData({ ...state, userId: session.userId })
|
||||
//sapSalesStoreCd 추가예정 필수값
|
||||
// setEstimateData({ ...state, userId: session.userId, sapSalesStoreCd : session.sapSalesStoreCd })
|
||||
setEstimateData({ ...state, userId: session.userId, sapSalesStoreCd: session.custCd })
|
||||
}, [state])
|
||||
|
||||
//견적서 저장
|
||||
const handleEstimateSubmit = async () => {
|
||||
//0. 필수체크
|
||||
let flag = true
|
||||
console.log('::담긴 estimateData:::', estimateData)
|
||||
//1. 첨부파일 저장
|
||||
const formData = new FormData()
|
||||
formData.append('file', estimateData.fileList)
|
||||
formData.append('objectNo', estimateData.objectNo)
|
||||
formData.append('planNo', estimateData.planNo)
|
||||
formData.append('category', '10')
|
||||
formData.append('userId', estimateData.userId)
|
||||
for (const value of formData.values()) {
|
||||
console.log('formData::', value)
|
||||
}
|
||||
|
||||
await promisePost({ url: '/api/file/fileUpload', data: formData }).then((res) => {
|
||||
console.log('파일저장::::::::::', res)
|
||||
})
|
||||
|
||||
//2. 상세데이터 저장
|
||||
|
||||
console.log('상세저장시작!!')
|
||||
return
|
||||
try {
|
||||
const result = await promisePost({
|
||||
url: ESTIMATE_API_ENDPOINT,
|
||||
data: estimateData,
|
||||
//아이템 fileUploadFlg가1(첨부파일 필수)이 1개라도 있는데 후일 자료 제출(fileFlg) 체크안했으면(0) alert 저장안돼
|
||||
if (estimateData.itemList.length > 1) {
|
||||
estimateData.itemList.map((row) => {
|
||||
if (row.fileUploadFlg === '1') {
|
||||
if (estimateData.fileFlg === '0') {
|
||||
alert(getMessage('estimate.detail.save.alertMsg'))
|
||||
flag = false
|
||||
}
|
||||
}
|
||||
})
|
||||
return result
|
||||
} catch (error) {
|
||||
console.error('Failed to submit estimate:', error)
|
||||
throw error
|
||||
}
|
||||
if (flag) {
|
||||
//1. 첨부파일 저장
|
||||
const formData = new FormData()
|
||||
formData.append('file', estimateData.fileList)
|
||||
formData.append('objectNo', estimateData.objectNo)
|
||||
formData.append('planNo', estimateData.planNo)
|
||||
formData.append('category', '10')
|
||||
formData.append('userId', estimateData.userId)
|
||||
for (const value of formData.values()) {
|
||||
console.log('formData::', value)
|
||||
}
|
||||
|
||||
await promisePost({ url: '/api/file/fileUpload', data: formData }).then((res) => {
|
||||
console.log('파일저장결과::::::::::', res)
|
||||
})
|
||||
|
||||
//2. 상세데이터 저장
|
||||
|
||||
console.log('상세저장시작!!')
|
||||
return
|
||||
try {
|
||||
const result = await promisePost({
|
||||
url: ESTIMATE_API_ENDPOINT,
|
||||
data: estimateData,
|
||||
})
|
||||
return result
|
||||
} catch (error) {
|
||||
console.error('Failed to submit estimate:', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -818,7 +818,7 @@
|
||||
"estimate.detail.estimateType": "注文分類",
|
||||
"estimate.detail.roofCns": "屋根材・仕様施工",
|
||||
"estimate.detail.remarks": "備考",
|
||||
"estimate.detail.nextSubmit": "後日資料提出",
|
||||
"estimate.detail.fileFlg": "後日資料提出",
|
||||
"estimate.detail.header.fileList1": "ファイル添付",
|
||||
"estimate.detail.fileList.btn": "ファイル選択",
|
||||
"estimate.detail.header.fileList2": "添付ファイル一覧",
|
||||
@ -835,11 +835,20 @@
|
||||
"estimate.detail.sepcialEstimateProductInfo.calcFormula1": "(モジュール容量 × 数量)÷1000",
|
||||
"estimate.detail.sepcialEstimateProductInfo.calcFormula2": "PKG単価 (W)×PKG容量(W)",
|
||||
"estimate.detail.header.showPrice": "価格表示",
|
||||
"estimate.detail.showPrice.btn1": "Pricing",
|
||||
"estimate.detail.header.unitPrice": "定価",
|
||||
"estimate.detail.showPrice.pricingBtn": "Pricing",
|
||||
"estimate.detail.showPrice.description1": "製品価格 OPEN",
|
||||
"estimate.detail.showPrice.description2": "追加, 変更資材",
|
||||
"estimate.detail.showPrice.description3": "添付必須",
|
||||
"estimate.detail.showPrice.description4": "クリックして製品の特異性を確認する",
|
||||
"estimate.detail.showPrice.btn2": "製品を追加",
|
||||
"estimate.detail.showPrice.btn3": "製品削除"
|
||||
"estimate.detail.showPrice.btn3": "製品削除",
|
||||
"estimate.detail.itemTableHeader.col1": "アイテム",
|
||||
"estimate.detail.itemTableHeader.col2": "品番",
|
||||
"estimate.detail.itemTableHeader.col3": "型板",
|
||||
"estimate.detail.itemTableHeader.col4": "数量",
|
||||
"estimate.detail.itemTableHeader.col5": "単位",
|
||||
"estimate.detail.itemTableHeader.col6": "単価",
|
||||
"estimate.detail.itemTableHeader.col7": "金額 (税別別)",
|
||||
"estimate.detail.save.alertMsg": "ファイル添付が必須のアイテムがあります。ファイルを添付するか、後日添付をチェックしてください."
|
||||
}
|
||||
|
||||
@ -824,7 +824,7 @@
|
||||
"estimate.detail.estimateType": "주문분류",
|
||||
"estimate.detail.roofCns": "지붕재・사양시공",
|
||||
"estimate.detail.remarks": "비고",
|
||||
"estimate.detail.nextSubmit": "후일자료제출",
|
||||
"estimate.detail.fileFlg": "후일자료제출",
|
||||
"estimate.detail.header.fileList1": "파일첨부",
|
||||
"estimate.detail.fileList.btn": "파일선택",
|
||||
"estimate.detail.header.fileList2": "첨부파일 목록",
|
||||
@ -841,11 +841,20 @@
|
||||
"estimate.detail.sepcialEstimateProductInfo.calcFormula1": "(모듈수량 * 수량)÷100",
|
||||
"estimate.detail.sepcialEstimateProductInfo.calcFormula2": "PKG단가(W) * PKG용량(W)",
|
||||
"estimate.detail.header.showPrice": "가격표시",
|
||||
"estimate.detail.showPrice.btn1": "Pricing",
|
||||
"estimate.detail.header.unitPrice": "정가",
|
||||
"estimate.detail.showPrice.pricingBtn": "Pricing",
|
||||
"estimate.detail.showPrice.description1": "제품 가격 OPEN",
|
||||
"estimate.detail.showPrice.description2": "추가, 변경 자재",
|
||||
"estimate.detail.showPrice.description3": "첨부필수",
|
||||
"estimate.detail.showPrice.description4": "클릭하여 제품 특이사항 확인",
|
||||
"estimate.detail.showPrice.btn2": "제품추가",
|
||||
"estimate.detail.showPrice.btn3": "제품삭제"
|
||||
"estimate.detail.showPrice.btn3": "제품삭제",
|
||||
"estimate.detail.itemTableHeader.col1": "Item",
|
||||
"estimate.detail.itemTableHeader.col2": "품번",
|
||||
"estimate.detail.itemTableHeader.col3": "형명",
|
||||
"estimate.detail.itemTableHeader.col4": "수량",
|
||||
"estimate.detail.itemTableHeader.col5": "단위",
|
||||
"estimate.detail.itemTableHeader.col6": "단가",
|
||||
"estimate.detail.itemTableHeader.col7": "금액(부가세별도)",
|
||||
"estimate.detail.save.alertMsg": "파일첨부가 필수인 아이템이 있습니다. 파일을 첨부하거나 후일첨부를 체크해주십시오."
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user