견적서 상세

This commit is contained in:
basssy 2024-11-07 17:57:54 +09:00
parent ed8a981631
commit 6f0f0883f8
4 changed files with 249 additions and 75 deletions

View File

@ -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>

View File

@ -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
}
}
}

View File

@ -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": "ファイル添付が必須のアイテムがあります。ファイルを添付するか、後日添付をチェックしてください."
}

View File

@ -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": "파일첨부가 필수인 아이템이 있습니다. 파일을 첨부하거나 후일첨부를 체크해주십시오."
}