견적서 상세
This commit is contained in:
parent
18e3ebe7f5
commit
889ced564d
@ -28,6 +28,8 @@ export default function Estimate({ params }) {
|
||||
const [files, setFiles] = useState([]) // 보내는 첨부파일
|
||||
const [originFiles, setOriginFiles] = useState([]) //기존 첨부파일
|
||||
|
||||
const [showPriceCd, setShowPriceCd] = useState('')
|
||||
|
||||
const [showContentCode, setShowContentCode] = useState('ATTR001')
|
||||
|
||||
const [productFeaturesPopupOpen, setProductFeaturesPopupOpen] = useState(false) //견적특이사항 팝업
|
||||
@ -46,8 +48,6 @@ export default function Estimate({ params }) {
|
||||
|
||||
const [storePriceList, setStorePriceList] = useState([]) //가격표시 option
|
||||
|
||||
const [tempPriceCd, setTempPriceCd] = useState('')
|
||||
|
||||
const [startDate, setStartDate] = useState(new Date())
|
||||
const singleDatePickerProps = {
|
||||
startDate,
|
||||
@ -182,7 +182,7 @@ export default function Estimate({ params }) {
|
||||
})
|
||||
}
|
||||
|
||||
//가격표시 option 최초세팅
|
||||
//가격표시 option 목록 최초세팅 && 주문분류 변경시
|
||||
useEffect(() => {
|
||||
if (state.estimateType !== '') {
|
||||
const param = {
|
||||
@ -200,23 +200,35 @@ export default function Estimate({ params }) {
|
||||
}
|
||||
}, [state?.estimateType])
|
||||
|
||||
//가격표시 option 변경시
|
||||
useEffect(() => {
|
||||
if (tempPriceCd !== '') {
|
||||
const param = {
|
||||
saleStoreId: session.storeId,
|
||||
sapSalesStoreCd: session.custCd,
|
||||
docTpCd: tempPriceCd,
|
||||
}
|
||||
|
||||
const apiUrl = `/api/estimate/price/store-price-list?${queryStringFormatter(param)}`
|
||||
get({ url: apiUrl }).then((res) => {
|
||||
if (isNotEmptyArray(res?.data)) {
|
||||
setStorePriceList(res.data)
|
||||
}
|
||||
})
|
||||
if (state?.priceCd) {
|
||||
setShowPriceCd(state.priceCd)
|
||||
}
|
||||
}, [tempPriceCd])
|
||||
}, [state?.priceCd])
|
||||
|
||||
//가격 표시 option 변경 이벤트
|
||||
const onChangeStorePriceList = (priceCd) => {
|
||||
const param = {
|
||||
saleStoreId: session.storeId,
|
||||
sapSalesStoreCd: session.custCd,
|
||||
docTpCd: priceCd,
|
||||
}
|
||||
|
||||
//가격표시 바꾸만헀을때는 tempPriceCd에 바꾼값 관리 불필요?
|
||||
//프라이싱 했을때 priceCd setState
|
||||
//화면에 보여지는 값은 showPriceCd로 관리
|
||||
setShowPriceCd(priceCd)
|
||||
//setState({
|
||||
// tempPriceCd: priceCd,
|
||||
//})
|
||||
|
||||
const apiUrl = `/api/estimate/price/store-price-list?${queryStringFormatter(param)}`
|
||||
get({ url: apiUrl }).then((res) => {
|
||||
if (isNotEmptyArray(res?.data)) {
|
||||
setStorePriceList(res.data)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
//Pricing 버튼
|
||||
const handlePricing = async (priceCd) => {
|
||||
@ -224,24 +236,55 @@ export default function Estimate({ params }) {
|
||||
saleStoreId: session.storeId,
|
||||
sapSalesStoreCd: session.custCd,
|
||||
docTpCd: state.estimateType,
|
||||
priceCd: session.storeLvl === '1' ? tempPriceCd : priceCd,
|
||||
itemIdList: state.itemList, //아이템 최초정보로 호출
|
||||
priceCd: priceCd,
|
||||
//itemIdList: state.itemList, //아이템 최초정보로 호출 delFlg 0인거만..
|
||||
itemIdList: state.itemList.filter((item) => item.delFlg === '0'),
|
||||
}
|
||||
|
||||
if (param.itemIdList.length > 0) {
|
||||
let pass = true
|
||||
|
||||
param.itemIdList.map((item) => {
|
||||
if (item.itemId === '') {
|
||||
pass = false
|
||||
}
|
||||
})
|
||||
|
||||
if (!pass) {
|
||||
//Pricing이 누락된 아이템이 있습니다. Pricing을 진행해주세요.
|
||||
return alert(getMessage('estimate.detail.showPrice.pricingBtn.noItemId'))
|
||||
}
|
||||
}
|
||||
|
||||
// console.log('프라이싱파람::', param)
|
||||
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로 비교해서 단가정보만 업데이트
|
||||
if (data.result.code === 200) {
|
||||
if (isNotEmptyArray(data.data2)) {
|
||||
//아이템쪽 다 새로고침............
|
||||
//성공후..
|
||||
//기존itemList랑 프라이싱결과랑 비교해서 단가만 업뎃 서로 갯수가 안맞을 수 있음 없는 itemId면 unitPrice 0으로
|
||||
//itemId로 비교해서 단가정보만 업데이트
|
||||
setState({
|
||||
priceCd: session.storeLvl === '1' ? tempPriceCd : priceCd,
|
||||
state.itemList.map((item) => {
|
||||
let checkYn = false
|
||||
data.data2.map((item2) => {
|
||||
if (item2.itemId === item.itemId) {
|
||||
updateList.push({ ...item, unitPrice: item2.unitPrice })
|
||||
checkYn = true
|
||||
}
|
||||
})
|
||||
|
||||
if (!checkYn) {
|
||||
updateList.push({ ...item, unitPrice: '0' })
|
||||
}
|
||||
})
|
||||
|
||||
setState({
|
||||
priceCd: priceCd,
|
||||
itemList: updateList,
|
||||
})
|
||||
|
||||
setItemChangeYn(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -319,13 +362,24 @@ export default function Estimate({ params }) {
|
||||
})
|
||||
|
||||
const updateList = state.itemList.map((item) => {
|
||||
const isDeleted = delList.some((row) => item.dispOrder === row.dispOrder)
|
||||
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 alert(getMessage('estimate.detail.save.requiredItem'))
|
||||
}
|
||||
|
||||
setState({
|
||||
itemList: updateList,
|
||||
})
|
||||
@ -336,7 +390,7 @@ export default function Estimate({ params }) {
|
||||
|
||||
useEffect(() => {
|
||||
if (itemChangeYn) {
|
||||
console.log('아이템에 뭔가 변화가 일어났어', itemChangeYn)
|
||||
// console.log('아이템에 뭔가 변화가 일어났어', itemChangeYn)
|
||||
console.log('아이템상태가져오기::::::::::', state.itemList)
|
||||
}
|
||||
|
||||
@ -778,8 +832,9 @@ export default function Estimate({ params }) {
|
||||
key={uuidv4()}
|
||||
className="select-light"
|
||||
onChange={(e) => {
|
||||
setTempPriceCd(e.target.value)
|
||||
onChangeStorePriceList(e.target.value)
|
||||
}}
|
||||
value={showPriceCd}
|
||||
>
|
||||
{storePriceList.length > 0 && storePriceList.map((row) => <option value={row.priceCd}>{row.priceNm}</option>)}
|
||||
</select>
|
||||
@ -790,9 +845,10 @@ export default function Estimate({ params }) {
|
||||
)}
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
className="btn-origin grey ml5"
|
||||
onClick={() => {
|
||||
handlePricing(state.priceCd)
|
||||
handlePricing(state?.priceCd)
|
||||
}}
|
||||
>
|
||||
{getMessage('estimate.detail.showPrice.pricingBtn')}
|
||||
@ -818,7 +874,15 @@ export default function Estimate({ params }) {
|
||||
</li>
|
||||
</ul>
|
||||
<div className="product-edit-btn">
|
||||
<button className="btn-origin navy mr5" type="button" onClick={addItem}>
|
||||
{/* <button className="btn-origin navy mr5" type="button" onClick={addItem}> */}
|
||||
<button
|
||||
className="btn-origin navy mr5"
|
||||
type="button"
|
||||
onClick={() => {
|
||||
addItem()
|
||||
setItemChangeYn(true)
|
||||
}}
|
||||
>
|
||||
<span className="plus"></span>
|
||||
{getMessage('estimate.detail.showPrice.addItem')}
|
||||
</button>
|
||||
@ -862,108 +926,114 @@ export default function Estimate({ params }) {
|
||||
</thead>
|
||||
<tbody>
|
||||
{state?.itemList.length > 0 &&
|
||||
state.itemList.map((item, index) => {
|
||||
return (
|
||||
<tr key={uuidv4()}>
|
||||
<td className="al-c">
|
||||
<div className="d-check-box light no-text">
|
||||
<input
|
||||
type="checkbox"
|
||||
id={item?.dispOrder}
|
||||
onChange={() => onChangeSelect(item.dispOrder)}
|
||||
checked={selection.has(item.dispOrder) ? true : false}
|
||||
/>
|
||||
<label htmlFor={item?.dispOrder}></label>
|
||||
</div>
|
||||
</td>
|
||||
<td className="al-r">{item?.dispOrder * 100}</td>
|
||||
<td>
|
||||
<div className="form-flex-wrap">
|
||||
<div className="select-wrap mr5">
|
||||
<Select
|
||||
id="long-value-select1"
|
||||
instanceId="long-value-select1"
|
||||
className="react-select-custom"
|
||||
classNamePrefix="custom"
|
||||
placeholder="Select"
|
||||
options={displayItemList}
|
||||
onChange={(e) => {
|
||||
if (isObjectNotEmpty(e)) {
|
||||
onChangeDisplayItem(e.itemId, item.dispOrder)
|
||||
}
|
||||
}}
|
||||
getOptionLabel={(x) => x.itemName}
|
||||
getOptionValue={(x) => x.itemId}
|
||||
isClearable={true}
|
||||
isDisabled={false}
|
||||
value={displayItemList.filter(function (option) {
|
||||
return option.itemId === item.itemId
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
{/* {item?.partAdd === '1' && ( */}
|
||||
{item?.itemChangeFlg === '1' && (
|
||||
<div className="btn-area">
|
||||
<span className="tb_ico change_check"></span>
|
||||
state.itemList.map((item) => {
|
||||
if (item.delFlg === '0') {
|
||||
return (
|
||||
<>
|
||||
<tr key={uuidv4()}>
|
||||
<td className="al-c">
|
||||
<div className="d-check-box light no-text">
|
||||
<input
|
||||
type="checkbox"
|
||||
id={item?.dispOrder}
|
||||
onChange={() => onChangeSelect(item.dispOrder)}
|
||||
checked={selection.has(item.dispOrder) ? true : false}
|
||||
/>
|
||||
<label htmlFor={item?.dispOrder}></label>
|
||||
</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)
|
||||
</td>
|
||||
<td className="al-r">{item?.dispOrder}</td>
|
||||
<td>
|
||||
<div className="form-flex-wrap">
|
||||
<div className="select-wrap mr5">
|
||||
<Select
|
||||
id="long-value-select1"
|
||||
instanceId="long-value-select1"
|
||||
className="react-select-custom"
|
||||
classNamePrefix="custom"
|
||||
placeholder="Select"
|
||||
options={displayItemList}
|
||||
onChange={(e) => {
|
||||
if (isObjectNotEmpty(e)) {
|
||||
onChangeDisplayItem(e.itemId, item.dispOrder)
|
||||
}
|
||||
}}
|
||||
getOptionLabel={(x) => x.itemName}
|
||||
getOptionValue={(x) => x.itemId}
|
||||
isClearable={true}
|
||||
isDisabled={false}
|
||||
value={displayItemList.filter(function (option) {
|
||||
return option.itemId === 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"
|
||||
defaultValue={convertNumberToPriceDecimal(item?.amount)}
|
||||
onChange={(e) => {
|
||||
//onChangeDisplayItem참고
|
||||
//itemChangeFlg = 1, partAdd = 0 셋팅
|
||||
console.log('수량변경::::::::', e.target.value)
|
||||
}}
|
||||
></button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div className="input-wrap" style={{ width: '100%' }}>
|
||||
<input
|
||||
type="text"
|
||||
className="input-light al-r"
|
||||
defaultValue={convertNumberToPriceDecimal(item?.amount)}
|
||||
onChange={(e) => {
|
||||
//onChangeDisplayItem참고
|
||||
//itemChangeFlg = 1, partAdd = 0 셋팅
|
||||
console.log('수량변경::::::::', e.target.value)
|
||||
}}
|
||||
/>
|
||||
</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={convertNumberToPriceDecimal(item?.salePrice)}
|
||||
onChange={(e) => {
|
||||
//onChangeDisplayItem참고
|
||||
//itemChangeFlg, partAdd 받아온 그대로
|
||||
console.log('단가변경:::::::', e.target.value)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{/* <div className="btn-area">
|
||||
<span className="tb_ico open_check">OPEN아이콘 처리</span>
|
||||
</div> */}
|
||||
</div>
|
||||
</td>
|
||||
<td className="al-r">{convertNumberToPriceDecimal(item?.saleTotPrice)}</td>
|
||||
</tr>
|
||||
)
|
||||
/>
|
||||
</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={convertNumberToPriceDecimal(item?.salePrice)}
|
||||
disabled={state?.estimateType === 'YJSS' ? (item.pkgMaterialFlg === '1' ? false : true) : false}
|
||||
onChange={(e) => {
|
||||
//onChangeDisplayItem참고
|
||||
//itemChangeFlg, partAdd 받아온 그대로
|
||||
console.log('단가변경:::::::', e.target.value)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{/* <div className="btn-area">
|
||||
<span className="tb_ico open_check">OPEN아이콘 처리</span>
|
||||
</div> */}
|
||||
</div>
|
||||
</td>
|
||||
<td className="al-r">{convertNumberToPriceDecimal(item?.saleTotPrice)}</td>
|
||||
</tr>
|
||||
</>
|
||||
)
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@ -59,6 +59,12 @@ export const useEstimateController = (planNo) => {
|
||||
try {
|
||||
await get({ url: `/api/estimate/${objectRecoil.floorPlanObjectNo}/${planNo}/detail` }).then((res) => {
|
||||
if (isObjectNotEmpty(res)) {
|
||||
if (res.itemList.length > 0) {
|
||||
res.itemList.map((item) => {
|
||||
item.delFlg = '0'
|
||||
})
|
||||
}
|
||||
|
||||
setState(res)
|
||||
}
|
||||
})
|
||||
@ -133,27 +139,26 @@ export const useEstimateController = (planNo) => {
|
||||
const handleEstimateSubmit = async () => {
|
||||
//0. 필수체크
|
||||
let flag = true
|
||||
console.log('::담긴 estimateData:::', estimateData)
|
||||
|
||||
// console.log('첨부파일:::::', estimateData.fileList)
|
||||
//첨부파일을 첨부안했는데
|
||||
//아이템 fileUploadFlg가1(첨부파일 필수)이 1개라도 있는데 후일 자료 제출(fileFlg) 체크안했으면(0) alert 저장안돼
|
||||
if (estimateData.fileList.length < 1) {
|
||||
if (estimateData.itemList.length > 1) {
|
||||
estimateData.itemList.map((row) => {
|
||||
if (row.fileUploadFlg === '1') {
|
||||
if (estimateData.fileFlg === '0') {
|
||||
alert(getMessage('estimate.detail.save.requiredMsg'))
|
||||
flag = false
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
// if (estimateData.fileList.length < 1) {
|
||||
// if (estimateData.itemList.length > 1) {
|
||||
// estimateData.itemList.map((row) => {
|
||||
// if (row.fileUploadFlg === '1') {
|
||||
// if (estimateData.fileFlg === '0') {
|
||||
// alert(getMessage('estimate.detail.save.requiredMsg'))
|
||||
// flag = false
|
||||
// }
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
|
||||
if (flag) {
|
||||
//1. 첨부파일 저장
|
||||
//1. 첨부파일 저장시작
|
||||
const formData = new FormData()
|
||||
console.log('첨부파일:!!!', estimateData.fileList)
|
||||
formData.append('file', estimateData.fileList)
|
||||
formData.append('objectNo', estimateData.objectNo)
|
||||
formData.append('planNo', estimateData.planNo)
|
||||
@ -161,7 +166,23 @@ export const useEstimateController = (planNo) => {
|
||||
formData.append('userId', estimateData.userId)
|
||||
|
||||
await post({ url: '/api/file/fileUpload', data: formData })
|
||||
//첨부파일저장끝
|
||||
|
||||
//제품라인 추가했는데 아이템 안고르고 저장하면itemId=''은 날리고 나머지 저장하기
|
||||
estimateData.itemList = estimateData.itemList.filter((item) => item.itemId !== '')
|
||||
|
||||
let delCnt = 0
|
||||
estimateData.itemList.map((item) => {
|
||||
if (item.delFlg === '1') {
|
||||
delCnt++
|
||||
}
|
||||
})
|
||||
if (delCnt === estimateData.itemList.length) {
|
||||
return alert(getMessage('estimate.detail.save.requiredItem'))
|
||||
}
|
||||
|
||||
console.log('최종 정보::;', estimateData)
|
||||
console.log('최종 남은 아이템정보:::', estimateData.itemList)
|
||||
//2. 상세데이터 저장
|
||||
return
|
||||
await promisePost({ url: `${ESTIMATE_API_ENDPOINT}/save-estimate`, data: estimateData }).then((res) => {
|
||||
|
||||
@ -844,6 +844,7 @@
|
||||
"estimate.detail.header.showPrice": "価格表示",
|
||||
"estimate.detail.header.unitPrice": "定価",
|
||||
"estimate.detail.showPrice.pricingBtn": "Pricing",
|
||||
"estimate.detail.showPrice.pricingBtn.noItemId": "Pricingが欠落しているアイテムがあります。 Pricingを進めてください.",
|
||||
"estimate.detail.showPrice.description1": "製品価格 OPEN",
|
||||
"estimate.detail.showPrice.description2": "追加, 変更資材",
|
||||
"estimate.detail.showPrice.description3": "添付必須",
|
||||
@ -879,6 +880,7 @@
|
||||
"estimate.detail.productFeaturesPopup.close": "閉じる",
|
||||
"estimate.detail.save.alertMsg": "保存されている見積書で製品を変更した場合、図面や回路には反映されません.",
|
||||
"estimate.detail.save.requiredMsg": "ファイル添付が必須のアイテムがあります。ファイルを添付するか、後日添付をチェックしてください.",
|
||||
"estimate.detail.save.requiredItem": "製品は1つ以上登録する必要があります.",
|
||||
"estimate.detail.reset.confirmMsg": "保存した見積書情報が初期化され、図面情報が反映されます。本当に初期化しますか?",
|
||||
"simulator.title.sub1": "物件番号",
|
||||
"simulator.title.sub2": "作成日",
|
||||
|
||||
@ -849,11 +849,12 @@
|
||||
"estimate.detail.sepcialEstimateProductInfo.pkgUnitPrice": "주택PKG단가 (W)",
|
||||
"estimate.detail.sepcialEstimateProductInfo.pkgWeight": "PKG 용량 (Kw)",
|
||||
"estimate.detail.sepcialEstimateProductInfo.pkgPrice": "PKG 금액",
|
||||
"estimate.detail.sepcialEstimateProductInfo.calcFormula1": "(모듈수량 * 수량)÷100",
|
||||
"estimate.detail.sepcialEstimateProductInfo.calcFormula1": "(모듈용량 * 수량)÷100",
|
||||
"estimate.detail.sepcialEstimateProductInfo.calcFormula2": "PKG단가(W) * PKG용량(W)",
|
||||
"estimate.detail.header.showPrice": "가격표시",
|
||||
"estimate.detail.header.unitPrice": "정가",
|
||||
"estimate.detail.showPrice.pricingBtn": "Pricing",
|
||||
"estimate.detail.showPrice.pricingBtn.noItemId": "Pricing이 누락된 아이템이 있습니다. Pricing을 진행해주세요.",
|
||||
"estimate.detail.showPrice.description1": "제품 가격 OPEN",
|
||||
"estimate.detail.showPrice.description2": "추가, 변경 자재",
|
||||
"estimate.detail.showPrice.description3": "첨부필수",
|
||||
@ -889,6 +890,7 @@
|
||||
"estimate.detail.productFeaturesPopup.close": "닫기",
|
||||
"estimate.detail.save.alertMsg": "저장되었습니다. 견적서에서 제품을 변경할 경우, 도면 및 회로에 반영되지 않습니다.",
|
||||
"estimate.detail.save.requiredMsg": "파일첨부가 필수인 아이템이 있습니다. 파일을 첨부하거나 후일첨부를 체크해주십시오.",
|
||||
"estimate.detail.save.requiredItem": "제품은 1개이상 등록해야 됩니다.",
|
||||
"estimate.detail.reset.confirmMsg": "저장된 견적서 정보가 초기화되고, 도면정보가 반영됩니다. 정말로 초기화 하시겠습니까?",
|
||||
"simulator.title.sub1": "물건번호",
|
||||
"simulator.title.sub2": "작성일",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user