Merge branch 'dev' into dev-yj

This commit is contained in:
yjnoh 2024-11-18 16:35:05 +09:00
commit 40787942f9
26 changed files with 826 additions and 394 deletions

View File

@ -20,6 +20,7 @@ import ProductFeaturesPop from './popup/ProductFeaturesPop'
import { v4 as uuidv4 } from 'uuid'
export default function Estimate({ params }) {
const fixedKey = 'itemKey'
const [itemChangeYn, setItemChangeYn] = useState(false)
const { session } = useContext(SessionContext)
const [objectNo, setObjectNo] = useState('') //
@ -28,6 +29,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 +49,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 +183,7 @@ export default function Estimate({ params }) {
})
}
// option
// option &&
useEffect(() => {
if (state.estimateType !== '') {
const param = {
@ -200,23 +201,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 +237,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)
}
}
}
@ -261,8 +305,71 @@ export default function Estimate({ params }) {
setSelection(newSelection)
}
//
const onChangeAmount = (value, dispOrder, index) => {
//itemChangeFlg = 1, partAdd = 0
let amount = value
amount = Number(value.replace(/[^0-9]/g, '').replaceAll(',', ''))
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(',', '')) * state.itemList[index].salePrice.replaceAll(',', '')).toLocaleString()
updateList = state.itemList.map((item) => {
if (item.dispOrder === dispOrder) {
return { ...item, ...updates }
} else {
return item
}
})
setState({
itemList: updateList,
})
setItemChangeYn(true)
}
//
const onChangeSalePrice = (value, dispOrder, index) => {
//itemChangeFlg, partAdd
let salePrice
salePrice = Number(value.replace(/[^0-9]/g, '').replaceAll(',', ''))
if (isNaN(salePrice)) {
salePrice = 0
} else {
salePrice = salePrice.toLocaleString()
}
let updateList = []
let updates = {}
updates.salePrice = salePrice
updates.saleTotPrice = (Number(salePrice.replaceAll(',', '')) * state.itemList[index].amount.replaceAll(',', '')).toLocaleString()
updateList = state.itemList.map((item) => {
if (item.dispOrder === dispOrder) {
return { ...item, ...updates }
} else {
return item
}
})
setState({
itemList: updateList,
})
setItemChangeYn(true)
}
//
const onChangeDisplayItem = (itemId, dispOrder) => {
const onChangeDisplayItem = (itemId, dispOrder, index) => {
const param = {
itemId: itemId,
}
@ -290,17 +397,37 @@ export default function Estimate({ params }) {
updates.specialNoteCd = res.spnAttrCds
updates.itemGroup = res.itemGroup
updates.delFlg = '0' // 0
updates.saleTotPrice = res.salePrice * state.itemList[index].amount
//104671
let bomList = res.itemBomList
updateList = state.itemList.map((item) => {
if (item.dispOrder === dispOrder) {
return { ...item, ...updates }
} else if (item.paDispOrder === dispOrder) {
return { ...item, delFlg: '1' }
} else {
return item
}
})
setState({
itemList: updateList,
})
//paDispOrder
if (bomList) {
bomList.map((bomItem, index) => {
let newItemDispOrder = Math.max(...state.itemList.map((item) => item.dispOrder))
bomItem.dispOrder = index + 1 + newItemDispOrder
bomItem.delFlg = '0'
bomItem.objectNo = objectNo
bomItem.planNo = planNo
})
setState({
itemList: [...updateList, ...bomList],
})
} else {
setState({
itemList: updateList,
})
}
setItemChangeYn(true)
})
@ -315,17 +442,31 @@ export default function Estimate({ params }) {
if (row2 === row.dispOrder) {
delList.push({ ...row })
}
if (row2 === row.paDispOrder) {
delList.push({ ...row })
}
})
})
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,12 +477,30 @@ export default function Estimate({ params }) {
useEffect(() => {
if (itemChangeYn) {
console.log('아이템에 뭔가 변화가 일어났어', itemChangeYn)
console.log('아이템상태가져오기::::::::::', state.itemList)
}
// console.log(' ::::::::::', state.itemList)
// console.log(' ::::::', itemList)
//delFlg 0 ..
//(PCS) : totAmount
//( Kw) : totVolKw
// : supplyPrice
//(10%) : vatPrice
// :totPrice
// false ..
setItemChangeYn(false)
let totAmount = 0
let amount = 0
state.itemList.map((item) => {
if (item.delFlg === '0') {
amount = item.amount.replace(/[^0-9]/g, '').replaceAll(',', '')
totAmount += Number(amount)
}
})
setState({
totAmount: totAmount,
})
setItemChangeYn(false)
}
}, [itemChangeYn])
return (
@ -534,10 +693,10 @@ export default function Estimate({ params }) {
<>
<div className={`form-flex-wrap ${style}`} key={uuidv4()}>
<div className="input-wrap mr5" style={{ width: '610px' }} key={`roof${index}`}>
<input type="text" className="input-light" defaultValue={roofList} readOnly />
<input type="text" className="input-light" value={roofList} readOnly />
</div>
<div className="input-wrap" style={{ width: '200px' }}>
<input type="text" className="input-light" defaultValue={constructSpecificationMulti[index]} readOnly />
<input type="text" className="input-light" value={constructSpecificationMulti[index]} readOnly />
</div>
</div>
</>
@ -778,8 +937,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 +950,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 +979,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>
@ -863,107 +1032,123 @@ export default function Estimate({ params }) {
<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>
if (item.delFlg === '0') {
return (
<>
<tr key={fixedKey}>
<td className="al-c">
<div className="d-check-box light no-text">
<input
type="checkbox"
id={item?.dispOrder}
disabled={item?.paDispOrder ? true : false}
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, index)
}
}}
getOptionLabel={(x) => x.itemName}
getOptionValue={(x) => x.itemId}
isClearable={false}
isDisabled={item?.paDispOrder ? true : 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"
value={item?.amount}
disabled={item.itemId === '' ? true : item?.paDispOrder ? true : false}
onChange={(e) => {
onChangeAmount(e.target.value, item.dispOrder, index)
}}
></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={item?.salePrice}
disabled={
state?.estimateType === 'YJSS'
? item?.paDispOrder
? true
: item.pkgMaterialFlg === '1'
? false
: true
: item.itemId === ''
? true
: item?.paDispOrder
? true
: false
}
onChange={(e) => {
onChangeSalePrice(e.target.value, item.dispOrder, index)
}}
/>
</div>
{/* <div className="btn-area">
<span className="tb_ico open_check">OPEN아이콘 처리</span>
</div> */}
</div>
</td>
<td className="al-r">{item?.saleTotPrice}</td>
</tr>
</>
)
} else {
return null
}
})}
</tbody>
</table>

View File

@ -6,36 +6,74 @@ import { useRecoilValue } from 'recoil'
import { floorPlanObjectState } from '@/store/floorPlanObjectAtom'
export default function DocDownOptionPop({ planNo, setEstimatePopupOpen }) {
// console.log('::::::::::::', planNo)
const { getMessage } = useMessage()
const { promiseGet } = useAxios()
const { promisePost } = useAxios()
//EXCEL, PDF
const [schDownload, setSchDownload] = useState('EXCEL')
// EXCEL
const [schUnitPriceFlg, setSchUnitPriceFlg] = useState('0')
//
const [schDisplayFlg, setSchSchDisplayFlg] = useState('0')
//
const [schWeightFlg, setSchWeightFlg] = useState('0')
///
const [schDrawingFlg, setSchDrawingFlg] = useState('0')
// (:1 : 0)
const [schWeightFlg, setSchWeightFlg] = useState('1')
/// (:1 : 0)
const [schDrawingFlg, setSchDrawingFlg] = useState('1')
// recoil
const objectRecoil = useRecoilValue(floorPlanObjectState)
//
const handleFileDown = async () => {
// console.log(':::', objectRecoil.floorPlanObjectNo)
// console.log('planNo::', planNo)
//
//0 : Excel 1 : Excel 2: PDF 3 :PDF
// console.log(schUnitPriceFlg)
// console.log(schDisplayFlg)
// console.log(schWeightFlg)
// console.log(schDrawingFlg)
const url = '/api/estimate/excel-download'
const params = {}
let sendUnitPriceFlg
if (schUnitPriceFlg === '0') {
sendUnitPriceFlg = '0'
} else if (schUnitPriceFlg === '1') {
sendUnitPriceFlg = '1'
} else if (schUnitPriceFlg === '2') {
sendUnitPriceFlg = '0'
} else {
sendUnitPriceFlg = '1'
}
const params = {
objectNo: objectRecoil.floorPlanObjectNo,
planNo: planNo,
schDownload: schDownload,
schUnitPriceFlg: sendUnitPriceFlg,
schDisplayFlg: schDisplayFlg,
schWeightFlg: schWeightFlg,
schDrawingFlg: schDrawingFlg,
}
const options = { responseType: 'blob' }
await promisePost({ url: url, data: params, option: options })
.then((resultData) => {
if (resultData) {
let fileName = 'unknow'
const blob = new Blob([resultData.data], { type: resultData.headers['content-type'] || 'application/octet-stream' })
const fileUrl = window.URL.createObjectURL(blob)
const link = document.createElement('a')
link.href = fileUrl
//
const contentDisposition = resultData.headers['content-disposition']
if (contentDisposition) {
fileName = contentDisposition.split('filename=')[1].replace(/['"]/g, '')
}
link.download = fileName
document.body.appendChild(link)
link.click()
link.remove()
window.URL.revokeObjectURL(fileUrl)
}
})
.catch((error) => {
console.log('::FileDownLoad Error::', error)
alert('File does not exist.')
})
}
return (
@ -74,28 +112,30 @@ export default function DocDownOptionPop({ planNo, setEstimatePopupOpen }) {
<div className="d-check-radio light mr10">
<input
type="radio"
id="schUnitPriceFlg0"
id="schUnitPriceExcelFlg0"
name="schUnitPriceFlg"
value={'0'}
checked={schUnitPriceFlg === '0'}
onChange={(e) => {
setSchDownload('EXCEL')
setSchUnitPriceFlg(e.target.value)
}}
/>
<label htmlFor="schUnitPriceFlg0">{getMessage('estimate.detail.docPopup.schUnitPriceFlg.schUnitPriceFlg0')}</label>
<label htmlFor="schUnitPriceExcelFlg0">{getMessage('estimate.detail.docPopup.schUnitPriceFlg.excelFlg0')}</label>
</div>
<div className="d-check-radio light mr10">
<input
type="radio"
id="schUnitPriceFlg1"
id="schUnitPriceExcelFlg1"
name="schUnitPriceFlg"
value={'1'}
checked={schUnitPriceFlg === '1'}
onChange={(e) => {
setSchDownload('EXCEL')
setSchUnitPriceFlg(e.target.value)
}}
/>
<label htmlFor="schUnitPriceFlg1">{getMessage('estimate.detail.docPopup.schUnitPriceFlg.schUnitPriceFlg1')}</label>
<label htmlFor="schUnitPriceExcelFlg1">{getMessage('estimate.detail.docPopup.schUnitPriceFlg.excelFlg1')}</label>
</div>
<div className="d-check-radio light mr10">
<input
@ -105,10 +145,11 @@ export default function DocDownOptionPop({ planNo, setEstimatePopupOpen }) {
value={'2'}
checked={schUnitPriceFlg === '2'}
onChange={(e) => {
setSchDownload('PDF')
setSchUnitPriceFlg(e.target.value)
}}
/>
<label htmlFor="schUnitPricePdfFlg0">{getMessage('estimate.detail.docPopup.schUnitPriceFlg.schUnitPriceFlg2')}</label>
<label htmlFor="schUnitPricePdfFlg0">{getMessage('estimate.detail.docPopup.schUnitPriceFlg.pdfFlg0')}</label>
</div>
<div className="d-check-radio light ">
<input
@ -118,10 +159,11 @@ export default function DocDownOptionPop({ planNo, setEstimatePopupOpen }) {
value={'3'}
checked={schUnitPriceFlg === '3'}
onChange={(e) => {
setSchDownload('PDF')
setSchUnitPriceFlg(e.target.value)
}}
/>
<label htmlFor="schUnitPricePdfFlg1">{getMessage('estimate.detail.docPopup.schUnitPriceFlg.schUnitPriceFlg3')}</label>
<label htmlFor="schUnitPricePdfFlg1">{getMessage('estimate.detail.docPopup.schUnitPriceFlg.pdfFlg1')}</label>
</div>
</div>
</td>
@ -168,19 +210,6 @@ export default function DocDownOptionPop({ planNo, setEstimatePopupOpen }) {
<td>
<div className="form-flex-wrap">
<div className="d-check-radio light mr10">
<input
type="radio"
name="schWeightFlg"
id="schWeightFlg0"
value={'0'}
checked={schWeightFlg === '0'}
onChange={(e) => {
setSchWeightFlg(e.target.value)
}}
/>
<label htmlFor="schWeightFlg0">{getMessage('estimate.detail.docPopup.schWeightFlg.schWeightFlg0')}</label>
</div>
<div className="d-check-radio light">
<input
type="radio"
name="schWeightFlg"
@ -193,6 +222,19 @@ export default function DocDownOptionPop({ planNo, setEstimatePopupOpen }) {
/>
<label htmlFor="schWeightFlg1">{getMessage('estimate.detail.docPopup.schWeightFlg.schWeightFlg1')}</label>
</div>
<div className="d-check-radio light">
<input
type="radio"
name="schWeightFlg"
id="schWeightFlg0"
value={'0'}
checked={schWeightFlg === '0'}
onChange={(e) => {
setSchWeightFlg(e.target.value)
}}
/>
<label htmlFor="schWeightFlg0">{getMessage('estimate.detail.docPopup.schWeightFlg.schWeightFlg0')}</label>
</div>
</div>
</td>
</tr>
@ -201,6 +243,19 @@ export default function DocDownOptionPop({ planNo, setEstimatePopupOpen }) {
<td>
<div className="form-flex-wrap">
<div className="d-check-radio light mr10">
<input
type="radio"
name="schDrawingFlg"
id="schDrawingFlg1"
value={'1'}
checked={schDrawingFlg === '1'}
onChange={(e) => {
setSchDrawingFlg(e.target.value)
}}
/>
<label htmlFor="schDrawingFlg1">{getMessage('estimate.detail.docPopup.schDrawingFlg.schDrawingFlg1')}</label>
</div>
<div className="d-check-radio light">
<input
type="radio"
name="schDrawingFlg"
@ -213,19 +268,6 @@ export default function DocDownOptionPop({ planNo, setEstimatePopupOpen }) {
/>
<label htmlFor="schDrawingFlg0">{getMessage('estimate.detail.docPopup.schDrawingFlg.schDrawingFlg0')}</label>
</div>
<div className="d-check-radio light">
<input
type="radio"
name="schDrawingFlg"
id="schDrawingFlg01"
value={'1'}
checked={schDrawingFlg === '1'}
onChange={(e) => {
setSchDrawingFlg(e.target.value)
}}
/>
<label htmlFor="schDrawingFlg01">{getMessage('estimate.detail.docPopup.schDrawingFlg.schDrawingFlg1')}</label>
</div>
</div>
</td>
</tr>

View File

@ -184,7 +184,7 @@ export default function CanvasMenu(props) {
}, [type, globalLocale])
useEffect(() => {
if (['2', '3'].includes(canvasSetting?.roofSizeSet?.toString())) {
if ([2, 3].some((num) => num === canvasSetting?.roofSizeSet)) {
setMenuNumber(3)
setType('surface')
setCurrentMenu(MENU.BATCH_CANVAS.BATCH_DRAWING)
@ -195,8 +195,12 @@ export default function CanvasMenu(props) {
}
}, [canvasSetting])
const checkMenuState = (menu) => {
return ([2, 3].some((num) => num === canvasSetting?.roofSizeSet) && menu.index === 2) || (menuNumber === 4 && menu.index === 2)
}
return (
<div className={`canvas-menu-wrap ${menuNumber === 2 || menuNumber === 3 || menuNumber === 4 ? 'active' : ''}`}>
<div className={`canvas-menu-wrap ${[2, 3, 4].some((num) => num === menuNumber) ? 'active' : ''}`}>
<div className="canvas-menu-inner">
<ul className="canvas-menu-list">
{canvasMenus.map((menu) => {
@ -205,11 +209,12 @@ export default function CanvasMenu(props) {
key={`canvas-menu-${menu.index}`}
className={`canvas-menu-item ${menuNumber === menu.index ? 'active' : ''}`}
onClick={() => {
if (['2', '3'].includes(canvasSetting?.roofSizeSet?.toString()) && menu.index === 2) return
if ([2, 3].some((num) => num === canvasSetting?.roofSizeSet) && menu.index === 2) return
if (menuNumber === 4 && menu.index === 2) return
onClickNav(menu)
}}
>
<button className={['2', '3'].includes(canvasSetting?.roofSizeSet?.toString()) && menu.index === 2 ? 'no-click' : ''}>
<button className={checkMenuState(menu) ? 'no-click' : ''}>
<span className={`menu-icon ${menu.icon}`}></span>
{getMessage(menu.name)}
</button>
@ -218,7 +223,7 @@ export default function CanvasMenu(props) {
})}
</ul>
<div className="canvas-side-btn-wrap">
{menuNumber !== 6 && menuNumber !== 5 && (
{![5, 6].some((num) => num === menuNumber) && (
<>
{
<div className={`vertical-horizontal ${verticalHorizontalMode ? 'on' : ''}`}>
@ -248,7 +253,7 @@ export default function CanvasMenu(props) {
handleZoom(false)
}}
></button>
<span>{canvasZoom}%</span>
<span onClick={handleZoomClear}>{canvasZoom}%</span>
<button
className="control-btn plus"
onClick={() => {
@ -314,8 +319,8 @@ export default function CanvasMenu(props) {
)}
</div>
</div>
<div className={`canvas-depth2-wrap ${menuNumber === 2 || menuNumber === 3 || menuNumber === 4 ? 'active' : ''}`}>
{(menuNumber === 2 || menuNumber === 3 || menuNumber === 4) && <MenuDepth01 />}
<div className={`canvas-depth2-wrap ${[2, 3, 4].some((num) => num === menuNumber) ? 'active' : ''}`}>
{[2, 3, 4].some((num) => num === menuNumber) && <MenuDepth01 />}
</div>
{/* 견적서(menuNumber=== 5) 상세화면인경우 문서다운로드 팝업 */}
{estimatePopupOpen && <DocDownOptionPop planNo={estimateRecoilState?.planNo} setEstimatePopupOpen={setEstimatePopupOpen} />}

View File

@ -1,6 +1,6 @@
import { forwardRef, useImperativeHandle, useState } from 'react'
import { useMessage } from '@/hooks/useMessage'
import { useOrientation } from '@/hooks/popup/useOrientation'
import { useOrientation } from '@/hooks/module/useOrientation'
import { getDegreeInOrientation } from '@/util/canvas-util'
export const Orientation = forwardRef(({ tabNum }, ref) => {

View File

@ -6,7 +6,7 @@ import { contextPopupPositionState } from '@/store/popupAtom'
import { useMessage } from '@/hooks/useMessage'
import { usePopup } from '@/hooks/usePopup'
import { useSurfaceShapeBatch } from '@/hooks/surface/useSurfaceShapeBatch'
import { FLOW_DIRECTION_TYPE, useFlowDirectionSetting } from '@/hooks/popup/useFlowDirectionSetting'
import { FLOW_DIRECTION_TYPE, useFlowDirectionSetting } from '@/hooks/contextpopup/useFlowDirectionSetting'
import { canvasState } from '@/store/canvasAtom'
export default function FlowDirectionSetting(props) {
const contextPopupPosition = useRecoilValue(contextPopupPositionState)

View File

@ -1,42 +0,0 @@
import WithDraggable from '@/components/common/draggable/WithDraggable'
import { useState } from 'react'
import { usePopup } from '@/hooks/usePopup'
import { useRecoilValue } from 'recoil'
import { contextPopupPositionState } from '@/store/popupAtom'
import { useMessage } from '@/hooks/useMessage'
export default function ImageSizeSetting(props) {
const contextPopupPosition = useRecoilValue(contextPopupPositionState)
const { id, pos = contextPopupPosition, size, setSize } = props
const [sizeValue, setSizeValue] = useState(100)
const { getMessage } = useMessage()
const { closePopup } = usePopup()
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap xxxm mount`}>
<div className="modal-head">
<h1 className="title">{getMessage('modal.image.size.setting')} </h1>
<button className="modal-close" onClick={() => closePopup(id)}>
닫기
</button>
</div>
<div className="modal-body">
<div className="range-wrap">
<input
type="range"
id="size"
name="volume"
min="20"
max="200"
step={10}
value={sizeValue}
onChange={(e) => setSizeValue(e.target.value)}
/>
<label htmlFor="size">{sizeValue}%</label>
</div>
</div>
</div>
</WithDraggable>
)
}

View File

@ -12,7 +12,6 @@ import { usePopup } from '@/hooks/usePopup'
import SizeGuide from '@/components/floor-plan/modal/placementShape/SizeGuide'
import MaterialGuide from '@/components/floor-plan/modal/placementShape/MaterialGuide'
import WithDraggable from '@/components/common/draggable/WithDraggable'
import { SessionContext } from '@/app/SessionProvider'
export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, setShowPlaceShapeModal }) {
const [objectNo, setObjectNo] = useState('test123241008001') //

View File

@ -4,7 +4,7 @@ import { Fragment, useCallback, useEffect, useState } from 'react'
import Link from 'next/link'
import { usePathname } from 'next/navigation'
import { useRecoilState, useRecoilValue } from 'recoil'
import { useRecoilState, useRecoilValue, useResetRecoilState } from 'recoil'
import { dimmedStore, sessionStore } from '@/store/commonAtom'
import { useMessage } from '@/hooks/useMessage'
@ -16,6 +16,8 @@ import UserInfoModal from '@/components/myInfo/UserInfoModal'
import { useAxios } from '@/hooks/useAxios'
import { globalLocaleStore } from '@/store/localeAtom'
import { stuffSearchState } from '@/store/stuffAtom'
export const ToggleonMouse = (e, act, target) => {
const listWrap = e.target.closest(target)
const ListItem = Array.from(listWrap.childNodes)
@ -34,6 +36,8 @@ export const ToggleonMouse = (e, act, target) => {
export default function Header(props) {
const [userInfoModal, setUserInfoModal] = useState(false)
const resetStuffRecoil = useResetRecoilState(stuffSearchState)
const { userSession } = props
const [sessionState, setSessionState] = useRecoilState(sessionStore)
const { getMessage } = useMessage()
@ -184,7 +188,14 @@ export default function Header(props) {
{userInfoModal && <UserInfoModal userId={sessionState.userId} userInfoModal={userInfoModal} setUserInfoModal={setUserInfoModal} />}
</div>
<div className="sign-out-box">
<button className="sign-out" onClick={() => logout()}>
<button
className="sign-out"
onClick={() => {
// ..
resetStuffRecoil()
logout()
}}
>
{getMessage('header.logout')}
</button>
</div>

View File

@ -39,9 +39,9 @@ export default function Stuff() {
const copyNo = async (value) => {
try {
await navigator.clipboard.writeText(value)
alert(getMessage('stuff.detail.header.message2'))
alert(getMessage('stuff.detail.header.successCopy'))
} catch (error) {
alert(getMessage('stuff.detail.header.message3'))
alert(getMessage('stuff.detail.header.failCopy'))
}
}
@ -209,6 +209,7 @@ export default function Stuff() {
endRow: pageNo * pageSize,
schSelSaleStoreId: stuffSearchParams?.schOtherSelSaleStoreId ? stuffSearchParams.schOtherSelSaleStoreId : stuffSearchParams.schSelSaleStoreId,
schSortType: 'R',
code: 'S',
}
setStuffSearch({
...params,

View File

@ -19,10 +19,15 @@ import { useCommonCode } from '@/hooks/common/useCommonCode'
import StuffPlanQGrid from './StuffPlanQGrid'
import { floorPlanObjectState } from '@/store/floorPlanObjectAtom'
import { ManagementContext } from '@/app/management/ManagementProvider'
import DocDownOptionPop from '../estimate/popup/DocDownOptionPop'
export default function StuffDetail() {
const setFloorPlanObjectNo = useSetRecoilState(floorPlanObjectState) //
const [estimatePopupOpen, setEstimatePopupOpen] = useState(false)
const [popPlanNo, setPopPlanNo] = useState('1') //default 1
//
const { commonCode, findCommonCode } = useCommonCode()
const [selOptions, setSelOptions] = useState('') // 1
@ -266,11 +271,12 @@ export default function StuffDetail() {
type="button"
className="grid-btn"
onClick={() => {
console.log('엑셀버튼클릭')
setFloorPlanObjectNo({ floorPlanObjectNo: params.data.objectNo })
handleEstimatePopup(params.data.planNo)
}}
>
<span className="excel"></span>
{getMessage('stuff.detail.planGrid.btn2')}
{getMessage('stuff.detail.planGrid.docDownload')}
</button>
</div>
</>
@ -280,6 +286,12 @@ export default function StuffDetail() {
],
})
//
const handleEstimatePopup = (planNo) => {
setPopPlanNo(planNo)
setEstimatePopupOpen(true)
}
useEffect(() => {
if (objectNo) {
setEditMode('EDIT')
@ -289,10 +301,12 @@ export default function StuffDetail() {
}
promiseGet({ url: `/api/object/${objectNo}/detail` }).then((res) => {
if (res.status === 200) {
if (res.data != null) {
if (isObjectNotEmpty(res.data)) {
setManagementState(res.data)
} else {
setManagementState({})
alert(getMessage('stuff.detail.header.notExistObjectNo'))
router.push('/management/stuff')
}
if (isNotEmptyArray(res.data.planList)) {
setPlanGridProps({ ...planGridProps, planGridData: res.data.planList })
@ -302,6 +316,9 @@ export default function StuffDetail() {
} else {
setManagementState({})
setPlanGridProps({ ...planGridProps, planGridData: [] })
alert(getMessage('stuff.detail.header.notExistObjectNo'))
router.push('/management/stuff')
}
})
} else {
@ -2433,6 +2450,8 @@ export default function StuffDetail() {
{showWindSpeedButtonValid && (
<WindSelectPop setShowWindSpeedButtonValid={setShowWindSpeedButtonValid} prefName={form.watch('prefName')} windSpeedInfo={setWindSppedInfo} />
)}
{estimatePopupOpen && <DocDownOptionPop planNo={popPlanNo} setEstimatePopupOpen={setEstimatePopupOpen} />}
</>
)
}

View File

@ -116,8 +116,10 @@ export default function StuffSearchCondition() {
schAddress: address,
schObjectName: objectName,
schDispCompanyName: dispCompanyName,
schSelSaleStoreId: stuffSearch?.schSelSaleStoreId,
schOtherSelSaleStoreId: stuffSearch?.schOtherSelSaleStoreId,
// schSelSaleStoreId: stuffSearch?.schSelSaleStoreId,
// schOtherSelSaleStoreId: stuffSearch?.schOtherSelSaleStoreId,
schSelSaleStoreId: schSelSaleStoreId,
schOtherSelSaleStoreId: otherSaleStoreId,
schReceiveUser: receiveUser,
schDateType: dateType,
schFromDt: dayjs(startDate).format('YYYY-MM-DD'),
@ -157,6 +159,7 @@ export default function StuffSearchCondition() {
setStuffSearch({
schSelSaleStoreId: '',
schOtherSelSaleStoreId: '',
schDateType: 'U',
})
} else {
if (otherSaleStoreList.length > 1) {
@ -312,8 +315,8 @@ export default function StuffSearchCondition() {
} else {
//X
//
setSchSelSaleStoreId('')
// stuffSearch.schSelSaleStoreId = ''
// setSchSelSaleStoreId('') // ..
setSchSelSaleStoreId(null)
//2
setOtherSaleStoreList([])
@ -333,7 +336,6 @@ export default function StuffSearchCondition() {
if (session.storeLvl === '1') {
if (stuffSearch.schOtherSelSaleStoreId === '') {
//
// stuffSearch.schSelSaleStoreId = ''
setSchSelSaleStoreId(session.storeId)
} else {
//
@ -357,6 +359,7 @@ export default function StuffSearchCondition() {
setobjectName(stuffSearch.schObjectName ? stuffSearch.schObjectName : objectName)
setDispCompanyName(stuffSearch.schDispCompanyName ? stuffSearch.schDispCompanyName : dispCompanyName)
setReceiveUser(stuffSearch.schReceiveUser ? stuffSearch.schReceiveUser : receiveUser)
setDateType(stuffSearch.schDateType ? stuffSearch.schDateType : dateType)
}, [stuffSearch])
useEffect(() => {
@ -638,7 +641,7 @@ export default function StuffSearchCondition() {
type="radio"
name="radio_ptype"
id="radio_u"
checked={stuffSearch.schDateType === 'U' ? true : false}
checked={dateType === 'U' ? true : false}
value={'U'}
onChange={(e) => {
setDateType(e.target.value)
@ -652,7 +655,7 @@ export default function StuffSearchCondition() {
type="radio"
name="radio_ptype"
id="radio_r"
checked={stuffSearch.schDateType === 'R' ? true : false}
checked={dateType === 'R' ? true : false}
value={'R'}
onChange={(e) => {
setDateType(e.target.value)

View File

@ -105,8 +105,8 @@ export default function Simulator() {
useEffect(() => {
if (objectNo) {
fetchObjectDetail(objectNo)
fetchSimulatorNotice()
}
fetchSimulatorNotice()
}, [objectNo, plan])
//
@ -158,23 +158,25 @@ export default function Simulator() {
<div className="estimate-box">
<div className="estimate-tit">{getMessage('simulator.title.sub1')}</div>
<div className="estimate-name">
{objectDetail.objectNo} (Plan No: {objectDetail.planNo})
{objectDetail.objectNo} (Plan No: {plan?.id})
</div>
</div>
{/* 작성일 */}
<div className="estimate-box">
<div className="estimate-tit">{getMessage('simulator.title.sub2')}</div>
<div className="estimate-name">{`${dayjs(objectDetail.drawingEstimateCreateDate).format('YYYY.MM.DD')}`}</div>
<div className="estimate-name">
{objectDetail.drawingEstimateCreateDate ? `${dayjs(objectDetail.drawingEstimateCreateDate).format('YYYY.MM.DD')}` : ''}
</div>
</div>
{/* 시스템용량 */}
<div className="estimate-box">
<div className="estimate-tit">{getMessage('simulator.title.sub3')}</div>
<div className="estimate-name">{convertNumberToPriceDecimal(objectDetail.capacity)}kW</div>
<div className="estimate-name">{objectDetail.capacity ? `${convertNumberToPriceDecimal(objectDetail.capacity)}kW` : ''}</div>
</div>
{/* 연간예측발전량 */}
<div className="estimate-box">
<div className="estimate-tit">{getMessage('simulator.title.sub4')}</div>
<div className="estimate-name">{convertNumberToPriceDecimal(objectDetail.anlFrcsGnrt)}</div>
<div className="estimate-name">{objectDetail.anlFrcsGnrt ? convertNumberToPriceDecimal(objectDetail.anlFrcsGnrt) : ''}</div>
</div>
</div>
<div className="estimate-list-wrap">

View File

@ -40,19 +40,19 @@ export function useCanvasConfigInitialize() {
const flowTexts = canvas.getObjects().filter((obj) => obj.name === 'flowText')
if (basicSetting.roofAngleSet === 'slope') {
offsetTexts.forEach((obj) => {
obj.set({ text: `${obj.originText}-${obj.pitch}${angleUnit}` })
obj.set({ text: `${!obj.originText ? '' : obj.originText + '-'}${obj.pitch}${angleUnit}` })
})
flowTexts.forEach((obj) => {
obj.set({ text: `${obj.originText}-${obj.pitch}${pitchText}` })
obj.set({ text: `${!obj.originText ? '' : obj.originText + '-'}${obj.pitch}${pitchText}` })
})
}
if (basicSetting.roofAngleSet === 'flat') {
offsetTexts.forEach((obj) => {
obj.set({ text: `${obj.originText}-${getDegreeByChon(obj.pitch)}${angleUnit}` })
obj.set({ text: `${!obj.originText ? '' : obj.originText + '-'}${getDegreeByChon(obj.pitch)}${angleUnit}` })
})
flowTexts.forEach((obj) => {
obj.set({ text: `${obj.originText}-${getDegreeByChon(obj.pitch)}${pitchText}` })
obj.set({ text: `${!obj.originText ? '' : obj.originText + '-'}${getDegreeByChon(obj.pitch)}${pitchText}` })
})
}

View File

@ -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)
}
})
@ -76,7 +82,9 @@ export const useEstimateController = (planNo) => {
}
const addItem = () => {
const newItemDispOrder = Math.max(...state.itemList.map((item) => item.dispOrder)) + 1
// const newItemDispOrder = (Math.max(...state.itemList.map((item) => item.dispOrder)) / 100 + 1) * 100
let newItemDispOrder = Math.max(...state.itemList.map((item) => item.dispOrder))
newItemDispOrder = (Math.floor(newItemDispOrder / 100) + 1) * 100
setState({
itemList: [
...state.itemList,
@ -90,8 +98,8 @@ export const useEstimateController = (planNo) => {
amount: '', //수량
unitPrice: '0',
unit: '', //단위
salePrice: '0', //단가
saleTotPrice: '0', //금액(부가세별도)
salePrice: '', //단가
saleTotPrice: '', //금액(부가세별도)
itemChangeFlg: '1', //추가시 체인지플래그 1로
partAdd: '1', //NEW 체인지 플래그
delFlg: '0', //삭제 플래그 0 삭제하면 1
@ -133,7 +141,7 @@ 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 저장안돼
@ -151,9 +159,8 @@ export const useEstimateController = (planNo) => {
}
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,26 +168,30 @@ 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
// return
await promisePost({ url: `${ESTIMATE_API_ENDPOINT}/save-estimate`, data: estimateData }).then((res) => {
if (res) {
alert(getMessage('estimate.detail.save.alertMsg'))
}
})
// try {
// const result = await promisePost({
// url: ESTIMATE_API_ENDPOINT,
// data: estimateData,
// })
// alert(getMessage('estimate.detail.save.alertMsg'))
// return result
// } catch (error) {
// console.error('Failed to submit estimate:', error)
// throw error
// }
}
}

View File

@ -3,6 +3,7 @@ import { canvasState } from '@/store/canvasAtom'
import { usePolygon } from '@/hooks/usePolygon'
import { POLYGON_TYPE } from '@/common/common'
import { compasDegAtom } from '@/store/orientationAtom'
import { useEffect } from 'react'
// 모듈,회로 구성 탭 기본설정 > 방위설정 탭
export function useOrientation() {
@ -11,6 +12,16 @@ export function useOrientation() {
const { drawDirectionArrow } = usePolygon()
useEffect(() => {
const roofs = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
roofs.forEach((roof) => {
roof.set({
moduleCompass: null,
})
drawDirectionArrow(roof)
})
}, [])
const nextStep = () => {
const roofs = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
roofs.forEach((roof) => {

View File

@ -277,7 +277,7 @@ export function useCanvasSetting() {
optionName = ['outerLine', POLYGON_TYPE.WALL]
break
case 'gridDisplay': //그리드 표시
optionName = ['lindGrid', 'dotGrid']
optionName = ['lindGrid', 'dotGrid', 'tempGrid']
break
case 'lineDisplay': //지붕선 표시
optionName = ['roof', POLYGON_TYPE.ROOF]

View File

@ -1,81 +0,0 @@
import { useRecoilState, useRecoilValue } from 'recoil'
import { canvasState } from '@/store/canvasAtom'
import { useEffect } from 'react'
import { settingModalFirstOptionsState } from '@/store/settingAtom'
import { POLYGON_TYPE } from '@/common/common'
export function useFirstOption() {
const canvas = useRecoilValue(canvasState)
const [settingModalFirstOptions, setSettingModalFirstOptions] = useRecoilState(settingModalFirstOptionsState)
useEffect(() => {
const option1 = settingModalFirstOptions.option1
// 'allocDisplay' 할당 표시
// 'outlineDisplay' 외벽선 표시 'outerLine', POLYGON_TYPE.WALL
// 'gridDisplay' 그리드 표시 'lindGrid', 'dotGrid'
// 'lineDisplay' 지붕선 표시 'roof', POLYGON_TYPE.ROOF
// 'wordDisplay' 문자 표시
// 'circuitNumDisplay' 회로번호 표시
// 'flowDisplay' 흐름방향 표시 'arrow'
// 'trestleDisplay' 가대 표시
// 'totalDisplay' 집계표 표시
let optionName //옵션명
let optionSelected //옵션상태
for (let i = 0; i < option1.length; i++) {
switch (option1[i].column) {
case 'allocDisplay': //할당 표시
optionName = ['1']
break
case 'outlineDisplay': //외벽선 표시
optionName = ['outerLine', POLYGON_TYPE.WALL]
break
case 'gridDisplay': //그리드 표시
optionName = ['lineGrid', 'dotGrid', 'adsorptionPoint', 'tempGrid']
break
case 'lineDisplay': //지붕선 표시
optionName = ['roof', POLYGON_TYPE.ROOF]
break
case 'wordDisplay': //문자 표시
optionName = ['commonText']
break
case 'circuitNumDisplay': //회로번호 표시
optionName = ['7']
break
case 'flowDisplay': //흐름방향 표시
optionName = ['arrow', 'flowText']
break
case 'trestleDisplay': //가대 표시
optionName = ['8']
break
case 'totalDisplay': //집계표 표시
optionName = ['9']
break
}
// 표시 선택 상태(true/false)
optionSelected = option1[i].selected
canvas
.getObjects()
.filter((obj) => optionName.includes(obj.name))
//.filter((obj) => obj.name === optionName)
.forEach((obj) => {
obj.set({ visible: optionSelected })
//obj.set({ visible: !obj.visible })
})
canvas.renderAll()
// console.log(
// 'optionName',
// optionName,
// canvas.getObjects().filter((obj) => optionName.includes(obj.name)),
// )
}
}, [settingModalFirstOptions])
return { settingModalFirstOptions, setSettingModalFirstOptions }
}

View File

@ -455,9 +455,24 @@ export function useAuxiliaryDrawing(id) {
name: 'auxiliaryLine',
})
lineHistory.current.push(line)
const historyLines = [...lineHistory.current]
const hasSameLine = historyLines.some((history) => {
return (
(isSamePoint(history.startPoint, line.startPoint) && isSamePoint(history.endPoint, line.endPoint)) ||
(isSamePoint(history.startPoint, line.endPoint) && isSamePoint(history.endPoint, line.startPoint))
)
})
mousePointerArr.current = []
clear()
if (hasSameLine) {
canvas.remove(line)
return
}
lineHistory.current.push(line)
}
const mouseDown = (e) => {

View File

@ -125,6 +125,12 @@ export function usePropertiesSetting(id) {
}
const lines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
const notSetAttributes = lines.filter((line) => !line.attributes?.type)
if (notSetAttributes.length > 0) {
alert('설정되지 않은 외벽선이 있습니다.')
return
}
lines.forEach((line) => {
line.set({
attributes: line.attributes ? line.attributes : { offset: 0, type: LINE_TYPE.WALLLINE.WALL },

View File

@ -377,20 +377,20 @@ export function useRoofShapeSetting(id) {
}
// 기존 wallLine, roofBase 제거
/*canvas
canvas
.getObjects()
.filter((obj) => obj.name === POLYGON_TYPE.WALL)
.forEach((line) => {
canvas.remove(line)
})*/
})
/*canvas
canvas
.getObjects()
.filter((obj) => obj.name === POLYGON_TYPE.ROOF)
.filter((obj) => obj.name === POLYGON_TYPE.ROOF && !obj.isFixed)
.forEach((obj) => {
canvas.remove(...obj.innerLines)
canvas.remove(obj)
})*/
})
const polygon = addPolygonByLines(outerLines, { name: POLYGON_TYPE.WALL, direction })
polygon.lines = [...outerLines]

View File

@ -446,19 +446,24 @@ export function useContextMenu() {
])
break
case 'lineGrid':
case 'dotGrid':
case 'tempGrid':
setContextMenu([
[
{
id: 'gridMove',
name: getMessage('modal.grid.move'),
component: <GridMove id={popupId} />,
},
{
id: 'gridCopy',
name: getMessage('modal.grid.copy'),
component: <GridCopy id={popupId} />,
},
{
id: 'gridColorEdit',
name: getMessage('contextmenu.grid.color.edit'),
component: <ColorPickerModal id={popupId} color={gridColor} setColor={setGridColor} />,
},
{
id: 'remove',

View File

@ -284,7 +284,6 @@
"modal.panel.batch.statistic.total": "合計",
"modal.flow.direction.setting": "流れ方向の設定",
"modal.flow.direction.setting.info": "流れ方向を選択してください。",
"modal.image.size.setting": "画像のサイズ変更",
"modal.actual.size.setting": "実測値設定",
"modal.actual.size.setting.info": "※隅棟・谷・棟の実際の寸法を入力してください。",
"modal.actual.size.setting.not.exist.auxiliary.line": "실측치 입력할 보조선을 선택해 주세요(JA)",
@ -733,7 +732,7 @@
"stuff.detail.planGridHeader.pcTypeNo": "パワーコンディショナー",
"stuff.detail.planGridHeader.management": "管理",
"stuff.detail.planGrid.btn1": "見積書の照会",
"stuff.detail.planGrid.btn2": "Excel",
"stuff.detail.planGrid.docDownload": "文書のダウンロード",
"stuff.grid.noData": "照会されたデータがありません",
"length": "長さ",
"height": "高さ",
@ -844,6 +843,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": "添付必須",
@ -860,25 +860,26 @@
"estimate.detail.docPopup.title": "ドキュメントダウンロードオプションの設定",
"estimate.detail.docPopup.explane": "ダウンロードする文書のオプションを選択したら、 [文書のダウンロード]ボタンをクリックします.",
"estimate.detail.docPopup.schUnitPriceFlg": "ダウンロードファイル",
"estimate.detail.docPopup.schUnitPriceFlg.schUnitPriceFlg0": "見積もり Excel",
"estimate.detail.docPopup.schUnitPriceFlg.schUnitPriceFlg1": "定価用 Excel",
"estimate.detail.docPopup.schUnitPriceFlg.schUnitPriceFlg2": "見積もり PDF",
"estimate.detail.docPopup.schUnitPriceFlg.schUnitPriceFlg3": "定価用 PDF",
"estimate.detail.docPopup.schUnitPriceFlg.excelFlg0": "見積もり Excel",
"estimate.detail.docPopup.schUnitPriceFlg.excelFlg1": "定価用 Excel",
"estimate.detail.docPopup.schUnitPriceFlg.pdfFlg0": "見積もり PDF",
"estimate.detail.docPopup.schUnitPriceFlg.pdfFlg1": "定価用 PDF",
"estimate.detail.docPopup.schDisplayFlg": "見積提出先表示名",
"estimate.detail.docPopup.schDisplayFlg.schDisplayFlg0": "販売店名",
"estimate.detail.docPopup.schDisplayFlg.schDisplayFlg1": "案件名",
"estimate.detail.docPopup.schWeightFlg": "架台重量表を含む",
"estimate.detail.docPopup.schWeightFlg.schWeightFlg0": "含む",
"estimate.detail.docPopup.schWeightFlg.schWeightFlg1": "含まない",
"estimate.detail.docPopup.schWeightFlg.schWeightFlg1": "含む",
"estimate.detail.docPopup.schWeightFlg.schWeightFlg0": "含まない",
"estimate.detail.docPopup.schDrawingFlg": "図面/シミュレーションファイルを含む",
"estimate.detail.docPopup.schDrawingFlg.schDrawingFlg0": "含む",
"estimate.detail.docPopup.schDrawingFlg.schDrawingFlg1": "含まない",
"estimate.detail.docPopup.schDrawingFlg.schDrawingFlg1": "含む",
"estimate.detail.docPopup.schDrawingFlg.schDrawingFlg0": "含まない",
"estimate.detail.docPopup.close": "閉じる",
"estimate.detail.docPopup.docDownload": "文書のダウンロード",
"estimate.detail.productFeaturesPopup.title": "製品特異事項",
"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": "作成日",

View File

@ -289,7 +289,6 @@
"modal.panel.batch.statistic.total": "합계",
"modal.flow.direction.setting": "흐름 방향 설정",
"modal.flow.direction.setting.info": "흐름방향을 선택하세요.",
"modal.image.size.setting": "이미지 크기 조절",
"modal.actual.size.setting": "실측치 설정",
"modal.actual.size.setting.info": "※隅棟・谷・棟의 실제 치수를 입력해주세요.",
"modal.actual.size.setting.not.exist.auxiliary.line": "실측치 입력할 보조선을 선택해 주세요",
@ -743,7 +742,7 @@
"stuff.detail.planGridHeader.pcTypeNo": "파워컨디셔너",
"stuff.detail.planGridHeader.management": "관리",
"stuff.detail.planGrid.btn1": "견적서 조회",
"stuff.detail.planGrid.btn2": "Excel",
"stuff.detail.planGrid.docDownload": "문서 다운로드",
"stuff.grid.noData": "조회된 데이터가 없습니다",
"length": "길이",
"height": "높이",
@ -849,11 +848,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": "첨부필수",
@ -870,25 +870,26 @@
"estimate.detail.docPopup.title": "문서다운로드 옵션설정",
"estimate.detail.docPopup.explane": "다운로드할 문서 옵션을 선택한 후 문서 다운로드 버튼을 클릭합니다.",
"estimate.detail.docPopup.schUnitPriceFlg": "다운로드 파일",
"estimate.detail.docPopup.schUnitPriceFlg.schUnitPriceFlg0": "견적가 Excel",
"estimate.detail.docPopup.schUnitPriceFlg.schUnitPriceFlg1": "정가용 Excel",
"estimate.detail.docPopup.schUnitPriceFlg.schUnitPriceFlg2": "견적가 PDF",
"estimate.detail.docPopup.schUnitPriceFlg.schUnitPriceFlg3": "정가용 PDF",
"estimate.detail.docPopup.schUnitPriceFlg.excelFlg0": "견적가 Excel",
"estimate.detail.docPopup.schUnitPriceFlg.excelFlg1": "정가용 Excel",
"estimate.detail.docPopup.schUnitPriceFlg.pdfFlg0": "견적가 PDF",
"estimate.detail.docPopup.schUnitPriceFlg.pdfFlg1": "정가용 PDF",
"estimate.detail.docPopup.schDisplayFlg": "견적제출서 표시명",
"estimate.detail.docPopup.schDisplayFlg.schDisplayFlg0": "판매점명",
"estimate.detail.docPopup.schDisplayFlg.schDisplayFlg1": "안건명",
"estimate.detail.docPopup.schWeightFlg": "가대 중량표 포함",
"estimate.detail.docPopup.schWeightFlg.schWeightFlg0": "포함",
"estimate.detail.docPopup.schWeightFlg.schWeightFlg1": "미포함",
"estimate.detail.docPopup.schWeightFlg.schWeightFlg1": "포함",
"estimate.detail.docPopup.schWeightFlg.schWeightFlg0": "미포함",
"estimate.detail.docPopup.schDrawingFlg": "도면/시뮬레이션 파일 포함",
"estimate.detail.docPopup.schDrawingFlg.schDrawingFlg0": "포함",
"estimate.detail.docPopup.schDrawingFlg.schDrawingFlg1": "미포함",
"estimate.detail.docPopup.schDrawingFlg.schDrawingFlg1": "포함",
"estimate.detail.docPopup.schDrawingFlg.schDrawingFlg0": "미포함",
"estimate.detail.docPopup.close": "닫기",
"estimate.detail.docPopup.docDownload": "문서 다운로드",
"estimate.detail.productFeaturesPopup.title": "제품특이사항",
"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": "작성일",

File diff suppressed because it is too large Load Diff

View File

@ -1201,7 +1201,7 @@ export function removeDuplicatePolygons(polygons) {
}
export const isSamePoint = (a, b) => {
return Math.abs(Math.round(a.x) - Math.round(b.x)) <= 1 && Math.abs(Math.round(a.y) - Math.round(b.y)) <= 1
return Math.abs(Math.round(a.x) - Math.round(b.x)) <= 2 && Math.abs(Math.round(a.y) - Math.round(b.y)) <= 2
}
/**