Merge branch 'dev' into dev-yj

This commit is contained in:
yjnoh 2024-10-23 15:04:50 +09:00
commit c418da7560
16 changed files with 555 additions and 292 deletions

View File

@ -0,0 +1,5 @@
<svg width="15" height="16" viewBox="0 0 15 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="0.5" y="1" width="14" height="14" rx="7" fill="white"/>
<rect x="0.5" y="1" width="14" height="14" rx="7" stroke="#94A0AD"/>
<path d="M9.741 11.059L7.509 8.827L5.277 11.059L4.512 10.294L6.744 8.062L4.512 5.83L5.277 5.065L7.509 7.297L9.741 5.065L10.506 5.83L8.274 8.062L10.506 10.294L9.741 11.059Z" fill="#94A0AD"/>
</svg>

After

Width:  |  Height:  |  Size: 427 B

View File

@ -8,12 +8,12 @@ import Header from '@/components/header/Header'
import QModal from '@/components/common/modal/QModal'
import Dimmed from '@/components/ui/Dimmed'
import SessionProvider from './SessionProvider'
import LocaleSwitch from '@/components/LocaleSwitch'
import PopupManager from '@/components/common/popupManager/PopupManager'
import './globals.css'
import '../styles/style.scss'
import '../styles/contents.scss'
import Footer from '@/components/footer/Footer'
export const metadata = {
title: 'Create Next App',
@ -69,12 +69,7 @@ export default async function RootLayout({ children }) {
<SessionProvider useSession={sessionProps}>{children}</SessionProvider>
</QcastProvider>
</div>
<footer>
<div className="footer-inner flex justify-center">
<span>COPYRIGHT©2024 Hanwha Japan All Rights Reserved.</span>
<LocaleSwitch />
</div>
</footer>
<Footer />
</div>
)}
<QModal />

View File

@ -71,6 +71,10 @@ export default function Login() {
const { promisePost, promisePatch, post } = useAxios(globalLocaleState)
// focus state
const [idFocus, setIdFocus] = useState(false)
const [secFocus, setSecFocus] = useState(false)
// login process
const loginProcess = async (e) => {
e.preventDefault()
@ -191,7 +195,7 @@ export default function Login() {
{getMessage('site.sub_name')}
</div>
<div className="login-input-wrap">
<div className="login-area id">
<div className={`login-area id ${idFocus ? 'focus' : ''}`}>
<input
type="text"
className="login-input"
@ -203,6 +207,8 @@ export default function Login() {
onChange={(e) => {
setUserId(e.target.value)
}}
onFocus={() => setIdFocus(true)}
onBlur={() => setIdFocus(false)}
/>
<button
type="button"
@ -212,7 +218,7 @@ export default function Login() {
}}
></button>
</div>
<div className="login-area password">
<div className={`login-area password ${secFocus ? 'focus' : ''}`}>
<input
type={passwordVisible ? 'text' : 'password'}
className="login-input"
@ -224,6 +230,8 @@ export default function Login() {
onChange={(e) => {
setPasswordVisible(passwordVisible)
}}
onFocus={() => setSecFocus(true)}
onBlur={() => setSecFocus(false)}
/>
<button
className={`password-hidden ${passwordVisible ? 'visible' : ''}`}
@ -275,7 +283,7 @@ export default function Login() {
{getMessage('login.init_password.sub_title')}
</div>
<div className="login-input-wrap">
<div className="login-area id">
<div className={`login-area id ${idFocus ? 'focus' : ''}`}>
<input
type="text"
id="checkId"
@ -287,6 +295,8 @@ export default function Login() {
onChange={(e) => {
setCheckId(e.target.value)
}}
onFocus={() => setIdFocus(true)}
onBlur={() => setIdFocus(false)}
/>
<button
type="button"
@ -296,7 +306,7 @@ export default function Login() {
}}
></button>
</div>
<div className="login-area email">
<div className={`login-area email ${secFocus ? 'focus' : ''}`}>
<input
id="checkEmail"
name="checkEmail"
@ -308,6 +318,8 @@ export default function Login() {
setCheckEmail(e.target.value)
}}
placeholder={getMessage('login.init_password.email.placeholder')}
onFocus={() => setSecFocus(true)}
onBlur={() => setSecFocus(false)}
/>
<button
type="button"

View File

@ -118,8 +118,7 @@ export default function WallLineSetting(props) {
<div className={`modal-pop-wrap r mount`}>
<div className="modal-head">
<h1 className="title">{getMessage('modal.cover.outline.drawing')}</h1>
{/*<button className="modal-close" onClick={() => closePopup(id)}>*/}
<button className="modal-close">닫기</button>
<button className="modal-close" onClick={() => closePopup(id)}></button>
</div>
<div className="modal-body">
<div className="modal-btn-wrap">

View File

@ -0,0 +1,18 @@
'use client'
import LocaleSwitch from '@/components/LocaleSwitch'
import { usePathname } from 'next/navigation'
export default function Footer() {
return (
<>
{usePathname() !== '/floor-plan' && (
<footer>
<div className="footer-inner flex justify-center">
<span>COPYRIGHT©2024 Hanwha Japan All Rights Reserved.</span>
<LocaleSwitch />
</div>
</footer>
)}
</>
)
}

View File

@ -52,7 +52,7 @@ export default function StuffDetail() {
prefName: '',
address: '', //
areaId: '', //id
windSpeed: '', //
standardWindSpeedId: '', //
verticalSnowCover: '', //NEW
coldRegionFlg: false, //(true : 1 / false : 0)
surfaceType: 'III・IV', //(IIIIV / )
@ -147,7 +147,7 @@ export default function StuffDetail() {
useEffect(() => {
const code1 = findCommonCode(200800) //
const code2 = findCommonCode(201700) ///
const code3 = findCommonCode(113600) //
const code3 = findCommonCode(202000) // 202000
if (code1 != null) {
// console.log('::::::', code1)
setHonorificCodeList(code1)
@ -225,8 +225,8 @@ export default function StuffDetail() {
//
const onChangeHonorificCode = (key) => {
if (isObjectNotEmpty(key)) {
setSelHonorificCode(key.clCode)
form.setValue('objectNameOmit', key.clCode)
setSelHonorificCode(key.clCodeNm)
form.setValue('objectNameOmit', key.clCodeNm)
} else {
setSelHonorificCode('')
form.setValue('objectNameOmit', '')
@ -236,9 +236,9 @@ export default function StuffDetail() {
//
const onChangeWindSpeedCode = (key) => {
if (isObjectNotEmpty(key)) {
form.setValue('windSpeed', key.clCode)
form.setValue('standardWindSpeedId', key.clCode)
} else {
form.setValue('windSpeed', '')
form.setValue('standardWindSpeedId', '')
}
}
@ -388,7 +388,9 @@ export default function StuffDetail() {
form.setValue('prefName', info.address1)
}
})
form.setValue('windSpeed', info.windSpeed)
// WL_
form.setValue('standardWindSpeedId', `WL_${info.windSpeed}`)
form.setValue('verticalSnowCover', info.verticalSnowCover)
form.setValue('surfaceType', info.surfaceType)
form.setValue('installHeight', info.installHeight)
@ -407,9 +409,9 @@ export default function StuffDetail() {
}
}
//
//
const setWindSppedInfo = (info) => {
form.setValue('windSpeed', info.windSpeed)
form.setValue('standardWindSpeedId', info.windSpeed)
}
//dispCompanyName: '', //
@ -428,8 +430,8 @@ export default function StuffDetail() {
const _address = watch('address')
// areaId: '', //
const _areaId = watch('areaId')
// windSpeed: '', //
const _windSpeed = watch('windSpeed')
// standardWindSpeedId: '', //
const _standardWindSpeedId = watch('standardWindSpeedId')
// verticalSnowCover: '', //
const _verticalSnowCover = watch('verticalSnowCover')
// installHeight: '', //
@ -464,8 +466,8 @@ export default function StuffDetail() {
errors.areaId = true
}
if (!formData.windSpeed) {
errors.windSpeed = true
if (!formData.standardWindSpeedId) {
errors.standardWindSpeedId = true
}
if (!formData.verticalSnowCover) {
@ -506,8 +508,8 @@ export default function StuffDetail() {
errors.areaId = true
}
if (!formData.windSpeed) {
errors.windSpeed = true
if (!formData.standardWindSpeedId) {
errors.standardWindSpeedId = true
}
if (!formData.verticalSnowCover) {
@ -530,7 +532,7 @@ export default function StuffDetail() {
_prefId,
_address,
_areaId,
_windSpeed,
_standardWindSpeedId,
_verticalSnowCover,
_installHeight,
])
@ -575,7 +577,7 @@ export default function StuffDetail() {
//
const onValid = async () => {
const formData = form.getValues()
console.log('필수값 통과:::', formData)
// console.log(' :::', formData)
const apiUrl = '/api/object/save-object'
const params = {
saleStoreId: formData.otherSaleStoreId ? formData.otherSaleStoreId : formData.saleStoreId,
@ -592,7 +594,7 @@ export default function StuffDetail() {
areaId: formData.areaId,
receiveUser: formData.dispCompanyName,
installHeight: formData.installHeight,
windSpeed: formData.windSpeed,
standardWindSpeedId: formData.standardWindSpeedId,
verticalSnowCover: formData.verticalSnowCover,
surfaceType: formData.surfaceType,
conType: formData.conType,
@ -602,7 +604,7 @@ export default function StuffDetail() {
workNo: null,
workName: null,
}
console.log('params::', params)
// console.log('params::', params)
alert('작업중')
return
if (editMode === 'NEW') {
@ -646,7 +648,7 @@ export default function StuffDetail() {
areaId: formData.areaId,
receiveUser: formData.dispCompanyName,
installHeight: formData.installHeight,
windSpeed: formData.windSpeed,
standardWindSpeedId: formData.standardWindSpeedId,
verticalSnowCover: formData.verticalSnowCover,
surfaceType: formData.surfaceType,
conType: formData.conType,
@ -662,6 +664,7 @@ export default function StuffDetail() {
params.saleStoreId = sessionState.storeId
params.saleStoreLevel = sessionState.storeLvl
}
console.log('임시저장파람:::', params)
alert('작업중')
return
await promisePost({ url: '/api/object/save-object', data: params }).then((res) => {
@ -674,19 +677,27 @@ export default function StuffDetail() {
//
const onDelete = () => {
//http://localhost:8080/api/object/R201TES01240910023
// console.log('::::::::', objectNo)
alert('사양확정일이 있으면 삭제 불가')
if (confirm(getMessage('common.message.data.delete'))) {
let testobj = '10'
del({ url: `/api/object/${testobj}` }).then((res) => {
console.log('삭제 결과:::', res)
router.push('/management/stuff')
})
// console.log('detailData:::::::::', detailData)
const specificationConfirmDate = detailData.specificationConfirmDate
if (specificationConfirmDate != null) {
alert(getMessage('stuff.detail.delete.message1'))
} else {
if (confirm(getMessage('common.message.data.delete'))) {
del({ url: `/api/object/${objectNo}` }).then((res) => {
console.log('삭제결과:::::::', res)
router.push('/management/stuff')
})
}
}
}
//
const handleKeyUp = (e) => {
let input = e.target
input.value = input.value.replace(/[^0-9]/g, '')
}
return (
<>
{(editMode === 'NEW' && (
@ -707,8 +718,18 @@ export default function StuffDetail() {
<th>{getMessage('stuff.detail.planReqNo')}</th>
<td>
<div className="flx-box">
<div className="input-wrap mr5" style={{ width: '200px' }}>
<input type="text" className="input-light" readOnly value={form.watch('planReqNo')} />
<div className="product-input-wrap mr5">
<input type="text" className="product-input" readOnly value={form.watch('planReqNo') || ''} />
{(form.watch('planReqNo') !== '' && (
<button
type="button"
className="product-delete"
onClick={() => {
form.setValue('planReqNo', '')
}}
></button>
)) ||
null}
</div>
<Button className="btn-origin grey" onClick={onSearchDesignRequestPopOpen}>
{getMessage('stuff.planReqPopup.title')}
@ -768,7 +789,7 @@ export default function StuffDetail() {
isClearable={true}
isSearchable={false}
value={honorificCodeList.filter(function (option) {
return option.clCode === selHonorificCode
return option.clCodeNm === selHonorificCode
})}
></Select>
</div>
@ -815,7 +836,13 @@ export default function StuffDetail() {
/>
</div>
<div className="input-wrap" style={{ width: '216px' }}>
<input type="text" className="input-light" value={form.watch('saleStoreId')} {...form.register('saleStoreId')} readOnly />
<input
type="text"
className="input-light"
value={form.watch('saleStoreId') || ''}
{...form.register('saleStoreId')}
readOnly
/>
</div>
</div>
</td>
@ -869,7 +896,7 @@ export default function StuffDetail() {
<td>
<div className="flx-box">
<div className="input-wrap mr5" style={{ width: '200px' }}>
<input type="text" className="input-light" disabled value={form.watch('zipNo')} />
<input type="text" className="input-light" disabled value={form.watch('zipNo') || ''} />
</div>
<Button className="btn-origin grey" onClick={onSearchPostNumberPopOpen}>
{getMessage('stuff.detail.btn.addressPop')}
@ -905,7 +932,7 @@ export default function StuffDetail() {
)}
</div>
<div className="input-wrap mr5" style={{ width: '580px' }}>
<input type="text" className="input-light" value={form.watch('address')} {...form.register('address')} />
<input type="text" className="input-light" value={form.watch('address') || ''} {...form.register('address')} />
</div>
</div>
</td>
@ -944,7 +971,7 @@ export default function StuffDetail() {
{/* 기준풍속sel시작 */}
<div className="select-wrap mr10" style={{ width: '200px' }}>
<Select
{...register('windSpeed')}
{...register('standardWindSpeedId')}
id="long-value-select5"
instanceId="long-value-select5"
className="react-select-custom"
@ -957,7 +984,7 @@ export default function StuffDetail() {
isClearable={true}
isSearchable={false}
value={windSpeedList.filter(function (option) {
return option.clCode === watch('windSpeed')
return option.clCode === watch('standardWindSpeedId')
})}
></Select>
</div>
@ -976,7 +1003,13 @@ export default function StuffDetail() {
<td>
<div className="flx-box">
<div className="input-wrap mr10" style={{ width: '200px' }}>
<input type="text" className="input-light" value={form.watch('verticalSnowCover')} {...register('verticalSnowCover')} />
<input
type="text"
className="input-light"
onKeyUp={handleKeyUp}
value={form.watch('verticalSnowCover')}
{...register('verticalSnowCover')}
/>
</div>
<span className="mr10">cm</span>
<div className="d-check-box light">
@ -1015,7 +1048,13 @@ export default function StuffDetail() {
<td>
<div className="flx-box">
<div className="input-wrap mr10" style={{ width: '200px' }}>
<input type="text" className="input-light" value={form.watch('installHeight')} {...register('installHeight')} />
<input
type="text"
className="input-light"
onKeyUp={handleKeyUp}
value={form.watch('installHeight')}
{...register('installHeight')}
/>
</div>
<span>m</span>
</div>
@ -1047,19 +1086,19 @@ export default function StuffDetail() {
</tbody>
</table>
</div>
<div className="sub-table-footer">
<div className="sub-right-footer">
{!isFormValid ? (
<Button className="btn-origin grey mr5" onClick={onTempSave}>
New화면 임시저장
New화면 {getMessage('stuff.detail.btn.tempSave')}
</Button>
) : (
<Button type="submit" className="btn-origin navy mr5">
NEW화면 저장
NEW화면 {getMessage('stuff.detail.btn.save')}
</Button>
)}
<Link href="/management/stuff" scroll={false}>
<button type="button" className="btn-origin grey">
NEW화면 물건목록이동
NEW화면 {getMessage('stuff.detail.btn.moveList')}
</button>
</Link>
</div>
@ -1072,229 +1111,303 @@ export default function StuffDetail() {
<div className="promise-gudie">
<span className="important">*</span> {getMessage('stuff.detail.required')}
</div>
<div className="infomation-table">
<table>
<colgroup>
<col style={{ width: '200px' }} />
<col />
</colgroup>
<tbody>
<tr>
<th>{getMessage('stuff.detail.planReqNo')}</th>
<td>
<div className="flx-box">
<div className="input-wrap mr5" style={{ width: '200px' }}>
<input type="text" className="input-light" readOnly value={form.watch('planReqNo')} />
<div className="infomation-wrap">
<div className="infomation-table">
<table>
<colgroup>
<col style={{ width: '200px' }} />
<col />
</colgroup>
<tbody>
<tr>
<th>{getMessage('stuff.detail.planReqNo')}</th>
<td>
<div className="flx-box">
<div className="product-input-wrap mr5">
<input type="text" className="product-input" readOnly value={form.watch('planReqNo') || ''} />
{objectNo.substring(0, 1) === 'T' && form.watch('planReqNo') !== '' ? (
<button
type="button"
className="product-delete"
onClick={() => {
form.setValue('planReqNo', '')
}}
></button>
) : null}
</div>
{objectNo.substring(0, 1) === 'T' ? (
<>
<Button className="btn-origin grey" onClick={onSearchDesignRequestPopOpen}>
{getMessage('stuff.planReqPopup.title')}
</Button>
</>
) : null}
</div>
{objectNo.substring(0, 1) === 'T' ? (
<>
<Button className="btn-origin grey" onClick={onSearchDesignRequestPopOpen}>
{getMessage('stuff.planReqPopup.title')}
</Button>
</>
) : null}
</div>
</td>
</tr>
<tr>
<th>
{getMessage('stuff.detail.dispCompanyName')} <span className="important">*</span>
</th>
<td>
<div className="input-wrap" style={{ width: '500px' }}>
<input type="text" className="input-light" {...form.register('dispCompanyName')} value={form.watch('dispCompanyName')} />
</div>
</td>
</tr>
<tr>
<th>
{getMessage('stuff.detail.objectStatusId')} <span className="importatn">*</span>
</th>
<td>
<div className="flx-box">
{/* 상세라디오시작 */}
{objectStatusList.map((row) => {
return (
<div className="d-check-radio light mr10" key={`objectStatusId_${row.clCode}`}>
<input
type="radio"
name="objectStatusId"
value={row.clCode}
id={`objectStatus${row.clCode}`}
{...register('objectStatusId')}
onChange={onRadioChange}
checked={row.clCode === selectObjectStatusId}
/>
<label htmlFor={`objectStatus${row.clCode}`}>{row.clCodeNm}</label>
</div>
)
})}
{/* 상세라디오끝 */}
<div className="input-wrap mr5" style={{ width: '545px' }}>
<input type="text" className="input-light" {...form.register('objectName')} />
</div>
<div className="select-wrap" style={{ width: '120px' }}>
<Select
{...register('objectNameOmit')}
id="long-value-select0"
instanceId="long-value-select0"
className="react-select-custom"
classNamePrefix="custom"
placeholder="Select"
options={honorificCodeList}
onChange={onChangeHonorificCode}
getOptionLabel={(x) => x.clCodeNm}
getOptionValue={(x) => x.clCode}
isClearable={true}
isSearchable={false}
value={honorificCodeList.filter(function (option) {
console.log('상세 경칭코드결과:::::::::::::::', option.clCode)
console.log('상세 셋팅된 경칭코드값:::::::::::::::', selHonorificCode)
return option.clCode === selHonorificCode
})}
></Select>
</div>
</div>
</td>
</tr>
<tr>
<th>{getMessage('stuff.detail.objectNameKana')}</th>
<td>
<div className="input-wrap" style={{ width: '789px' }}>
<input type="text" className="input-light" {...form.register('objectNameKana')} />
</div>
</td>
</tr>
<tr>
<th>
<div className="flx-box">
<div className="title">
{getMessage('stuff.detail.saleStoreId')}
<span className="important">*</span>
</div>
<div className="tooltips"></div>
</div>
</th>
<td>
<div className="flx-box">
<div className="select-wrap mr5" style={{ width: '567px' }}>
<Select
id="long-value-select1"
instanceId="long-value-select1"
className="react-select-custom"
classNamePrefix="custom"
placeholder="Select"
options={saleStoreList}
onChange={onSelectionChange}
getOptionLabel={(x) => x.saleStoreName}
getOptionValue={(x) => x.saleStoreId}
isClearable={sessionState?.storeLvl === '1' ? true : false}
value={saleStoreList.filter(function (option) {
return option.saleStoreId === selOptions
})}
/>
</div>
<div className="input-wrap" style={{ width: '216px' }}>
<input type="text" className="input-light" value={form.watch('saleStoreId')} {...form.register('saleStoreId')} readOnly />
</div>
</div>
</td>
</tr>
<tr>
<th>
<div className="flx-box">
<div className="title">{getMessage('stuff.detail.otherSaleStoreId')}</div>
<div className="tooltips">
<span>{getMessage('stuff.detail.tooltip.saleStoreId')}</span>
</div>
</div>
</th>
<td>
<div className="flx-box">
<div className="select-wrap mr5" style={{ width: '567px' }}>
<Select
id="long-value-select2"
instanceId="long-value-select2"
className="react-select-custom"
classNamePrefix="custom"
placeholder="Select"
ref={ref}
options={otherSaleStoreList}
onChange={onSelectionChange2}
getOptionLabel={(x) => x.saleStoreName}
getOptionValue={(x) => x.saleStoreId}
isDisabled={sessionState?.storeLvl === '1' && form.watch('saleStoreId') != '' ? false : true}
isClearable={sessionState?.storeLvl === '1' ? true : false}
value={otherSaleStoreList.filter(function (option) {
return option.saleStoreId === otherSelOptions
})}
/>
</div>
<div className="input-wrap" style={{ width: '216px' }}>
</td>
</tr>
<tr>
<th>
{getMessage('stuff.detail.dispCompanyName')} <span className="important">*</span>
</th>
<td>
<div className="input-wrap" style={{ width: '500px' }}>
<input
type="text"
className="input-light"
value={form.watch('otherSaleStoreId')}
{...form.register('otherSaleStoreId')}
readOnly
{...form.register('dispCompanyName')}
value={form.watch('dispCompanyName') || ''}
/>
</div>
</div>
</td>
</tr>
<tr>
<th>
{getMessage('stuff.detail.zipNo')} <span className="important">*</span>
</th>
<td>
<div className="flx-box">
<div className="input-wrap mr5" style={{ width: '200px' }}>
<input type="text" className="input-light" disabled value={form.watch('zipNo')} />
</td>
</tr>
<tr>
<th>
{getMessage('stuff.detail.objectStatusId')} <span className="importatn">*</span>
</th>
<td>
<div className="flx-box">
{/* 상세라디오시작 */}
{objectStatusList.map((row) => {
return (
<div className="d-check-radio light mr10" key={`objectStatusId_${row.clCode}`}>
<input
type="radio"
name="objectStatusId"
value={row.clCode}
id={`objectStatus${row.clCode}`}
{...register('objectStatusId')}
onChange={onRadioChange}
checked={row.clCode === selectObjectStatusId}
/>
<label htmlFor={`objectStatus${row.clCode}`}>{row.clCodeNm}</label>
</div>
)
})}
{/* 상세라디오끝 */}
<div className="input-wrap mr5" style={{ width: '545px' }}>
<input type="text" className="input-light" {...form.register('objectName')} />
</div>
<div className="select-wrap" style={{ width: '120px' }}>
<Select
{...register('objectNameOmit')}
id="long-value-select0"
instanceId="long-value-select0"
className="react-select-custom"
classNamePrefix="custom"
placeholder="Select"
options={honorificCodeList}
onChange={onChangeHonorificCode}
getOptionLabel={(x) => x.clCodeNm}
getOptionValue={(x) => x.clCode}
isClearable={true}
isSearchable={false}
value={honorificCodeList.filter(function (option) {
return option.clCodeNm === selHonorificCode
})}
></Select>
</div>
</div>
<Button className="btn-origin grey" onClick={onSearchPostNumberPopOpen}>
{getMessage('stuff.detail.btn.addressPop')}
</Button>
<div className="guide">{getMessage('stuff.detail.btn.addressPop.guide')}</div>
</div>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
<tr>
<th>{getMessage('stuff.detail.objectNameKana')}</th>
<td>
<div className="input-wrap" style={{ width: '789px' }}>
<input type="text" className="input-light" {...form.register('objectNameKana')} />
</div>
</td>
</tr>
<tr>
<th>
<div className="flx-box">
<div className="title">
{getMessage('stuff.detail.saleStoreId')}
<span className="important">*</span>
</div>
<div className="tooltips"></div>
</div>
</th>
<td>
<div className="flx-box">
<div className="select-wrap mr5" style={{ width: '567px' }}>
<Select
id="long-value-select1"
instanceId="long-value-select1"
className="react-select-custom"
classNamePrefix="custom"
placeholder="Select"
options={saleStoreList}
onChange={onSelectionChange}
getOptionLabel={(x) => x.saleStoreName}
getOptionValue={(x) => x.saleStoreId}
isClearable={sessionState?.storeLvl === '1' ? true : false}
value={saleStoreList.filter(function (option) {
return option.saleStoreId === selOptions
})}
/>
</div>
<div className="input-wrap" style={{ width: '216px' }}>
<input
type="text"
className="input-light"
value={form.watch('saleStoreId')}
{...form.register('saleStoreId')}
readOnly
/>
</div>
</div>
</td>
</tr>
<tr>
<th>
<div className="flx-box">
<div className="title">{getMessage('stuff.detail.otherSaleStoreId')}</div>
<div className="tooltips">
<span>{getMessage('stuff.detail.tooltip.saleStoreId')}</span>
</div>
</div>
</th>
<td>
<div className="flx-box">
<div className="select-wrap mr5" style={{ width: '567px' }}>
<Select
id="long-value-select2"
instanceId="long-value-select2"
className="react-select-custom"
classNamePrefix="custom"
placeholder="Select"
ref={ref}
options={otherSaleStoreList}
onChange={onSelectionChange2}
getOptionLabel={(x) => x.saleStoreName}
getOptionValue={(x) => x.saleStoreId}
isDisabled={sessionState?.storeLvl === '1' && form.watch('saleStoreId') != '' ? false : true}
isClearable={sessionState?.storeLvl === '1' ? true : false}
value={otherSaleStoreList.filter(function (option) {
return option.saleStoreId === otherSelOptions
})}
/>
</div>
<div className="input-wrap" style={{ width: '216px' }}>
<input
type="text"
className="input-light"
value={form.watch('otherSaleStoreId')}
{...form.register('otherSaleStoreId')}
readOnly
/>
</div>
</div>
</td>
</tr>
<tr>
<th>
{getMessage('stuff.detail.zipNo')} <span className="important">*</span>
</th>
<td>
<div className="flx-box">
<div className="input-wrap mr5" style={{ width: '200px' }}>
<input type="text" className="input-light" disabled value={form.watch('zipNo') || ''} />
</div>
<Button className="btn-origin grey" onClick={onSearchPostNumberPopOpen}>
{getMessage('stuff.detail.btn.addressPop')}
</Button>
<div className="guide">{getMessage('stuff.detail.btn.addressPop.guide')}</div>
</div>
</td>
</tr>
{/* 도도부현 /주소 시작*/}
{/* 도도부현 /주소 끝 */}
{/* 발전량시뮬레이션지역시작 */}
{/* 발전량시뮬레이션지역끝 */}
{/* 기준풍속시작 */}
{/* 기준풍속끝 */}
{/* 수직적설량시작 */}
{/* 수직적설량끝 */}
{/* 면조도구분시작 */}
{/* 면조도구분끝 */}
{/* 설치높이싲가 */}
{/* 설치높이끝 */}
{/* 계약조건시작 */}
{/* 계약조건끝 */}
{/* 메모시작 */}
{/* 메모끝 */}
<tr>
<th></th>
</tr>
</tbody>
</table>
</div>
</div>
{objectNo.substring(0, 1) === 'R' ? (
<>
{/* 진짜R 플랜시작 */}
<div className="table-box-title-wrap">
<div className="title-wrap">
<h3>{getMessage('stuff.detail.planList.title')}</h3>
<ul className="info-wrap">
<li>
{getMessage('stuff.detail.planList.cnt')}
<span className="red">플랜갯수찍어주기</span>
</li>
</ul>
</div>
</div>
<div className="information-help-wrap">
<div className="information-help-tit-wrap">
<div className="help-tit-icon"></div>
<div className="help-tit">{getMessage('stuff.detail.planList.help')}</div>
</div>
<div className="information-help-guide">
<span>{getMessage('stuff.detail.planList.guide1')}</span>
<span>{getMessage('stuff.detail.planList.guide2')}</span>
<span>{getMessage('stuff.detail.planList.guide3')}</span>
</div>
</div>
<div className="information-grid">
<div className="q-grid no-cols">
그리드영역
<div className="pagination-wrap">페이징영역</div>
</div>
</div>
{/* 진짜R 플랜끝 */}
<div className="sub-right-footer">
<Link href="/management/stuff">
<button type="button" className="btn-origin grey mr5">
R상세: {getMessage('stuff.detail.btn.moveList')}
</button>
</Link>
<Button type="submit" className="btn-origin navy mr5">
R상세:{getMessage('stuff.detail.btn.save')}
</Button>
<Button type="button" className="btn-origin grey" onClick={onDelete}>
{getMessage('stuff.detail.btn.delete')}
</Button>
</div>
</>
) : (
<>
<div className="sub-right-footer">
{!isFormValid ? (
<Button type="submit" className="btn-origin grey mr5" onClick={onTempSave}>
TEMP상세:{getMessage('stuff.detail.btn.tempSave')}
</Button>
) : (
<Button type="submit" className="btn-origin navy mr5">
TEMP상세:{getMessage('stuff.detail.btn.save')}
</Button>
)}
<Link href="/management/stuff">
<button type="button" className="btn-origin grey">
TEMP상세:{getMessage('stuff.detail.btn.moveList')}
</button>
</Link>
</div>
</>
)}
</div>
</form>
{objectNo.substring(0, 1) === 'R' ? (
<>
<Link href="/management/stuff">
<button type="button" className="btn-origin grey mr5">
R상세:물건목록
</button>
</Link>
<Button type="submit" className="btn-origin navy mr5">
R상세:저장
</Button>
<Button type="submit" className="btn-origin navy" onClick={onDelete}>
R상세:물건삭제
</Button>
</>
) : (
<>
{!isFormValid ? (
<Button type="submit" className="btn-origin navy mr5" onClick={onTempSave}>
TEMP상세:임시저장
</Button>
) : (
<Button type="submit" className="btn-origin navy mr5">
TEMP상세:저장
</Button>
)}
<Link href="/management/stuff">
<button type="button" className="btn-origin grey">
T상세:물건목록
</button>
</Link>
</>
)}
</>
)}
{showAddressButtonValid && <FindAddressPop setShowAddressButtonValid={setShowAddressButtonValid} zipInfo={setZipInfo} />}

View File

@ -5,7 +5,10 @@ import { useAxios } from '@/hooks/useAxios'
import { useRouter, useSearchParams } from 'next/navigation'
import { globalLocaleStore } from '@/store/localeAtom'
import { useRecoilValue } from 'recoil'
import { useMessage } from '@/hooks/useMessage'
export default function StuffHeader() {
const { getMessage } = useMessage()
const router = useRouter()
const searchParams = useSearchParams()
const objectNo = searchParams.get('objectNo') //url set
@ -15,35 +18,49 @@ export default function StuffHeader() {
useEffect(() => {
get({ url: `/api/object/${objectNo}/detail` }).then((res) => {
//console.log('res::', res)
if (res != null && res != '') {
console.log('헤더상세::::::::::', res)
setHeaderData(res)
} else {
alert('삭제된 물건입니다')
alert(getMessage('stuff.detail.header.message1'))
router.push('/management/stuff')
}
})
}, [objectNo])
//
const copyObjectNo = async (objectNo) => {
await navigator.clipboard.writeText(objectNo)
alert(getMessage('stuff.detail.header.message2'))
try {
} catch (error) {
alert(getMessage('stuff.detail.header.message3'))
}
}
return (
<div className="infomation-box-wrap">
<div className="sub-table-box">
<div className="info-title">물건번호</div>
<div className="info-title">{getMessage('stuff.detail.header.objectNo')}</div>
<div className="info-inner">
{headerData.objectNo} <button className="copy-ico"></button>
{headerData.objectNo}{' '}
<button
className="copy-ico"
onClick={() => {
copyObjectNo(headerData.objectNo)
}}
></button>
</div>
</div>
<div className="sub-table-box">
<div className="info-title">사양확정일</div>
<div className="info-title">{getMessage('stuff.detail.header.specificationConfirmDate')}</div>
<div className="info-inner">{headerData.specificationConfirmDate}</div>
</div>
<div className="sub-table-box">
<div className="info-title">갱신일시</div>
<div className="info-title">{getMessage('stuff.detail.header.lastEditDatetime')}</div>
<div className="info-inner">{headerData.lastEditDatetime}</div>
</div>
<div className="sub-table-box">
<div className="info-title">등록일</div>
<div className="info-title">{getMessage('stuff.detail.header.createDatetime')}</div>
<div className="info-inner">{headerData.createDatetime}</div>
</div>
</div>

View File

@ -81,16 +81,21 @@ export default function WindSelectPop(props) {
</thead>
<tbody>
{windSpeedList.map((row, index) => {
// console.log('row:::', row)
return (
<tr key={index}>
<td className="al-c">
<div className="d-check-radio light no-text">
<input type="radio" value={row.windSpeed} name="windS" id={row.windSpeed} onChange={handleChangeRadio} />
<label htmlFor={row.windSpeed}></label>
<input
type="radio"
value={row.standardWindSpeedId}
name="windS"
id={row.standardWindSpeedId}
onChange={handleChangeRadio}
/>
<label htmlFor={row.standardWindSpeedId}></label>
</div>
</td>
<td className="al-c">{row.windSpeed}</td>
<td className="al-c">{row.standardWindSpeedId.slice(3)}</td>
<td>{row.remarks}</td>
</tr>
)

View File

@ -1,6 +1,6 @@
import { useEffect, useRef, useState } from 'react'
import { useRecoilState, useRecoilValue } from 'recoil'
import { adsorptionRangeState, canvasState } from '@/store/canvasAtom'
import { adsorptionRangeState, canvasState, verticalHorizontalModeState } from '@/store/canvasAtom'
import { useEvent } from '@/hooks/useEvent'
import { useMouse } from '@/hooks/useMouse'
import { useLine } from '@/hooks/useLine'
@ -21,6 +21,7 @@ import { useAdsorptionPoint } from '@/hooks/useAdsorptionPoint'
import { useSwal } from '@/hooks/useSwal'
import { booleanPointInPolygon } from '@turf/turf'
import { usePopup } from '@/hooks/usePopup'
import { calculateAngle } from '@/util/qpolygon-utils'
// 보조선 작성
export function useAuxiliaryDrawing(id) {
@ -60,6 +61,7 @@ export function useAuxiliaryDrawing(id) {
const outerLineDiagonalLengthRef = useRef(0)
const intersectionPoints = useRef([])
const verticalHorizontalMode = useRecoilValue(verticalHorizontalModeState)
useEffect(() => {
arrow1Ref.current = arrow1
@ -100,6 +102,10 @@ export function useAuxiliaryDrawing(id) {
}
}, [])
useEffect(() => {
addCanvasMouseEventListener('mouse:down', mouseDown)
}, [verticalHorizontalMode])
const clear = () => {
addCanvasMouseEventListener('mouse:move', mouseMove)
setLength1(0)
@ -453,12 +459,26 @@ export function useAuxiliaryDrawing(id) {
const mouseDown = (e) => {
canvas.renderAll()
const pointer = getIntersectMousePoint(e)
console.log(pointer)
let pointer = getIntersectMousePoint(e)
mousePointerArr.current.push(pointer)
if (mousePointerArr.current.length === 2) {
drawLine(mousePointerArr.current[0], mousePointerArr.current[1])
if (mousePointerArr.current.length === 1) {
const currentPoint = canvas.getPointer(e.e)
const prevPoint = mousePointerArr.current[0]
const degreeByTwoPoints = calculateAngle(prevPoint, currentPoint)
const degree = Math.round(degreeByTwoPoints / 45) * 45
if (verticalHorizontalMode) {
pointer = {
x: prevPoint.x + distanceBetweenPoints(currentPoint, prevPoint) * Math.cos((degree * Math.PI) / 180),
y: prevPoint.y + distanceBetweenPoints(currentPoint, prevPoint) * Math.sin((degree * Math.PI) / 180),
}
}
mousePointerArr.current.push(pointer)
drawLine()
} else {
const circle = new fabric.Circle({
radius: 3,
@ -472,6 +492,7 @@ export function useAuxiliaryDrawing(id) {
})
canvas.add(circle)
canvas.renderAll()
mousePointerArr.current.push(pointer)
}
}

View File

@ -1,6 +1,6 @@
import { useRecoilValue } from 'recoil'
import { canvasState } from '@/store/canvasAtom'
import { calculateIntersection } from '@/util/canvas-util'
import { calculateIntersection, getInterSectionLineNotOverCoordinate } from '@/util/canvas-util'
export function useMouse() {
const canvas = useRecoilValue(canvasState)
@ -14,7 +14,7 @@ export function useMouse() {
return pointer
}
return calculateIntersection(mouseLines[0], mouseLines[1]) || pointer
return getInterSectionLineNotOverCoordinate(mouseLines[0], mouseLines[1]) || pointer
}
return {

View File

@ -401,7 +401,7 @@ export const usePolygon = () => {
const addTextByArrows = (arrows, txt, canvas) => {
arrows.forEach((arrow, index) => {
const text = new fabric.Text(`${txt}${index + 1} (${arrow.pitch}寸)`, {
fontSize: arrow.parent.fontSize,
fontSize: fontSize,
fill: 'black',
originX: 'center',
originY: 'center',

View File

@ -468,6 +468,13 @@
"stuff.addressPopup.btn2": "住所適用",
"stuff.planReqPopup.title": "設計依頼のインポート",
"stuff.temp.subTitle": "商品情報",
"stuff.detail.header.message1": "存在しないものです。",
"stuff.detail.header.message2": "商品番号がコピーされました。",
"stuff.detail.header.message3": "存在しないものです。",
"stuff.detail.header.objectNo": "商品番号のコピーに失敗しました。",
"stuff.detail.header.specificationConfirmDate": "仕様拡張日",
"stuff.detail.header.lastEditDatetime": "更新日時",
"stuff.detail.header.createDatetime": "登録日",
"stuff.detail.required": "必須入力項目",
"stuff.detail.planReqNo": "設計依頼No.",
"stuff.detail.dispCompanyName": "担当者",
@ -497,6 +504,17 @@
"stuff.detail.tooltip.saleStoreId": "販売代理店または販売代理店IDを1文字以上入力してください",
"stuff.detail.tempSave.message1": "一時保存されました。商品番号を取得するには、必須項目をすべて入力してください。",
"stuff.detail.confirm.message1": "販売店情報を変更すると、設計依頼文書番号が削除されます。変更しますか?",
"stuff.detail.delete.message1": "仕様が確定したものは削除できません。",
"stuff.detail.planList.title": "プランリスト",
"stuff.detail.planList.cnt": "全体",
"stuff.detail.planList.help": "ヘルプ",
"stuff.detail.planList.guide1": "1.発注は同一品番基準1件のみ可能です。",
"stuff.detail.planList.guide2": "2.[Excelダウンロード]は見積書、図面、シミュレーション結果をExcelファイルで一度にダウンロードします。",
"stuff.detail.planList.guide3": "3. プラン情報をダブルクリックすると図面作成画面に移動します。",
"stuff.detail.btn.delete": "物の削除",
"stuff.detail.btn.moveList": "商品リスト",
"stuff.detail.btn.save": "保存",
"stuff.detail.btn.tempSave": "一時保存",
"stuff.planReqPopup.popTitle": "設計依頼検索",
"stuff.planReqPopup.btn1": "検索",
"stuff.planReqPopup.btn2": "初期化",

View File

@ -473,6 +473,13 @@
"stuff.addressPopup.btn2": "주소적용",
"stuff.planReqPopup.title": "설계의뢰 불러오기",
"stuff.temp.subTitle": "물건정보",
"stuff.detail.header.message1": "존재하지 않는 물건입니다.",
"stuff.detail.header.message2": "물건번호가 복사되었습니다.",
"stuff.detail.header.message3": "물건번호 복사에 실패했습니다.",
"stuff.detail.header.objectNo": "물건번호",
"stuff.detail.header.specificationConfirmDate": "사양확장일",
"stuff.detail.header.lastEditDatetime": "갱신일시",
"stuff.detail.header.createDatetime": "등록일",
"stuff.detail.required": "필수 입력항목",
"stuff.detail.planReqNo": "설계의뢰No.",
"stuff.detail.dispCompanyName": "담당자",
@ -502,6 +509,17 @@
"stuff.detail.tooltip.saleStoreId": "판매대리점 또는 판매대리점ID를 1자 이상 입력하세요",
"stuff.detail.tempSave.message1": "임시저장 되었습니다. 물건번호를 획득하려면 필수 항목을 모두 입력해 주십시오.",
"stuff.detail.confirm.message1": "판매점 정보를 변경하면, 설계의뢰 문서번호가 삭제됩니다. 변경하시겠습니까?",
"stuff.detail.delete.message1": "사양이 확정된 물건은 삭제할 수 없습니다.",
"stuff.detail.planList.title": "플랜리스트",
"stuff.detail.planList.cnt": "전체",
"stuff.detail.planList.help": "도움말",
"stuff.detail.planList.guide1": "1.발주는 동일 물건번호 기준 1건만 가능합니다.",
"stuff.detail.planList.guide2": "2.[Excel 다운로드]는 견적서, 도면, 시뮬레이션 결과를 엑셀파일로 한번에 다운로드 합니다.",
"stuff.detail.planList.guide3": "3.플랜정보를 더블 클릭하면 도면작성 화면으로 이동합니다.",
"stuff.detail.btn.delete": "물건삭제",
"stuff.detail.btn.moveList": "물건목록",
"stuff.detail.btn.save": "저장",
"stuff.detail.btn.tempSave": "임시저장",
"stuff.planReqPopup.popTitle": "설계 요청 검색",
"stuff.planReqPopup.btn1": "검색",
"stuff.planReqPopup.btn2": "초기화",

View File

@ -1200,7 +1200,6 @@
border: 1px solid #E5E5E5;
background: #FFF;
transition: all .15s ease-in-out;
cursor: pointer;
.file-item-info{
.item-num{
display: inline-block;
@ -1255,4 +1254,32 @@
font-size: 16px;
font-weight: 500;
color: #344356;
}
//신규물건 등록
.product-input-wrap{
display: flex;
align-items: center;
width: 200px;
height: 30px;
background-color: #FAFAFA;
border: 1px solid #EEE;
padding: 0 10px;
input{
font-size: 13px;
font-weight: 400;
color: #999999;
padding: 0;
height: 100%;
flex: 1 ;
background-color: inherit;
}
.product-delete{
flex: none;
display: block;
width: 15px;
height: 100%;
background: url(../../public/static/images/sub/product-del.svg)no-repeat center;
background-size: 15px 15px;
}
}

View File

@ -460,6 +460,7 @@ input[type=text]{
line-height: 30px;
border-radius: 2px;
background-color: #323234;
border: 1px solid #323234;
color: #fff;
font-size: 12px;
font-weight: 500;
@ -467,6 +468,10 @@ input[type=text]{
padding: 0 10px;
letter-spacing: 0px;
text-align: right;
transition: border .15s ease-in-out;
&:focus{
border: 1px solid #1083E3;
}
&::placeholder{
opacity: 1;
font-size: 12px;
@ -498,6 +503,9 @@ input[type=text]{
font-weight: normal;
transition: border-color .17s ease-in-out;
text-align: left;
&:focus{
border-color: #94A0AD;
}
&:read-only{
background-color: #FAFAFA;
color: #999999;

View File

@ -333,7 +333,6 @@ export const findIntersection1 = (line1, line2) => {
export const calculateIntersection = (line1, line2) => {
const result = intersect([line1.x1, line1.y1], [line1.x2, line1.y2], [line2.x1, line2.y1], [line2.x2, line2.y2])
if (!result) {
return null
}
@ -366,6 +365,14 @@ export const calculateIntersection = (line1, line2) => {
}
}
export const getInterSectionLineNotOverCoordinate = (line1, line2) => {
const result = intersect([line1.x1, line1.y1], [line1.x2, line1.y2], [line2.x1, line2.y1], [line2.x2, line2.y2])
if (result) {
return { x: Math.round(result[0]), y: Math.round(result[1]) }
}
return null
}
export function findOrthogonalPoint(line1, line2) {
// Calculate the intersection point of two lines
const intersectionX =