Merge branch 'dev' into dev-yj
This commit is contained in:
commit
67330e7322
35
src/app/QcastProvider.js
Normal file
35
src/app/QcastProvider.js
Normal file
@ -0,0 +1,35 @@
|
||||
'use client'
|
||||
|
||||
import { useEffect } from 'react'
|
||||
import { useRecoilState, useRecoilValue } from 'recoil'
|
||||
import { appMessageStore, globalLocaleStore } from '@/store/localeAtom'
|
||||
import { ErrorBoundary } from 'next/dist/client/components/error-boundary'
|
||||
import ServerError from './error'
|
||||
|
||||
import '@/styles/common.scss'
|
||||
|
||||
import KO from '@/locales/ko.json'
|
||||
import JA from '@/locales/ja.json'
|
||||
|
||||
export const QcastProvider = ({ children }) => {
|
||||
const globalLocale = useRecoilValue(globalLocaleStore)
|
||||
const [appMessageState, setAppMessageState] = useRecoilState(appMessageStore)
|
||||
|
||||
useEffect(() => {
|
||||
console.log(sessionStorage.getItem('hi'))
|
||||
console.log(Object.keys(appMessageState).length)
|
||||
// if (Object.keys(appMessageState).length === 0) {
|
||||
if (globalLocale === 'ko') {
|
||||
setAppMessageState(KO)
|
||||
} else {
|
||||
setAppMessageState(JA)
|
||||
}
|
||||
// }
|
||||
}, [globalLocale])
|
||||
|
||||
return (
|
||||
<>
|
||||
<ErrorBoundary fallback={<ServerError />}>{children}</ErrorBoundary>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@ -1,11 +1,15 @@
|
||||
import React from 'react'
|
||||
import Hero from '@/components/Hero'
|
||||
import StuffDetail from '@/components/management/StuffDetail'
|
||||
import Link from 'next/link'
|
||||
export default function ManagementStuffDetailPage() {
|
||||
return (
|
||||
<>
|
||||
<div className="pt-48 flex justify-left">
|
||||
<h1 className="text-4xl archivo-black-regular">물건정보</h1>
|
||||
<Link href="/management/plan">
|
||||
<h1 className="text-4xl archivo-black-regular">도면작성</h1>
|
||||
</Link>
|
||||
</div>
|
||||
<div className="m2">
|
||||
<StuffDetail />
|
||||
|
||||
15
src/app/[locale]/management/stuff/tempdetail/page.jsx
Normal file
15
src/app/[locale]/management/stuff/tempdetail/page.jsx
Normal file
@ -0,0 +1,15 @@
|
||||
import React from 'react'
|
||||
import Hero from '@/components/Hero'
|
||||
import StuffDetail from '@/components/management/StuffDetail'
|
||||
export default function ManagementStuffDetailPage() {
|
||||
return (
|
||||
<>
|
||||
<div className="pt-48 flex justify-left">
|
||||
<h1 className="text-4xl archivo-black-regular">물건정보</h1>
|
||||
</div>
|
||||
<div className="m2">
|
||||
<StuffDetail />
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@ -1,21 +1,16 @@
|
||||
import { getSession } from '@/lib/authActions'
|
||||
import { getCurrentLocale } from '@/locales/server'
|
||||
import MainPage from '@/components/Main'
|
||||
|
||||
export default async function page() {
|
||||
const session = await getSession()
|
||||
|
||||
const currentLocale = getCurrentLocale()
|
||||
|
||||
const mainPageProps = {
|
||||
currentLocale,
|
||||
isLoggedIn: session?.isLoggedIn,
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="m-4">
|
||||
<h3>Main</h3>
|
||||
<MainPage {...mainPageProps} />
|
||||
</div>
|
||||
</>
|
||||
|
||||
16
src/app/community/archive/page.jsx
Normal file
16
src/app/community/archive/page.jsx
Normal file
@ -0,0 +1,16 @@
|
||||
import Hero from '@/components/Hero'
|
||||
import Archive from '@/components/community/Archive'
|
||||
import { initCheck } from '@/util/session-util'
|
||||
|
||||
export default async function CommunityArchivePage() {
|
||||
await initCheck()
|
||||
|
||||
return (
|
||||
<>
|
||||
<Hero title="자료 다운로드" />
|
||||
<div className="container flex flex-wrap items-center justify-between mx-auto p-4 m-4 border">
|
||||
<Archive />
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
16
src/app/community/faq/page.jsx
Normal file
16
src/app/community/faq/page.jsx
Normal file
@ -0,0 +1,16 @@
|
||||
import Hero from '@/components/Hero'
|
||||
import Faq from '@/components/community/Faq'
|
||||
import { initCheck } from '@/util/session-util'
|
||||
|
||||
export default async function CommunityFaqPage() {
|
||||
await initCheck()
|
||||
|
||||
return (
|
||||
<>
|
||||
<Hero title="FAQ" />
|
||||
<div className="container flex flex-wrap items-center justify-between mx-auto p-4 m-4 border">
|
||||
<Faq />
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
16
src/app/community/notice/page.jsx
Normal file
16
src/app/community/notice/page.jsx
Normal file
@ -0,0 +1,16 @@
|
||||
import Hero from '@/components/Hero'
|
||||
import Notice from '@/components/community/Notice'
|
||||
import { initCheck } from '@/util/session-util'
|
||||
|
||||
export default async function CommunityNoticePage() {
|
||||
await initCheck()
|
||||
|
||||
return (
|
||||
<>
|
||||
<Hero title="공지사항" />
|
||||
<div className="container flex flex-wrap items-center justify-between mx-auto p-4 m-4 border">
|
||||
<Notice />
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
9
src/app/floor-plan/page.jsx
Normal file
9
src/app/floor-plan/page.jsx
Normal file
@ -0,0 +1,9 @@
|
||||
import FloorPlan from '@/components/floor-plan/FloorPlan'
|
||||
|
||||
export default function FloorPlanPage() {
|
||||
return (
|
||||
<>
|
||||
<FloorPlan />
|
||||
</>
|
||||
)
|
||||
}
|
||||
16
src/app/initSettingsModal/page.jsx
Normal file
16
src/app/initSettingsModal/page.jsx
Normal file
@ -0,0 +1,16 @@
|
||||
import Hero from '@/components/Hero'
|
||||
import InitSettingsModal from '@/components/InitSettingsModal'
|
||||
import { initCheck } from '@/util/session-util'
|
||||
|
||||
export default async function InitSettingsModalPage() {
|
||||
await initCheck()
|
||||
|
||||
return (
|
||||
<>
|
||||
<Hero title="Basic Settings" />
|
||||
<div className="flex flex-col justify-center my-8">
|
||||
<InitSettingsModal />
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
14
src/app/intro/page.jsx
Normal file
14
src/app/intro/page.jsx
Normal file
@ -0,0 +1,14 @@
|
||||
import Intro from '@/components/Intro'
|
||||
import { initCheck } from '@/util/session-util'
|
||||
|
||||
export default async function IntroPage() {
|
||||
await initCheck()
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="container mx-auto p-4 m-4 border">
|
||||
<Intro />
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
19
src/app/join/complete/page.jsx
Normal file
19
src/app/join/complete/page.jsx
Normal file
@ -0,0 +1,19 @@
|
||||
'use client'
|
||||
|
||||
import { useMessage } from '@/hooks/useMessage'
|
||||
|
||||
export default function CompletePage() {
|
||||
const { getMessage } = useMessage()
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="flex min-h-full flex-1 flex-col justify-center px-6 py-12 lg:px-8">
|
||||
<h1 className="text-center text-4xl font-bold mb-10">{getMessage('join.complete.title')}</h1>
|
||||
<div className="mt-10 mb-10 w-full text-center text-2xl">{getMessage('join.complete.contents')}</div>
|
||||
<div className="mt-10 w-full text-center">
|
||||
{getMessage('join.complete.email_comment')} : {getMessage('join.complete.email')}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
5
src/app/join/page.jsx
Normal file
5
src/app/join/page.jsx
Normal file
@ -0,0 +1,5 @@
|
||||
import Join from '@/components/auth/Join'
|
||||
|
||||
export default function JoinPage() {
|
||||
return <>{<Join />}</>
|
||||
}
|
||||
@ -1,14 +1,19 @@
|
||||
import { Inter } from 'next/font/google'
|
||||
|
||||
import { headers } from 'next/headers'
|
||||
import { redirect } from 'next/navigation'
|
||||
import { getSession } from '@/lib/authActions'
|
||||
import RecoilRootWrapper from './RecoilWrapper'
|
||||
import UIProvider from './UIProvider'
|
||||
|
||||
import { ToastContainer } from 'react-toastify'
|
||||
|
||||
import Header from '@/components/header/Header'
|
||||
import QModal from '@/components/common/modal/QModal'
|
||||
|
||||
import './globals.css'
|
||||
import '../styles/style.scss'
|
||||
import Header from '@/components/header/Header'
|
||||
import { QcastProvider } from './QcastProvider'
|
||||
|
||||
const inter = Inter({ subsets: ['latin'] })
|
||||
|
||||
@ -17,16 +22,29 @@ export const metadata = {
|
||||
description: 'Generated by create next app',
|
||||
}
|
||||
|
||||
export default function RootLayout({ children }) {
|
||||
export default async function RootLayout({ children }) {
|
||||
const headersList = headers()
|
||||
const headerPathname = headersList.get('x-pathname') || ''
|
||||
|
||||
// console.log('headerPathname:', headerPathname)
|
||||
// const isLoggedIn = await checkSession()
|
||||
const session = await getSession()
|
||||
console.log('session[layout]:', session)
|
||||
if (!headerPathname.includes('/login') && !session.isLoggedIn) {
|
||||
redirect('/login')
|
||||
}
|
||||
|
||||
return (
|
||||
<html lang="en">
|
||||
<body className={inter.className}>
|
||||
{/*{headerPathname !== '/login' && <Headers />}*/}
|
||||
<RecoilRootWrapper>
|
||||
<div className="wrap">
|
||||
<Header />
|
||||
<Header loginedUserNm={session.userNm} />
|
||||
<div className="content">
|
||||
<UIProvider>{children}</UIProvider>
|
||||
<UIProvider>
|
||||
<QcastProvider>{children}</QcastProvider>
|
||||
</UIProvider>
|
||||
</div>
|
||||
</div>
|
||||
<ToastContainer />
|
||||
|
||||
9
src/app/login/page.jsx
Normal file
9
src/app/login/page.jsx
Normal file
@ -0,0 +1,9 @@
|
||||
import Login from '@/components/auth/Login'
|
||||
|
||||
export default function LoginPage() {
|
||||
return (
|
||||
<>
|
||||
<Login />
|
||||
</>
|
||||
)
|
||||
}
|
||||
16
src/app/management/plan/page.jsx
Normal file
16
src/app/management/plan/page.jsx
Normal file
@ -0,0 +1,16 @@
|
||||
import Hero from '@/components/Hero'
|
||||
import Plan from '@/components/management/Plan'
|
||||
import { initCheck } from '@/util/session-util'
|
||||
|
||||
export default async function ManagementPlanPage() {
|
||||
await initCheck()
|
||||
|
||||
return (
|
||||
<>
|
||||
<Hero title="도면관리" />
|
||||
<div className="container flex flex-wrap items-center justify-between mx-auto p-4 m-4 border">
|
||||
<Plan />
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
19
src/app/management/stuff/detail/page.jsx
Normal file
19
src/app/management/stuff/detail/page.jsx
Normal file
@ -0,0 +1,19 @@
|
||||
import React from 'react'
|
||||
import Hero from '@/components/Hero'
|
||||
import StuffDetail from '@/components/management/StuffDetail'
|
||||
import Link from 'next/link'
|
||||
export default function ManagementStuffDetailPage() {
|
||||
return (
|
||||
<>
|
||||
<div className="pt-48 flex justify-left">
|
||||
<h1 className="text-4xl archivo-black-regular">물건정보</h1>
|
||||
<Link href="/management/plan">
|
||||
<h1 className="text-4xl archivo-black-regular">도면작성</h1>
|
||||
</Link>
|
||||
</div>
|
||||
<div className="m2">
|
||||
<StuffDetail />
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
21
src/app/management/stuff/page.jsx
Normal file
21
src/app/management/stuff/page.jsx
Normal file
@ -0,0 +1,21 @@
|
||||
import StuffSearchCondition from '@/components/management/StuffSearchCondition'
|
||||
import Stuff from '@/components/management/Stuff'
|
||||
import { initCheck } from '@/util/session-util'
|
||||
import Hero from '@/components/Hero'
|
||||
export default async function ManagementStuffPage() {
|
||||
await initCheck()
|
||||
|
||||
return (
|
||||
<>
|
||||
<Hero title="물건현황" />
|
||||
<div>
|
||||
<div className="m2">
|
||||
<StuffSearchCondition />
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col justify-center my-8 pt-20">
|
||||
<Stuff />
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
15
src/app/management/stuff/tempdetail/page.jsx
Normal file
15
src/app/management/stuff/tempdetail/page.jsx
Normal file
@ -0,0 +1,15 @@
|
||||
import React from 'react'
|
||||
import Hero from '@/components/Hero'
|
||||
import StuffDetail from '@/components/management/StuffDetail'
|
||||
export default function ManagementStuffDetailPage() {
|
||||
return (
|
||||
<>
|
||||
<div className="pt-48 flex justify-left">
|
||||
<h1 className="text-4xl archivo-black-regular">물건정보</h1>
|
||||
</div>
|
||||
<div className="m2">
|
||||
<StuffDetail />
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
16
src/app/master/company/page.jsx
Normal file
16
src/app/master/company/page.jsx
Normal file
@ -0,0 +1,16 @@
|
||||
import Hero from '@/components/Hero'
|
||||
import Company from '@/components/master/Company'
|
||||
import { initCheck } from '@/util/session-util'
|
||||
|
||||
export default async function MasterCompanyPage() {
|
||||
await initCheck()
|
||||
|
||||
return (
|
||||
<>
|
||||
<Hero title="회사정보 조회" />
|
||||
<div className="container flex flex-wrap items-center justify-between mx-auto p-4 m-4 border">
|
||||
<Company />
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
16
src/app/master/price/page.jsx
Normal file
16
src/app/master/price/page.jsx
Normal file
@ -0,0 +1,16 @@
|
||||
import Hero from '@/components/Hero'
|
||||
import Price from '@/components/master/Price'
|
||||
import { initCheck } from '@/util/session-util'
|
||||
|
||||
export default async function MasterPricePage() {
|
||||
await initCheck()
|
||||
|
||||
return (
|
||||
<>
|
||||
<Hero title="가격 마스터 조회" />
|
||||
<div className="container flex flex-wrap items-center justify-between mx-auto p-4 m-4 border">
|
||||
<Price />
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@ -1,5 +1,16 @@
|
||||
import Main from '@/components/Main'
|
||||
import MainPage from '@/components/Main'
|
||||
import { getSession } from '@/lib/authActions'
|
||||
|
||||
export default function Home() {
|
||||
return <Main />
|
||||
export default async function Home() {
|
||||
const session = await getSession()
|
||||
|
||||
const mainPageProps = {
|
||||
isLoggedIn: session?.isLoggedIn,
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<MainPage {...mainPageProps} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
17
src/app/playground/page.jsx
Normal file
17
src/app/playground/page.jsx
Normal file
@ -0,0 +1,17 @@
|
||||
import Playground from '@/components/Playground'
|
||||
import { initCheck } from '@/util/session-util'
|
||||
|
||||
export default async function PlaygroundPage() {
|
||||
// const { session } = await checkSession()
|
||||
|
||||
// if (!session.isLoggedIn) {
|
||||
// redirect('/login')
|
||||
// }
|
||||
await initCheck()
|
||||
|
||||
return (
|
||||
<>
|
||||
<Playground />
|
||||
</>
|
||||
)
|
||||
}
|
||||
16
src/app/roof/page.jsx
Normal file
16
src/app/roof/page.jsx
Normal file
@ -0,0 +1,16 @@
|
||||
import Hero from '@/components/Hero'
|
||||
import Roof from '@/components/Roof'
|
||||
import { initCheck } from '@/util/session-util'
|
||||
|
||||
export default async function RoofPage() {
|
||||
await initCheck()
|
||||
|
||||
return (
|
||||
<>
|
||||
<Hero title="Drawing on canvas 2D Roof" />
|
||||
<div className="flex flex-col justify-center my-8">
|
||||
<Roof />
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
128
src/app/roof2/RoofSelect.jsx
Normal file
128
src/app/roof2/RoofSelect.jsx
Normal file
@ -0,0 +1,128 @@
|
||||
'use client'
|
||||
|
||||
import { Select, SelectItem } from '@nextui-org/react'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useAxios } from '@/hooks/useAxios'
|
||||
|
||||
export default function RoofSelect() {
|
||||
const [roofMaterials, setRoofMaterials] = useState([])
|
||||
const [manufacturers, setManufacturers] = useState([])
|
||||
const [trestles, setTrestles] = useState([])
|
||||
const [modules, setModules] = useState([])
|
||||
const [originTrestles, setOriginTrestles] = useState([])
|
||||
|
||||
const [roofMaterialId, setRoofMaterialId] = useState(null)
|
||||
const [manufacturerId, setManufacturerId] = useState(null)
|
||||
const [trestleId, setTrestleId] = useState(null)
|
||||
|
||||
const { get } = useAxios()
|
||||
|
||||
useEffect(() => {
|
||||
get({ url: '/api/roof-material/roof-material-infos' }).then((res) => {
|
||||
//TODO: error handling
|
||||
if (!res) return
|
||||
|
||||
setRoofMaterials(res)
|
||||
})
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (!roofMaterialId) {
|
||||
return
|
||||
}
|
||||
|
||||
get({ url: `/api/roof-material/roof-material-infos/${roofMaterialId}/trestles` }).then((res) => {
|
||||
if (res.length === 0) {
|
||||
return
|
||||
}
|
||||
setOriginTrestles(res)
|
||||
const manufactural = res.map((trestle) => {
|
||||
return { id: trestle.manufacturerId, name: trestle.manufacturerName }
|
||||
})
|
||||
// Remove duplicates
|
||||
const uniqueManufactural = Array.from(new Set(manufactural.map((a) => a.id))).map((id) => {
|
||||
return manufactural.find((a) => a.id === id)
|
||||
})
|
||||
|
||||
setManufacturers(uniqueManufactural)
|
||||
})
|
||||
}, [roofMaterialId])
|
||||
|
||||
useEffect(() => {
|
||||
if (!manufacturerId) {
|
||||
return
|
||||
}
|
||||
|
||||
const trestles = originTrestles.filter((trestle) => trestle.manufacturerId === manufacturerId)
|
||||
setTrestles(trestles)
|
||||
}, [manufacturerId])
|
||||
|
||||
useEffect(() => {
|
||||
if (!trestleId) {
|
||||
return
|
||||
}
|
||||
get({ url: `/api/module/module-infos?roofMaterialId=${roofMaterialId}&trestleId=${trestleId}` }).then((res) => {
|
||||
if (res.length === 0) {
|
||||
return
|
||||
}
|
||||
setModules(res)
|
||||
})
|
||||
}, [trestleId])
|
||||
|
||||
const handleRoofMaterialOnChange = (e) => {
|
||||
const roofMaterialId = e.target.value
|
||||
setRoofMaterialId(roofMaterialId)
|
||||
setManufacturers([])
|
||||
setManufacturerId(null)
|
||||
setTrestleId(null)
|
||||
setTrestles([])
|
||||
setModules([])
|
||||
}
|
||||
|
||||
const handleManufacturersOnChange = (e) => {
|
||||
const manufacturerId = Number(e.target.value)
|
||||
setTrestles([])
|
||||
setManufacturerId(manufacturerId)
|
||||
setTrestleId(null)
|
||||
setModules([])
|
||||
}
|
||||
|
||||
const handleTrestlesOnChange = (e) => {
|
||||
const trestleId = Number(e.target.value)
|
||||
setTrestleId(trestleId)
|
||||
setModules([])
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex w-full flex-wrap md:flex-nowrap gap-4">
|
||||
{roofMaterials.length > 0 && (
|
||||
<Select label="지붕재" className="max-w-xs" onChange={handleRoofMaterialOnChange}>
|
||||
{roofMaterials.map((roofMaterial) => (
|
||||
<SelectItem key={roofMaterial.id}>{roofMaterial.name}</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
)}
|
||||
{manufacturers.length > 0 && (
|
||||
<Select label="제조 회사" className="max-w-xs" onChange={handleManufacturersOnChange}>
|
||||
{manufacturers.map((manufacturer) => (
|
||||
<SelectItem key={manufacturer.id}>{manufacturer.name}</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
)}
|
||||
{trestles.length > 0 && (
|
||||
<Select label="가대" className="max-w-xs" onChange={handleTrestlesOnChange}>
|
||||
{trestles.map((trestle) => (
|
||||
<SelectItem key={trestle.id}>{trestle.name}</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
)}
|
||||
{modules.length > 0 && (
|
||||
<Select label="설치가능 모듈" className="max-w-xs">
|
||||
{modules.map((module) => (
|
||||
<SelectItem key={module.id}>{module.name}</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
26
src/app/roof2/page.jsx
Normal file
26
src/app/roof2/page.jsx
Normal file
@ -0,0 +1,26 @@
|
||||
import Roof2 from '@/components/Roof2'
|
||||
import RoofSelect from '@/app/[locale]/roof2/RoofSelect'
|
||||
import { initCheck } from '@/util/session-util'
|
||||
|
||||
export default async function Roof2Page() {
|
||||
const session = await initCheck()
|
||||
const roof2Props = {
|
||||
name: session.name || '',
|
||||
userId: session.userId || '',
|
||||
email: session.email || '',
|
||||
isLoggedIn: session.isLoggedIn,
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div>
|
||||
<div className="m-2">
|
||||
<RoofSelect />
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col justify-center my-8 pt-20">
|
||||
<Roof2 {...roof2Props} />
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
16
src/app/settings/page.jsx
Normal file
16
src/app/settings/page.jsx
Normal file
@ -0,0 +1,16 @@
|
||||
import Hero from '@/components/Hero'
|
||||
import Settings from '@/components/Settings'
|
||||
import { initCheck } from '@/util/session-util'
|
||||
|
||||
export default async function SettingsPage() {
|
||||
await initCheck()
|
||||
|
||||
return (
|
||||
<>
|
||||
<Hero title="Canvas Setting" />
|
||||
<div className="flex flex-col justify-center my-8">
|
||||
<Settings />
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@ -1,19 +1,22 @@
|
||||
export const STEP = {
|
||||
export const MENU = {
|
||||
INITIAL_CANVAS_SETTING: 'initialCanvasSetting', // 배치면 초기설정
|
||||
ROOF_COVERING: {
|
||||
EXTERIOR_WALL_LINE: 'exteriorWallLine', // 외벽선 그리기
|
||||
ROOF_SHAPE_SETTINGS: 'roofShapeSettings', // 지붕형상 설정
|
||||
ROOF_SHAPE_EDITING: 'roofShapeEditing', // 지붕형상 편집
|
||||
HELP_LINE_DRAWING: 'helpLineDrawing', // 보조선 그리기
|
||||
DEFAULT: 'roofCoveringDefault', // 아무것도 선택 안할 경우
|
||||
}, // 지붕덮개
|
||||
BATCH_CANVAS: {
|
||||
BATCH_DRAWING: 'batchDrawing', // 배치면 그리기
|
||||
SURFACE_SHAPE_BATCH: 'surfaceShapeBatch', // 면형상 배치
|
||||
OBJECT_BATCH: 'objectBatch', // 오브젝트 배치
|
||||
DEFAULT: 'batchCanvasDefault', // default
|
||||
}, // 배치면
|
||||
MODULE_CIRCUIT_SETTING: {
|
||||
BASIC_SETTING: 'basicSetting', // 기본설정
|
||||
CIRCUIT_TRESTLE_SETTING: 'circuitTrestleSetting', // 회로가대설정
|
||||
DEFAULT: 'moduleCircuitSettingDefault',
|
||||
}, // 모듈회로구성
|
||||
ESTIMATE: 'estimate', // todo 견적서
|
||||
POWER_GENERATION_SIMULATION: 'powerGenerationSimulation', // todo 발전 시뮬레이션
|
||||
|
||||
@ -1,62 +1,9 @@
|
||||
'use client'
|
||||
|
||||
import { logout } from '@/lib/authActions'
|
||||
import { useChangeLocale, useI18n } from '@/locales/client'
|
||||
import { Button, Chip } from '@nextui-org/react'
|
||||
import Link from 'next/link'
|
||||
|
||||
export default function MainPage(props) {
|
||||
const { currentLocale, isLoggedIn } = props
|
||||
const t = useI18n()
|
||||
const changeLocale = useChangeLocale()
|
||||
|
||||
const handleChangeLocale = () => {
|
||||
currentLocale === 'ja' ? changeLocale('ko') : changeLocale('ja')
|
||||
}
|
||||
|
||||
// console.log('MainPage', currentLocale)
|
||||
|
||||
const handleLogout = async () => {
|
||||
await logout()
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<h3>{t('locale', { locale: <Chip color="primary">{currentLocale}</Chip> })}</h3>
|
||||
<div>{t('hello')}</div>
|
||||
<div>{t('welcome', { name: '효준' })}</div>
|
||||
<div>
|
||||
<Button onClick={handleChangeLocale}>Change Locale</Button>
|
||||
</div>
|
||||
{isLoggedIn && (
|
||||
<div className="my-4">
|
||||
<Button color="primary" onClick={handleLogout}>
|
||||
로그아웃
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
{!isLoggedIn && (
|
||||
<div className="my-4">
|
||||
<Link href={'/' + currentLocale + '/login'}>
|
||||
<Button color="primary">로그인 페이지로 이동</Button>
|
||||
</Link>
|
||||
</div>
|
||||
)}
|
||||
<div className="font-test">font-test</div>
|
||||
{/*<h3>{t('locale', { locale: <Chip color="primary">{currentLocale}</Chip> })}</h3>*/}
|
||||
{/*<div>{t('hello')}</div>*/}
|
||||
{/*<div>{t('welcome', { name: '효준' })}</div>*/}
|
||||
{/*<div>*/}
|
||||
{/* <Button onClick={handleChangeLocale}>Change Locale</Button>*/}
|
||||
{/*</div>*/}
|
||||
{/*{isLoggedIn && (*/}
|
||||
{/* <div className="my-4">*/}
|
||||
{/* <Button color="primary" onClick={handleLogout}>*/}
|
||||
{/* 로그아웃*/}
|
||||
{/* </Button>*/}
|
||||
{/* </div>*/}
|
||||
{/*)}*/}
|
||||
{/*<div className="font-test">font-test</div>*/}
|
||||
<h1>Main page</h1>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
'use client'
|
||||
|
||||
import { post, patch } from '@/lib/Axios'
|
||||
import { useState } from 'react'
|
||||
import { useAxios } from '@/hooks/useAxios'
|
||||
import { setSession } from '@/lib/authActions'
|
||||
import { redirect } from 'next/navigation'
|
||||
import { useMessage } from '@/hooks/useMessage'
|
||||
@ -9,9 +10,10 @@ import { Button, Switch } from '@nextui-org/react'
|
||||
import { useRecoilState } from 'recoil'
|
||||
import { globalLocaleStore } from '@/store/localeAtom'
|
||||
import { modalContent, modalState } from '@/store/modalAtom'
|
||||
import { useState } from 'react'
|
||||
|
||||
export default function Login(props) {
|
||||
const { patch } = useAxios()
|
||||
|
||||
const { currentLocale } = props
|
||||
const { getMessage } = useMessage()
|
||||
const [globalLocaleState, setGlbalLocaleState] = useRecoilState(globalLocaleStore)
|
||||
|
||||
@ -1,15 +1,19 @@
|
||||
'use client'
|
||||
|
||||
import { useState } from 'react'
|
||||
import { useEffect, useState } from 'react'
|
||||
import Draggable from 'react-draggable'
|
||||
|
||||
export default function WithDraggable({ isShow, children }) {
|
||||
export default function WithDraggable({ isShow, children, pos }) {
|
||||
const [position, setPosition] = useState({ x: 0, y: 0 })
|
||||
|
||||
const handleOnDrag = (data) => {
|
||||
setPosition({ x: data.x, y: data.y })
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
setPosition({ ...pos })
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<>
|
||||
{isShow && (
|
||||
|
||||
@ -1,16 +1,22 @@
|
||||
'use client'
|
||||
import { useState } from 'react'
|
||||
|
||||
export default function QSelectBox({ title, option }) {
|
||||
const [selectAct, setSelectAct] = useState(false)
|
||||
export default function QSelectBox({ title = '', options, onChange }) {
|
||||
const [openSelect, setOpenSelect] = useState(false)
|
||||
const [selected, setSelected] = useState(title === '' ? options[0].name : title)
|
||||
|
||||
const handleClickSelectOption = (option) => {
|
||||
setSelected(option.name)
|
||||
onChange?.(option)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={`sort-select ${selectAct ? 'active' : ''}`} onClick={() => setSelectAct(!selectAct)}>
|
||||
<p>{title}</p>
|
||||
<div className={`sort-select ${openSelect ? 'active' : ''}`} onClick={() => setOpenSelect(!openSelect)}>
|
||||
<p>{selected}</p>
|
||||
<ul className="select-item-wrap">
|
||||
{option.map((el, idx) => (
|
||||
<li key={idx} className="select-item">
|
||||
<button>{el.name}</button>
|
||||
{options?.map((option) => (
|
||||
<li key={option.id} className="select-item">
|
||||
<button onClick={() => handleClickSelectOption(option)}>{option.name}</button>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
@ -1,45 +1,47 @@
|
||||
'use client'
|
||||
|
||||
import { useState } from "react"
|
||||
import CanvasFrame from "./CanvasFrame";
|
||||
import { useState } from 'react'
|
||||
import CanvasFrame from './CanvasFrame'
|
||||
import { useRecoilState, useRecoilValue } from 'recoil'
|
||||
import { currentMenuState, stepState } from '@/store/canvasAtom'
|
||||
|
||||
export default function CanvasLayout () {
|
||||
const [plans, setPlans] = useState([{ id: 0, name: 'Plan 1' }, { id: 1, name: 'Plan 2' }, { id: 2, name: 'Plan 3' }]);
|
||||
const [idxNum, setIdxNum] = useState(null);
|
||||
export default function CanvasLayout() {
|
||||
const [plans, setPlans] = useState([
|
||||
{ id: 0, name: 'Plan 1' },
|
||||
{ id: 1, name: 'Plan 2' },
|
||||
{ id: 2, name: 'Plan 3' },
|
||||
])
|
||||
const [idxNum, setIdxNum] = useState(null)
|
||||
|
||||
const onClickPlane = (num) => {
|
||||
setIdxNum(num);
|
||||
}
|
||||
const onClickPlane = (num) => {
|
||||
setIdxNum(num)
|
||||
}
|
||||
|
||||
const handleDeletePlan = (e, id) => {
|
||||
e.stopPropagation(); // 이벤트 버블링 방지
|
||||
setPlans(plans.filter(plan => plan.id !== id)); // 삭제할 아이디와 다른 아이템만 남김
|
||||
}
|
||||
const handleDeletePlan = (e, id) => {
|
||||
e.stopPropagation() // 이벤트 버블링 방지
|
||||
setPlans(plans.filter((plan) => plan.id !== id)) // 삭제할 아이디와 다른 아이템만 남김
|
||||
}
|
||||
|
||||
const addNewPlan = () => {
|
||||
setPlans([...plans, { id: plans.length, name: `Plan ${plans.length + 1}` }]);
|
||||
}
|
||||
const addNewPlan = () => {
|
||||
setPlans([...plans, { id: plans.length, name: `Plan ${plans.length + 1}` }])
|
||||
}
|
||||
|
||||
return(
|
||||
<div className="canvas-layout">
|
||||
<div className="canvas-page-list">
|
||||
<div className="canvas-plane-wrap">
|
||||
{plans.map((plan, idx) => (
|
||||
<button
|
||||
key={plan.id}
|
||||
className={`canvas-page-box ${idx === idxNum ? 'on' : ''}`}
|
||||
onClick={() => onClickPlane(idx)}
|
||||
>
|
||||
<span>{plan.name}</span>
|
||||
<i className="close" onClick={(e) => handleDeletePlan(e, plan.id)}></i>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<button className="plane-add" onClick={addNewPlan}>
|
||||
<span></span>
|
||||
</button>
|
||||
</div>
|
||||
<CanvasFrame/>
|
||||
return (
|
||||
<div className="canvas-layout">
|
||||
<div className="canvas-page-list">
|
||||
<div className="canvas-plane-wrap">
|
||||
{plans.map((plan, idx) => (
|
||||
<button key={plan.id} className={`canvas-page-box ${idx === idxNum ? 'on' : ''}`} onClick={() => onClickPlane(idx)}>
|
||||
<span>{plan.name}</span>
|
||||
<i className="close" onClick={(e) => handleDeletePlan(e, plan.id)}></i>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
<button className="plane-add" onClick={addNewPlan}>
|
||||
<span></span>
|
||||
</button>
|
||||
</div>
|
||||
<CanvasFrame />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@ -1,23 +1,79 @@
|
||||
'use client'
|
||||
import { useState } from 'react'
|
||||
import { useEffect, useState } from 'react'
|
||||
import MenuDepth01 from './MenuDepth01'
|
||||
import { useRecoilState } from 'recoil'
|
||||
import { modalState } from '@/store/modalAtom'
|
||||
import QSelectBox from '@/components/common/select/QSelectBox'
|
||||
import { useMessage } from '@/hooks/useMessage'
|
||||
import { post } from '@/lib/Axios'
|
||||
import { useRecoilState } from 'recoil'
|
||||
import { settingModalFirstOptionsState } from '@/store/settingAtom'
|
||||
|
||||
export default function CanvasMenu() {
|
||||
const [modalOption, setModalOption] = useRecoilState(modalState) //modal 열림닫힘 state
|
||||
export default function CanvasMenu(props) {
|
||||
const [objectNo] = useState('test123240912001')
|
||||
const { setShowCanvasSettingModal, showOutlineModal, setShowOutlineModal } = props
|
||||
const [menuNumber, setMenuNumber] = useState(null)
|
||||
const [vertical, setVertical] = useState(true)
|
||||
const [type, setType] = useState('')
|
||||
const { getMessage } = useMessage()
|
||||
const SelectOption = [{ name: '瓦53A' }, { name: '瓦53A' }]
|
||||
const onClickNav = (number) => {
|
||||
setMenuNumber(number)
|
||||
if (menuNumber === number) {
|
||||
setMenuNumber(null)
|
||||
if (number === 2) setType('outline')
|
||||
if (number === 3) setType('surface')
|
||||
if (number === 4) setType('module')
|
||||
}
|
||||
const menuProps = {
|
||||
setShowOutlineModal,
|
||||
type,
|
||||
}
|
||||
|
||||
const settingsModalOptions = useRecoilState(settingModalFirstOptionsState)
|
||||
|
||||
useEffect(() => {}, [menuNumber, type])
|
||||
|
||||
// 저장버튼(btn08) 클릭 시 호출되는 함수
|
||||
const handleSaveSettings = async () => {
|
||||
try {
|
||||
// 서버에 전송할 데이터
|
||||
const dataToSend = {
|
||||
option1: settingsModalOptions[0].option1.map((item) => ({
|
||||
column: item.column,
|
||||
selected: item.selected,
|
||||
})),
|
||||
option2: settingsModalOptions[0].option2.map((item) => ({
|
||||
column: item.column,
|
||||
selected: item.selected,
|
||||
})),
|
||||
}
|
||||
|
||||
const patternData = {
|
||||
objectNo,
|
||||
assignDisplay: dataToSend.option1[0].selected,
|
||||
drawDisplay: dataToSend.option1[1].selected,
|
||||
gridDisplay: dataToSend.option1[2].selected,
|
||||
charDisplay: dataToSend.option1[3].selected,
|
||||
flowDisplay: dataToSend.option1[4].selected,
|
||||
hallwayDimenDisplay: dataToSend.option1[5].selected,
|
||||
actualDimenDisplay: dataToSend.option1[6].selected,
|
||||
noDimenDisplay: dataToSend.option1[7].selected,
|
||||
trestleDisplay: dataToSend.option1[8].selected,
|
||||
coordiDisplay: dataToSend.option1[9].selected,
|
||||
drawConverDisplay: dataToSend.option1[10].selected,
|
||||
onlyBorder: dataToSend.option2[0].selected,
|
||||
lineHatch: dataToSend.option2[1].selected,
|
||||
allPainted: dataToSend.option2[2].selected,
|
||||
}
|
||||
|
||||
// HTTP POST 요청 보내기
|
||||
await post({ url: `/api/canvas-management/canvas-settings`, data: patternData })
|
||||
|
||||
// 응답 처리
|
||||
alert('설정이 저장되었습니다.')
|
||||
} catch (error) {
|
||||
console.error('설정을 저장하는 동안 오류가 발생했습니다:', error)
|
||||
alert('설정을 저장하는 중 오류가 발생했습니다.')
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={`canvas-menu-wrap ${menuNumber === 2 || menuNumber === 3 || menuNumber === 4 ? 'active' : ''}`}>
|
||||
<div className="canvas-menu-inner">
|
||||
@ -34,10 +90,15 @@ export default function CanvasMenu() {
|
||||
{getMessage('plan.menu.placement.surface.initial.setting')}
|
||||
</button>
|
||||
</li>
|
||||
<li className={`canvas-menu-item ${menuNumber === 2 ? 'active' : ''}`} onClick={() => onClickNav(2)}>
|
||||
<li
|
||||
className={`canvas-menu-item ${menuNumber === 2 ? 'active' : ''}`}
|
||||
onClick={() => {
|
||||
onClickNav(2)
|
||||
}}
|
||||
>
|
||||
<button>
|
||||
<span className="menu-icon con02"></span>
|
||||
{getMessage('plan.menu.root.cover')}
|
||||
{getMessage('plan.menu.roof.cover')}
|
||||
</button>
|
||||
</li>
|
||||
<li className={`canvas-menu-item ${menuNumber === 3 ? 'active' : ''}`} onClick={() => onClickNav(3)}>
|
||||
@ -73,15 +134,17 @@ export default function CanvasMenu() {
|
||||
<button className="btn02 active"></button>
|
||||
<button className="btn03 "></button>
|
||||
</div>
|
||||
<div className={`vertical-horizontal ${vertical ? 'on' : ''}`}>
|
||||
<span>{getMessage('plan.mode.vertical.horizontal')}</span>
|
||||
<button onClick={() => setVertical(!vertical)}>{vertical ? 'ON' : 'OFF'}</button>
|
||||
</div>
|
||||
{menuNumber !== 4 && (
|
||||
<div className={`vertical-horizontal ${vertical ? 'on' : ''}`}>
|
||||
<span>{getMessage('plan.mode.vertical.horizontal')}</span>
|
||||
<button onClick={() => setVertical(!vertical)}>{vertical ? 'ON' : 'OFF'}</button>
|
||||
</div>
|
||||
)}
|
||||
<div className="select-box">
|
||||
<QSelectBox title={'瓦53A'} option={SelectOption} />
|
||||
</div>
|
||||
<div className="btn-from">
|
||||
<button className="btn04" onClick={() => setModalOption({ ...modalOption, option: true })}></button>
|
||||
<button className="btn04" onClick={() => setShowCanvasSettingModal(true)}></button>
|
||||
<button className="btn05"></button>
|
||||
<button className="btn06"></button>
|
||||
</div>
|
||||
@ -92,7 +155,7 @@ export default function CanvasMenu() {
|
||||
</div>
|
||||
<div className="btn-from">
|
||||
<button className="btn07"></button>
|
||||
<button className="btn08"></button>
|
||||
<button className="btn08" onClick={handleSaveSettings}></button>
|
||||
<button className="btn09"></button>
|
||||
</div>
|
||||
</>
|
||||
@ -137,9 +200,7 @@ export default function CanvasMenu() {
|
||||
</div>
|
||||
</div>
|
||||
<div className={`canvas-depth2-wrap ${menuNumber === 2 || menuNumber === 3 || menuNumber === 4 ? 'active' : ''}`}>
|
||||
{menuNumber === 2 && <MenuDepth01 />}
|
||||
{menuNumber === 3 && <MenuDepth01 />}
|
||||
{menuNumber === 4 && <MenuDepth01 />}
|
||||
{(menuNumber === 2 || menuNumber === 3 || menuNumber === 4) && <MenuDepth01 {...menuProps} />}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@ -1,20 +1,40 @@
|
||||
'use client'
|
||||
|
||||
import CanvasMenu from '@/components/floor-plan/CanvasMenu'
|
||||
import SettingModal01 from '@/components/floor-plan/modal/settoing01/SettingModal01'
|
||||
import { useState } from 'react'
|
||||
import SettingModal01 from '@/components/floor-plan/modal/setting01/SettingModal01'
|
||||
import CanvasLayout from '@/components/floor-plan/CanvasLayout'
|
||||
import '@/styles/contents.scss'
|
||||
import OuterLineWall from '@/components/floor-plan/modal/outerlinesetting/OuterLineWall'
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
export default function FloorPlan() {
|
||||
const [modalOpen, setModalOpen] = useState('option')
|
||||
const [showCanvasSettingModal, setShowCanvasSettingModal] = useState(false)
|
||||
const [showOutlineModal, setShowOutlineModal] = useState(false)
|
||||
|
||||
const canvasSettingProps = {
|
||||
setShowCanvasSettingModal,
|
||||
}
|
||||
|
||||
const outlineProps = {
|
||||
setShowOutlineModal,
|
||||
}
|
||||
|
||||
const modalProps = {
|
||||
setShowCanvasSettingModal,
|
||||
showOutlineModal,
|
||||
setShowOutlineModal,
|
||||
}
|
||||
|
||||
useEffect(() => {}, [showOutlineModal])
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="canvas-wrap">
|
||||
<CanvasMenu modalOpen={modalOpen} setModalOpen={setModalOpen} />
|
||||
<CanvasMenu {...modalProps} />
|
||||
<div className="canvas-content">
|
||||
<CanvasLayout />
|
||||
{modalOpen === 'option' && <SettingModal01 modalOpen={modalOpen} setModalOpen={setModalOpen} />}
|
||||
{showCanvasSettingModal && <SettingModal01 {...canvasSettingProps} />}
|
||||
{showOutlineModal && <OuterLineWall {...outlineProps} />}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
|
||||
@ -2,33 +2,63 @@
|
||||
|
||||
import { ToggleonMouse } from '@/components/header/Header'
|
||||
import { useMessage } from '@/hooks/useMessage'
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
export default function MenuDepth01() {
|
||||
export default function MenuDepth01(props) {
|
||||
const { setShowOutlineModal, type } = props
|
||||
const { getMessage } = useMessage()
|
||||
const [activeMenu, setActiveMenu] = useState()
|
||||
const onClickMenu = (menuNum) => {
|
||||
setActiveMenu(menuNum)
|
||||
setShowOutlineModal(menuNum === 0)
|
||||
}
|
||||
|
||||
const menus = [
|
||||
{ id: 0, name: '外壁線を描' },
|
||||
{ id: 1, name: '補助線を描' },
|
||||
{ id: 2, name: '屋根形状設定' },
|
||||
{ id: 3, name: '軒下変更' },
|
||||
{ id: 4, name: '外壁線の上げ下げ' },
|
||||
{ id: 5, name: '銅線移動' },
|
||||
{ id: 6, name: '特殊コーナー形状' },
|
||||
]
|
||||
|
||||
const menuInfo = {
|
||||
outline: [
|
||||
// 지붕덮개
|
||||
{ id: 0, name: 'plan.menu.roof.cover.outline.drawing' },
|
||||
{ id: 1, name: 'plan.menu.roof.cover.roof.shape.setting' },
|
||||
{ id: 2, name: 'plan.menu.roof.cover.roof.shape.edit' },
|
||||
{ id: 3, name: 'plan.menu.roof.cover.auxiliary.line.drawing' },
|
||||
],
|
||||
surface: [
|
||||
// 배치면
|
||||
{ id: 0, name: 'plan.menu.placement.surface.drawing' },
|
||||
{ id: 1, name: 'plan.menu.placement.surface.surface' },
|
||||
{ id: 2, name: 'plan.menu.placement.surface.object' },
|
||||
],
|
||||
module: [
|
||||
// 모듈, 회로 구성
|
||||
{ id: 0, name: 'plan.menu.module.circuit.setting.default' },
|
||||
{ id: 1, name: 'plan.menu.module.circuit.setting.circuit.trestle.setting' },
|
||||
],
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
menus.forEach((menu) => {
|
||||
menu.isActive = menu.id === activeMenu
|
||||
})
|
||||
}, [menus, activeMenu])
|
||||
return (
|
||||
<div className="canvas-depth2-inner">
|
||||
<ul className="canvas-depth2-list">
|
||||
<li className="canvas-depth2-item active">
|
||||
<button>外壁線を描</button>
|
||||
</li>
|
||||
<li className="canvas-depth2-item">
|
||||
<button>補助線を描</button>
|
||||
</li>
|
||||
<li className="canvas-depth2-item">
|
||||
<button>屋根形状設定</button>
|
||||
</li>
|
||||
<li className="canvas-depth2-item">
|
||||
<button>軒下変更</button>
|
||||
</li>
|
||||
<li className="canvas-depth2-item">
|
||||
<button>外壁線の上げ下げ</button>
|
||||
</li>
|
||||
<li className="canvas-depth2-item">
|
||||
<button>銅線移動</button>
|
||||
</li>
|
||||
<li className="canvas-depth2-item">
|
||||
<button>特殊コーナー形状</button>
|
||||
</li>
|
||||
{menuInfo[type].map((menu) => {
|
||||
return (
|
||||
<li key={menu.id} className={`canvas-depth2-item ${menu.id === activeMenu ? 'active' : ''}`}>
|
||||
<button onClick={() => onClickMenu(menu.id)}>{getMessage(menu.name)}</button>
|
||||
</li>
|
||||
)
|
||||
})}
|
||||
</ul>
|
||||
<ul className="canvas-depth2-btn-list">
|
||||
<li className="depth2-btn-box" onMouseEnter={(e) => ToggleonMouse(e, 'add', 'ul')} onMouseLeave={(e) => ToggleonMouse(e, 'remove', 'ul')}>
|
||||
|
||||
54
src/components/floor-plan/RoofCoveringMenu.jsx
Normal file
54
src/components/floor-plan/RoofCoveringMenu.jsx
Normal file
@ -0,0 +1,54 @@
|
||||
'use client'
|
||||
|
||||
import { useMessage } from '@/hooks/useMessage'
|
||||
import { useRecoilState, useSetRecoilState } from 'recoil'
|
||||
import { currentMenuState } from '@/store/canvasAtom'
|
||||
import { MENU } from '@/common/common'
|
||||
import { modalState } from '@/store/modalAtom'
|
||||
import { ToggleonMouse } from '@/components/header/Header'
|
||||
|
||||
export default function RoofCoveringMenu() {
|
||||
const { getMessage } = useMessage()
|
||||
const [currentMenu, setCurrentMenu] = useRecoilState(currentMenuState)
|
||||
|
||||
const setModalState = useSetRecoilState(modalState)
|
||||
|
||||
const onClickNav = (menu) => {
|
||||
setCurrentMenu(menu)
|
||||
if (menu === MENU.ROOF_COVERING.EXTERIOR_WALL_LINE) {
|
||||
setModalState((prev) => ({ ...prev, outerwall: true }))
|
||||
} else {
|
||||
setModalState((prev) => ({ ...prev, outerwall: false }))
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="canvas-depth2-inner">
|
||||
<ul className="canvas-depth2-list">
|
||||
<li className={`canvas-depth2-item ${currentMenu === MENU.ROOF_COVERING.EXTERIOR_WALL_LINE ? 'active' : ''}`}>
|
||||
<button onClick={(e) => onClickNav(MENU.ROOF_COVERING.EXTERIOR_WALL_LINE)}>{getMessage('plan.menu.root.cover.outline.drawing')}</button>
|
||||
</li>
|
||||
<li className={`canvas-depth2-item ${currentMenu === MENU.ROOF_COVERING.ROOF_SHAPE_SETTINGS ? 'active' : ''}`}>
|
||||
<button onClick={(e) => onClickNav(MENU.ROOF_COVERING.ROOF_SHAPE_SETTINGS)}>{getMessage('plan.menu.root.cover.roof.setting')}</button>
|
||||
</li>
|
||||
<li className={`canvas-depth2-item ${currentMenu === MENU.ROOF_COVERING.ROOF_SHAPE_EDITING ? 'active' : ''}`}>
|
||||
<button onClick={(e) => onClickNav(MENU.ROOF_COVERING.ROOF_SHAPE_EDITING)}>{getMessage('plan.menu.root.cover.roof.edit')}</button>
|
||||
</li>
|
||||
<li className={`canvas-depth2-item ${currentMenu === MENU.ROOF_COVERING.HELP_LINE_DRAWING ? 'active' : ''}`}>
|
||||
<button onClick={(e) => onClickNav(MENU.ROOF_COVERING.HELP_LINE_DRAWING)}>{getMessage('plan.menu.root.cover.sub.line')}</button>
|
||||
</li>
|
||||
</ul>
|
||||
<ul className="canvas-depth2-btn-list">
|
||||
<li className="depth2-btn-box" onMouseEnter={(e) => ToggleonMouse(e, 'add', 'ul')} onMouseLeave={(e) => ToggleonMouse(e, 'remove', 'ul')}>
|
||||
<button>{getMessage('plan.menu.estimate.roof.alloc')}</button>
|
||||
</li>
|
||||
<li className="depth2-btn-box" onMouseEnter={(e) => ToggleonMouse(e, 'add', 'ul')} onMouseLeave={(e) => ToggleonMouse(e, 'remove', 'ul')}>
|
||||
<button>屋根材の設定と変更</button>
|
||||
</li>
|
||||
<li className="depth2-btn-box" onMouseEnter={(e) => ToggleonMouse(e, 'add', 'ul')} onMouseLeave={(e) => ToggleonMouse(e, 'remove', 'ul')}>
|
||||
<button>屋根面全体削除</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@ -0,0 +1,470 @@
|
||||
'use client'
|
||||
|
||||
import { useEffect, useRef } from 'react'
|
||||
import WithDraggable from '@/components/common/draggable/withDraggable'
|
||||
import { useRecoilState, useRecoilValue } from 'recoil'
|
||||
import { useMessage } from '@/hooks/useMessage'
|
||||
import { useEvent } from '@/hooks/useEvent'
|
||||
import { canvasState } from '@/store/canvasAtom'
|
||||
import {
|
||||
OUTER_LINE_TYPE,
|
||||
outerLineArrow1State,
|
||||
outerLineArrow2State,
|
||||
outerLineLength1State,
|
||||
outerLineLength2State,
|
||||
outerLinePointsState,
|
||||
outerLineTypeState,
|
||||
} from '@/store/outerLineAtom'
|
||||
import { QLine } from '@/components/fabric/QLine'
|
||||
import { useLine } from '@/hooks/useLine'
|
||||
|
||||
export default function OuterLineWall(props) {
|
||||
const { setShowOutlineModal } = props
|
||||
const { getMessage } = useMessage()
|
||||
const { addCanvasMouseEventListener, addDocumentEventListener, removeAllDocumentEventListeners } = useEvent()
|
||||
const { addLineText, removeLineText } = useLine()
|
||||
const length1Ref = useRef(null)
|
||||
const length2Ref = useRef(null)
|
||||
const [length1, setLength1] = useRecoilState(outerLineLength1State)
|
||||
const [length2, setLength2] = useRecoilState(outerLineLength2State)
|
||||
const [arrow1, setArrow1] = useRecoilState(outerLineArrow1State)
|
||||
const [arrow2, setArrow2] = useRecoilState(outerLineArrow2State)
|
||||
const [points, setPoints] = useRecoilState(outerLinePointsState)
|
||||
const [type, setType] = useRecoilState(outerLineTypeState)
|
||||
const arrow1Ref = useRef(arrow1)
|
||||
const arrow2Ref = useRef(arrow2)
|
||||
|
||||
const canvas = useRecoilValue(canvasState)
|
||||
|
||||
useEffect(() => {
|
||||
addCanvasMouseEventListener('mouse:down', mouseDown)
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
arrow1Ref.current = arrow1
|
||||
}, [arrow1])
|
||||
|
||||
useEffect(() => {
|
||||
arrow2Ref.current = arrow2
|
||||
}, [arrow2])
|
||||
|
||||
useEffect(() => {
|
||||
removeAllDocumentEventListeners()
|
||||
addDocumentEventListener('keydown', document, keydown[type])
|
||||
clear()
|
||||
}, [type])
|
||||
|
||||
const clear = () => {
|
||||
setLength1(0)
|
||||
setLength2(0)
|
||||
|
||||
setArrow1('')
|
||||
setArrow2('')
|
||||
}
|
||||
|
||||
const mouseDown = (e) => {
|
||||
const pointer = canvas.getPointer(e.e)
|
||||
|
||||
setPoints((prev) => [...prev, pointer])
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
canvas
|
||||
?.getObjects()
|
||||
.filter((obj) => obj.name === 'outerLine')
|
||||
.forEach((obj) => {
|
||||
canvas?.remove(obj)
|
||||
removeLineText(obj)
|
||||
})
|
||||
canvas?.remove(canvas?.getObjects().find((obj) => obj.name === 'startPoint'))
|
||||
if (points.length === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
if (points.length === 1) {
|
||||
const point = new fabric.Circle({
|
||||
radius: 5,
|
||||
fill: 'transparent',
|
||||
stroke: 'red',
|
||||
left: points[0].x - 5,
|
||||
top: points[0].y - 5,
|
||||
selectable: false,
|
||||
name: 'startPoint',
|
||||
})
|
||||
|
||||
canvas?.add(point)
|
||||
} else {
|
||||
points.forEach((point, idx) => {
|
||||
if (idx === 0) {
|
||||
return
|
||||
}
|
||||
drawLine(points[idx - 1], point, idx)
|
||||
})
|
||||
}
|
||||
}, [points])
|
||||
|
||||
const drawLine = (point1, point2, idx) => {
|
||||
const line = new QLine([point1.x, point1.y, point2.x, point2.y], {
|
||||
stroke: 'black',
|
||||
strokeWidth: 1,
|
||||
idx: idx,
|
||||
selectable: false,
|
||||
name: 'outerLine',
|
||||
})
|
||||
|
||||
canvas?.add(line)
|
||||
addLineText(line)
|
||||
}
|
||||
|
||||
// 직각 완료될 경우 확인
|
||||
const checkRightAngle = () => {
|
||||
const length1Num = Number(length1Ref.current.value) / 10
|
||||
const length2Num = Number(length2Ref.current.value) / 10
|
||||
|
||||
if (points.length === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
if (length1Num === 0 || length2Num === 0 || arrow1Ref.current === '' || arrow2Ref.current === '') {
|
||||
return
|
||||
}
|
||||
|
||||
if (arrow1Ref.current === '↓' && arrow2Ref.current === '→') {
|
||||
setPoints((prev) => {
|
||||
if (prev.length === 0) {
|
||||
return []
|
||||
}
|
||||
return [...prev, { x: prev[prev.length - 1].x + length2Num, y: prev[prev.length - 1].y + length1Num }]
|
||||
})
|
||||
} else if (arrow1Ref.current === '↓' && arrow2Ref.current === '←') {
|
||||
setPoints((prev) => {
|
||||
if (prev.length === 0) {
|
||||
return []
|
||||
}
|
||||
return [...prev, { x: prev[prev.length - 1].x - length2Num, y: prev[prev.length - 1].y + length1Num }]
|
||||
})
|
||||
} else if (arrow1Ref.current === '↑' && arrow2Ref.current === '→') {
|
||||
setPoints((prev) => {
|
||||
if (prev.length === 0) {
|
||||
return []
|
||||
}
|
||||
return [...prev, { x: prev[prev.length - 1].x + length2Num, y: prev[prev.length - 1].y - length1Num }]
|
||||
})
|
||||
} else if (arrow1Ref.current === '↑' && arrow2Ref.current === '←') {
|
||||
setPoints((prev) => {
|
||||
if (prev.length === 0) {
|
||||
return []
|
||||
}
|
||||
return [...prev, { x: prev[prev.length - 1].x - length2Num, y: prev[prev.length - 1].y - length1Num }]
|
||||
})
|
||||
} else if (arrow1Ref.current === '→' && arrow2Ref.current === '↓') {
|
||||
setPoints((prev) => {
|
||||
if (prev.length === 0) {
|
||||
return []
|
||||
}
|
||||
return [...prev, { x: prev[prev.length - 1].x + length1Num, y: prev[prev.length - 1].y + length2Num }]
|
||||
})
|
||||
} else if (arrow1Ref.current === '→' && arrow2Ref.current === '↑') {
|
||||
setPoints((prev) => {
|
||||
if (prev.length === 0) {
|
||||
return []
|
||||
}
|
||||
return [...prev, { x: prev[prev.length - 1].x + length1Num, y: prev[prev.length - 1].y - length2Num }]
|
||||
})
|
||||
} else if (arrow1Ref.current === '←' && arrow2Ref.current === '↓') {
|
||||
setPoints((prev) => {
|
||||
if (prev.length === 0) {
|
||||
return []
|
||||
}
|
||||
return [...prev, { x: prev[prev.length - 1].x - length1Num, y: prev[prev.length - 1].y + length2Num }]
|
||||
})
|
||||
} else if (arrow1Ref.current === '←' && arrow2Ref.current === '↑') {
|
||||
setPoints((prev) => {
|
||||
if (prev.length === 0) {
|
||||
return []
|
||||
}
|
||||
return [...prev, { x: prev[prev.length - 1].x - length1Num, y: prev[prev.length - 1].y - length2Num }]
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const keydown = {
|
||||
outerLine: (e) => {
|
||||
const key = e.key
|
||||
|
||||
if (!length1Ref.current) {
|
||||
return
|
||||
}
|
||||
|
||||
const lengthNum = Number(length1Ref.current.value) / 10
|
||||
if (lengthNum === 0) {
|
||||
return
|
||||
}
|
||||
switch (key) {
|
||||
case 'Down': // IE/Edge에서 사용되는 값
|
||||
case 'ArrowDown': {
|
||||
setArrow1('↓')
|
||||
setPoints((prev) => {
|
||||
if (prev.length === 0) {
|
||||
return []
|
||||
}
|
||||
return [...prev, { x: prev[prev.length - 1].x, y: prev[prev.length - 1].y + lengthNum }]
|
||||
})
|
||||
break
|
||||
}
|
||||
case 'Up': // IE/Edge에서 사용되는 값
|
||||
case 'ArrowUp':
|
||||
setArrow1('↑')
|
||||
setPoints((prev) => {
|
||||
if (prev.length === 0) {
|
||||
return []
|
||||
}
|
||||
return [...prev, { x: prev[prev.length - 1].x, y: prev[prev.length - 1].y - lengthNum }]
|
||||
})
|
||||
break
|
||||
case 'Left': // IE/Edge에서 사용되는 값
|
||||
case 'ArrowLeft':
|
||||
setArrow1('←')
|
||||
setPoints((prev) => {
|
||||
if (prev.length === 0) {
|
||||
return []
|
||||
}
|
||||
return [...prev, { x: prev[prev.length - 1].x - lengthNum, y: prev[prev.length - 1].y }]
|
||||
})
|
||||
break
|
||||
case 'Right': // IE/Edge에서 사용되는 값
|
||||
case 'ArrowRight':
|
||||
setArrow1('→')
|
||||
setPoints((prev) => {
|
||||
if (prev.length === 0) {
|
||||
return []
|
||||
}
|
||||
return [...prev, { x: prev[prev.length - 1].x + lengthNum, y: prev[prev.length - 1].y }]
|
||||
})
|
||||
break
|
||||
}
|
||||
},
|
||||
rightAngle: (e) => {
|
||||
const key = e.key
|
||||
|
||||
const activeElem = document.activeElement
|
||||
const length1Num = Number(length1Ref.current.value) / 10
|
||||
const length2Num = Number(length2Ref.current.value) / 10
|
||||
|
||||
switch (key) {
|
||||
case 'Down': // IE/Edge에서 사용되는 값
|
||||
case 'ArrowDown': {
|
||||
if (activeElem === length1Ref.current) {
|
||||
setArrow1('↓')
|
||||
arrow1Ref.current = '↓'
|
||||
length2Ref.current.focus()
|
||||
} else if (activeElem === length2Ref.current) {
|
||||
if (arrow1Ref.current === '↓' || arrow1Ref.current === '↑') {
|
||||
break
|
||||
}
|
||||
setArrow2('↓')
|
||||
arrow2Ref.current = '↓'
|
||||
checkRightAngle()
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
case 'Up': // IE/Edge에서 사용되는 값
|
||||
case 'ArrowUp':
|
||||
if (activeElem === length1Ref.current) {
|
||||
setArrow1('↑')
|
||||
arrow1Ref.current = '↑'
|
||||
length2Ref.current.focus()
|
||||
} else if (activeElem === length2Ref.current) {
|
||||
if (arrow1Ref.current === '↓' || arrow1Ref.current === '↑') {
|
||||
break
|
||||
}
|
||||
setArrow2('↑')
|
||||
arrow2Ref.current = '↑'
|
||||
checkRightAngle()
|
||||
}
|
||||
|
||||
break
|
||||
case 'Left': // IE/Edge에서 사용되는 값
|
||||
case 'ArrowLeft':
|
||||
if (activeElem === length1Ref.current) {
|
||||
setArrow1('←')
|
||||
arrow1Ref.current = '←'
|
||||
length2Ref.current.focus()
|
||||
} else if (activeElem === length2Ref.current) {
|
||||
if (arrow1Ref.current === '←' || arrow1Ref.current === '→') {
|
||||
break
|
||||
}
|
||||
setArrow2('←')
|
||||
arrow2Ref.current = '←'
|
||||
checkRightAngle()
|
||||
}
|
||||
|
||||
break
|
||||
case 'Right': // IE/Edge에서 사용되는 값
|
||||
case 'ArrowRight':
|
||||
if (activeElem === length1Ref.current) {
|
||||
setArrow1('→')
|
||||
arrow1Ref.current = '→'
|
||||
length2Ref.current.focus()
|
||||
} else if (activeElem === length2Ref.current) {
|
||||
if (arrow1Ref.current === '←' || arrow1Ref.current === '→') {
|
||||
break
|
||||
}
|
||||
setArrow2('→')
|
||||
arrow2Ref.current = '→'
|
||||
checkRightAngle()
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
},
|
||||
leeGubae: (e) => {
|
||||
console.log('leegubae')
|
||||
},
|
||||
angle: (e) => {
|
||||
console.log('angle')
|
||||
},
|
||||
diagonalLine: (e) => {
|
||||
console.log('diagonalLine')
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* 일변전으로 돌아가기
|
||||
*/
|
||||
const handleRollback = () => {
|
||||
//points의 마지막 요소를 제거
|
||||
setPoints((prev) => prev.slice(0, prev.length - 1))
|
||||
}
|
||||
|
||||
const handleFix = () => {
|
||||
setPoints((prev) => {
|
||||
if (prev.length === 0) {
|
||||
return []
|
||||
}
|
||||
return [...prev, { x: prev[0].x, y: prev[0].y }]
|
||||
})
|
||||
}
|
||||
return (
|
||||
<WithDraggable isShow={true} pos={{ x: 50, y: -1000 + 50 }}>
|
||||
<div className={`modal-pop-wrap ssm`}>
|
||||
<div className="modal-head">
|
||||
<h1 className="title">{getMessage('modal.cover.outline.drawing')}</h1>
|
||||
<button className="modal-close" onClick={() => setShowOutlineModal(false)}>
|
||||
닫기
|
||||
</button>
|
||||
</div>
|
||||
<div className="modal-body">
|
||||
<div className="modal-btn-wrap">
|
||||
<button
|
||||
className={`btn-frame modal ${type === OUTER_LINE_TYPE.OUTER_LINE ? 'act' : ''}`}
|
||||
onClick={() => setType(OUTER_LINE_TYPE.OUTER_LINE)}
|
||||
>
|
||||
{getMessage('modal.cover.outline')}
|
||||
</button>
|
||||
|
||||
<button
|
||||
className={`btn-frame modal ${type === OUTER_LINE_TYPE.RIGHT_ANGLE ? 'act' : ''}`}
|
||||
onClick={() => setType(OUTER_LINE_TYPE.RIGHT_ANGLE)}
|
||||
>
|
||||
{getMessage('modal.cover.outline.right.angle')}
|
||||
</button>
|
||||
<button
|
||||
className={`btn-frame modal ${type === OUTER_LINE_TYPE.LEE_GUBAE ? 'act' : ''}`}
|
||||
onClick={() => setType(OUTER_LINE_TYPE.LEE_GUBAE)}
|
||||
>
|
||||
{getMessage('modal.cover.outline2')}
|
||||
</button>
|
||||
<button className={`btn-frame modal ${type === OUTER_LINE_TYPE.ANGLE ? 'act' : ''}`} onClick={() => setType(OUTER_LINE_TYPE.ANGLE)}>
|
||||
{getMessage('modal.cover.outline.angle')}
|
||||
</button>
|
||||
<button
|
||||
className={`btn-frame modal ${type === OUTER_LINE_TYPE.DIAGONAL_LINE ? 'act' : ''}`}
|
||||
onClick={() => setType(OUTER_LINE_TYPE.DIAGONAL_LINE)}
|
||||
>
|
||||
{getMessage('modal.cover.outline.diagonal')}
|
||||
</button>
|
||||
</div>
|
||||
<div className="modal-check-btn-wrap">
|
||||
<h3 className="check-wrap-title">{getMessage('modal.cover.outline.setting')}</h3>
|
||||
{type === OUTER_LINE_TYPE.OUTER_LINE ? (
|
||||
<div className="outer-line-wrap">
|
||||
<div className="form-input">
|
||||
<label htmlFor="">{getMessage('modal.cover.outline.length')}</label>
|
||||
<input
|
||||
type="text"
|
||||
className="input-origin block"
|
||||
value={length1}
|
||||
ref={length1Ref}
|
||||
onChange={(e) => {
|
||||
setLength1(e.target.value.replace(/[^-0-9]/g, ''))
|
||||
}}
|
||||
placeholder="3000"
|
||||
/>
|
||||
</div>
|
||||
<div className="form-input">
|
||||
<label htmlFor="">{getMessage('modal.cover.outline.arrow')}</label>
|
||||
<input type="text" readOnly={true} value={arrow1} className="input-origin block" />
|
||||
</div>
|
||||
</div>
|
||||
) : type === OUTER_LINE_TYPE.RIGHT_ANGLE ? (
|
||||
<div className="outer-line-wrap">
|
||||
<div className="form-input">
|
||||
<label htmlFor="">{getMessage('modal.cover.outline.length')}</label>
|
||||
<input
|
||||
type="text"
|
||||
className="input-origin block"
|
||||
value={length1}
|
||||
ref={length1Ref}
|
||||
onChange={(e) => {
|
||||
setLength1(e.target.value.replace(/[^-0-9]/g, ''))
|
||||
}}
|
||||
placeholder="3000"
|
||||
/>
|
||||
</div>
|
||||
<div className="form-input">
|
||||
<label htmlFor="">{getMessage('modal.cover.outline.arrow')}</label>
|
||||
<input type="text" readOnly={true} value={arrow1} className="input-origin block" />
|
||||
</div>
|
||||
<div className="form-input">
|
||||
<label htmlFor="">{getMessage('modal.cover.outline.length')}</label>
|
||||
<input
|
||||
type="text"
|
||||
className="input-origin block"
|
||||
value={length2}
|
||||
ref={length2Ref}
|
||||
onChange={(e) => {
|
||||
setLength2(e.target.value.replace(/[^-0-9]/g, ''))
|
||||
}}
|
||||
placeholder="3000"
|
||||
/>
|
||||
</div>
|
||||
<div className="form-input">
|
||||
<label htmlFor="">{getMessage('modal.cover.outline.arrow')}</label>
|
||||
<input type="text" readOnly={true} value={arrow2} className="input-origin block" />
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
<div className="flex-check-box for2 btn">
|
||||
<button className="arr-btn dark" onClick={handleFix}>
|
||||
<span>{getMessage('modal.cover.outline.fix')}</span>
|
||||
</button>
|
||||
<button className="arr-btn dark act" onClick={handleRollback}>
|
||||
<span>{getMessage('modal.cover.outline.rollback')}</span>
|
||||
</button>
|
||||
<button className="arr-btn dark">
|
||||
<span>{getMessage('modal.cover.outline.remove')}</span>
|
||||
</button>
|
||||
<button className="arr-btn dark">
|
||||
<span>{getMessage('modal.cover.outline.select.move')}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</WithDraggable>
|
||||
)
|
||||
}
|
||||
@ -1,11 +1,58 @@
|
||||
import { useRecoilState } from 'recoil'
|
||||
import { settingModalFirstOptionsState } from '@/store/settingAtom'
|
||||
import { useMessage } from '@/hooks/useMessage'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { get } from '@/lib/Axios'
|
||||
|
||||
export default function FirstOption() {
|
||||
const [objectNo] = useState('test123240912001')
|
||||
const [settingsModalOptions, setSettingModalOptions] = useRecoilState(settingModalFirstOptionsState)
|
||||
const { option1, option2 } = settingsModalOptions
|
||||
const { getMessage } = useMessage()
|
||||
|
||||
// 초기 조회
|
||||
useEffect(() => {
|
||||
console.log('useEffect 실행')
|
||||
fetchSettings()
|
||||
}, [])
|
||||
|
||||
// Canvas Setting 조회 및 초기화
|
||||
const fetchSettings = async () => {
|
||||
try {
|
||||
const res = await get({ url: `/api/canvas-management/canvas-settings/by-object/${objectNo}` })
|
||||
|
||||
// console.log(res)
|
||||
|
||||
const options1 = [
|
||||
'assignDisplay',
|
||||
'drawDisplay',
|
||||
'gridDisplay',
|
||||
'charDisplay',
|
||||
'flowDisplay',
|
||||
'hallwayDimenDisplay',
|
||||
'actualDimenDisplay',
|
||||
'noDimenDisplay',
|
||||
'trestleDisplay',
|
||||
'coordiDisplay',
|
||||
'drawConverDisplay',
|
||||
]
|
||||
const option1 = settingsModalOptions.option1.map((item, index) => ({ ...item, selected: res[options1[index]] }))
|
||||
|
||||
const options2 = ['onlyBorder', 'lineHatch', 'allPainted']
|
||||
const option2 = settingsModalOptions.option2.map((item, index) => ({ ...item, selected: res[options2[index]] }))
|
||||
|
||||
// 데이터 설정
|
||||
setSettingModalOptions({
|
||||
option1,
|
||||
option2,
|
||||
// rangeSetting: data.rangeSetting,
|
||||
// gridSettings: data.gridSettings,
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('Data fetching error:', error)
|
||||
}
|
||||
}
|
||||
|
||||
const onClickOption = (option) => {
|
||||
option.selected = !option.selected
|
||||
|
||||
@ -1,9 +1,11 @@
|
||||
import { useRecoilState } from 'recoil'
|
||||
import { settingModalSecondOptionsState } from '@/store/settingAtom'
|
||||
import { useMessage } from '@/hooks/useMessage'
|
||||
|
||||
export default function SecondOption() {
|
||||
const [settingsModalOptions, setSettingModalOptions] = useRecoilState(settingModalSecondOptionsState)
|
||||
const { option1, option2 } = settingsModalOptions
|
||||
const { getMessage } = useMessage()
|
||||
const onClickOption = (option) => {
|
||||
option.selected = !option.selected
|
||||
|
||||
@ -12,31 +14,31 @@ export default function SecondOption() {
|
||||
return (
|
||||
<>
|
||||
<div className="modal-check-btn-wrap">
|
||||
<h3 className="check-wrap-title">フォントとサイズの変更</h3>
|
||||
<h3 className="check-wrap-title">{getMessage('modal.canvas.setting.font.plan.edit')}</h3>
|
||||
<div className="flex-check-box for2">
|
||||
{settingsModalOptions.option1.map((item) => (
|
||||
<button className="arr-btn">
|
||||
<span>{item.name}</span>
|
||||
<span>{getMessage(item.name)}</span>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="modal-check-btn-wrap">
|
||||
<h3 className="check-wrap-title">吸着範囲の設定</h3>
|
||||
<h3 className="check-wrap-title">{getMessage('modal.canvas.setting.font.plan.absorption')}</h3>
|
||||
<div className="flex-check-box for-line">
|
||||
{settingsModalOptions.option2.map((item) => (
|
||||
<button key={item.id} className={`check-btn ${item.selected ? 'act' : ''}`} onClick={() => onClickOption(item)}>
|
||||
<span className="check-area"></span>
|
||||
<span className="title-area">{item.name}</span>
|
||||
<span className="title-area">{getMessage(item.name)}</span>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<div className="flex-check-box for-line">
|
||||
<button className="arr-btn">
|
||||
<span>寸法線の設定</span>
|
||||
<span>{getMessage('modal.canvas.setting.font.plan.absorption.dimension.line')}</span>
|
||||
</button>
|
||||
<button className="arr-btn">
|
||||
<span>図面サイズの設定</span>
|
||||
<span>{getMessage('modal.canvas.setting.font.plan.absorption.plan.size.setting')}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@ -3,27 +3,20 @@
|
||||
import { useState } from 'react'
|
||||
import FirstOption from './FirstOption'
|
||||
import WithDraggable from '@/components/common/draggable/withDraggable'
|
||||
import SecondOption from '@/components/floor-plan/modal/settoing01/SecondOption'
|
||||
import SecondOption from '@/components/floor-plan/modal/setting01/SecondOption'
|
||||
import { useMessage } from '@/hooks/useMessage'
|
||||
|
||||
export default function SettingModal01({ modalOpen, setModalOpen }) {
|
||||
export default function SettingModal01(props) {
|
||||
const { setShowCanvasSettingModal } = props
|
||||
const [buttonAct, setButtonAct] = useState(1)
|
||||
const [close, setClose] = useState(false)
|
||||
const HandleClickClose = () => {
|
||||
setClose(true)
|
||||
setTimeout(() => {
|
||||
setModalOpen('')
|
||||
setClose(false)
|
||||
}, 180)
|
||||
}
|
||||
const { getMessage } = useMessage()
|
||||
|
||||
return (
|
||||
<WithDraggable isShow={true}>
|
||||
<div className={`modal-pop-wrap sm ${modalOpen === 'option' && close === false ? 'mount' : ''}${close ? 'unmount' : ''} `}>
|
||||
<WithDraggable isShow={true} pos={{ x: window.innerWidth - 450 - 50, y: -1000 + 50 }}>
|
||||
<div className={`modal-pop-wrap sm`}>
|
||||
<div className="modal-head">
|
||||
<h1 className="title">{getMessage('modal.canvas.setting')}</h1>
|
||||
<button className="modal-close" onClick={HandleClickClose}>
|
||||
<button className="modal-close" onClick={() => setShowCanvasSettingModal(false)}>
|
||||
닫기
|
||||
</button>
|
||||
</div>
|
||||
@ -1,8 +1,11 @@
|
||||
'use client'
|
||||
import { Fragment, useState } from 'react'
|
||||
import Link from 'next/link'
|
||||
import QSelectBox from '@/components/common/select/QSelectBox'
|
||||
import { usePathname } from 'next/navigation'
|
||||
import { usePathname, useRouter } from 'next/navigation'
|
||||
import { useMessage } from '@/hooks/useMessage'
|
||||
import { logout } from '@/lib/authActions'
|
||||
|
||||
import QSelectBox from '@/components/common/select/QSelectBox'
|
||||
|
||||
export const ToggleonMouse = (e, act, target) => {
|
||||
const listWrap = e.target.closest(target)
|
||||
@ -19,101 +22,122 @@ export const ToggleonMouse = (e, act, target) => {
|
||||
}
|
||||
}
|
||||
|
||||
export default function Header() {
|
||||
export default function Header(props) {
|
||||
const { loginedUserNm } = props
|
||||
const { getMessage } = useMessage()
|
||||
const pathName = usePathname()
|
||||
if (pathName.includes('login') || pathName.includes('join')) {
|
||||
return null
|
||||
// if (pathName.includes('login') || pathName.includes('join')) {
|
||||
// return null
|
||||
// }
|
||||
const [selected, setSelected] = useState('')
|
||||
|
||||
const SelectOptions = [
|
||||
{ id: 0, name: 'オンライン保証シ', link: '' },
|
||||
{ id: 1, name: 'ステム', link: '' },
|
||||
{ id: 2, name: 'TEST1', link: 'https://www.weather.go.kr/w/index.do' },
|
||||
{ id: 3, name: 'TEST2', link: 'https://www.google.com' },
|
||||
]
|
||||
const menus = [
|
||||
{ id: 0, name: 'header.menus.home', url: '/', children: [] },
|
||||
{
|
||||
id: 1,
|
||||
name: 'header.menus.management',
|
||||
url: '',
|
||||
children: [
|
||||
{ id: 3, name: 'header.menus.management.stuff', url: '/management/stuff', children: [] },
|
||||
{ id: 4, name: 'header.menus.management.plan', url: '/floor-plan', children: [] },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'header.menus.community',
|
||||
url: '',
|
||||
children: [
|
||||
{ id: 5, name: 'header.menus.community.notice', url: '/community/notice', children: [] },
|
||||
{ id: 6, name: 'header.menus.community.faq', url: '/community/faq', children: [] },
|
||||
{ id: 7, name: 'header.menus.community.archive', url: '/community/archive', children: [] },
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
const onChangeSelect = (option) => {
|
||||
setSelected(option)
|
||||
}
|
||||
const navPage = () => {
|
||||
if (selected.link) {
|
||||
location.href = selected.link
|
||||
}
|
||||
}
|
||||
|
||||
const getMenuTemplate = (menus) => {
|
||||
return menus.map((menu) => {
|
||||
return (
|
||||
<li
|
||||
key={`${menu.id}`}
|
||||
className={'nav-item'}
|
||||
onMouseEnter={(e) => ToggleonMouse(e, 'add', 'nav > ul')}
|
||||
onMouseLeave={(e) => ToggleonMouse(e, 'remove', 'nav > ul')}
|
||||
>
|
||||
{menu.children.length === 0 ? (
|
||||
<Link key={`${menu.id}`} href={menu.url}>
|
||||
{getMessage(menu.name)}
|
||||
</Link>
|
||||
) : (
|
||||
<Fragment key={`${menu.id}`}>
|
||||
<button>{getMessage(menu.name)}</button>
|
||||
<ul className="nav-depth2">
|
||||
{menu.children.map((m) => {
|
||||
return (
|
||||
<li
|
||||
key={`${m.id}`}
|
||||
className={'nav-depth2-item'}
|
||||
onMouseEnter={(e) => ToggleonMouse(e, 'add', 'li > ul')}
|
||||
onMouseLeave={(e) => ToggleonMouse(e, 'remove', 'li > ul')}
|
||||
>
|
||||
<Link href={m.url}>{getMessage(m.name)}</Link>
|
||||
</li>
|
||||
)
|
||||
})}
|
||||
</ul>
|
||||
</Fragment>
|
||||
)}
|
||||
</li>
|
||||
)
|
||||
})
|
||||
}
|
||||
const SelectOption = [{ name: 'オンライン保証シ' }, { name: 'ステム' }]
|
||||
|
||||
return (
|
||||
<header>
|
||||
<div className="header-inner">
|
||||
<div className="header-right">
|
||||
<h1 className="logo">
|
||||
<Link href={'/'}></Link>
|
||||
</h1>
|
||||
<nav>
|
||||
<ul className="nav-list ">
|
||||
<li
|
||||
className="nav-item "
|
||||
onMouseEnter={(e) => ToggleonMouse(e, 'add', 'nav > ul')}
|
||||
onMouseLeave={(e) => ToggleonMouse(e, 'remove', 'nav > ul')}
|
||||
>
|
||||
<Link href={'#'}>{getMessage('header.menus.home')}</Link>
|
||||
</li>
|
||||
<li
|
||||
className="nav-item"
|
||||
onMouseEnter={(e) => ToggleonMouse(e, 'add', 'nav > ul')}
|
||||
onMouseLeave={(e) => ToggleonMouse(e, 'remove', 'nav > ul')}
|
||||
>
|
||||
<button>{getMessage('header.menus.management')}</button>
|
||||
<ul className="nav-depth2">
|
||||
<li
|
||||
className="nav-depth2-item"
|
||||
onMouseEnter={(e) => ToggleonMouse(e, 'add', 'li > ul')}
|
||||
onMouseLeave={(e) => ToggleonMouse(e, 'remove', 'li > ul')}
|
||||
>
|
||||
<Link href={'#'}>{getMessage('header.menus.management.stuff')}</Link>
|
||||
</li>
|
||||
<li
|
||||
className="nav-depth2-item"
|
||||
onMouseEnter={(e) => ToggleonMouse(e, 'add', 'li > ul')}
|
||||
onMouseLeave={(e) => ToggleonMouse(e, 'remove', 'li > ul')}
|
||||
>
|
||||
<Link href={'#'}>{getMessage('header.menus.management.plan')}</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li
|
||||
className="nav-item"
|
||||
onMouseEnter={(e) => ToggleonMouse(e, 'add', 'nav > ul')}
|
||||
onMouseLeave={(e) => ToggleonMouse(e, 'remove', 'nav > ul')}
|
||||
>
|
||||
<button>{getMessage('header.menus.community')}</button>
|
||||
<ul className="nav-depth2">
|
||||
<li
|
||||
className="nav-depth2-item"
|
||||
onMouseEnter={(e) => ToggleonMouse(e, 'add', 'li > ul')}
|
||||
onMouseLeave={(e) => ToggleonMouse(e, 'remove', 'li > ul')}
|
||||
>
|
||||
<Link href={'#'}>{getMessage('header.menus.community.notice')}</Link>
|
||||
</li>
|
||||
<li
|
||||
className="nav-depth2-item"
|
||||
onMouseEnter={(e) => ToggleonMouse(e, 'add', 'li > ul')}
|
||||
onMouseLeave={(e) => ToggleonMouse(e, 'remove', 'li > ul')}
|
||||
>
|
||||
<Link href={'#'}>{getMessage('header.menus.community.faq')}</Link>
|
||||
</li>
|
||||
<li
|
||||
className="nav-depth2-item"
|
||||
onMouseEnter={(e) => ToggleonMouse(e, 'add', 'li > ul')}
|
||||
onMouseLeave={(e) => ToggleonMouse(e, 'remove', 'li > ul')}
|
||||
>
|
||||
<Link href={'#'}>{getMessage('header.menus.community.archive')}</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<div className="header-left">
|
||||
<div className="profile-box">
|
||||
<button className="profile">Kim Ji Young</button>
|
||||
!(pathName.includes('login') || pathName.includes('join')) && (
|
||||
<header>
|
||||
<div className="header-inner">
|
||||
<div className="header-right">
|
||||
<h1 className="logo">
|
||||
<Link href={'/'}></Link>
|
||||
</h1>
|
||||
<nav>
|
||||
<ul className="nav-list ">{getMenuTemplate(menus)}</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<div className="sign-out-box">
|
||||
<button className="sign-out">{getMessage('header.logout')}</button>
|
||||
</div>
|
||||
<div className="select-box">
|
||||
<QSelectBox title={'Q.ORDER'} option={SelectOption} />
|
||||
</div>
|
||||
<div className="btn-wrap">
|
||||
<button className="btn-frame small dark">{getMessage('header.go')}</button>
|
||||
<div className="header-left">
|
||||
<div className="profile-box">
|
||||
<button className="profile">{loginedUserNm}</button>
|
||||
</div>
|
||||
<div className="sign-out-box">
|
||||
<button className="sign-out" onClick={() => logout()}>
|
||||
{getMessage('header.logout')}
|
||||
</button>
|
||||
</div>
|
||||
<div className="select-box">
|
||||
<QSelectBox title={'Q.ORDER'} options={SelectOptions} onChange={onChangeSelect} />
|
||||
</div>
|
||||
<div className="btn-wrap">
|
||||
<button className="btn-frame small dark" onClick={() => navPage()}>
|
||||
{getMessage('header.go')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
</header>
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@ import { Button } from '@nextui-org/react'
|
||||
import { useAxios } from '@/hooks/useAxios'
|
||||
import { useMessage } from '@/hooks/useMessage'
|
||||
import StuffQGrid from './StuffQGrid'
|
||||
import { useRecoilValue } from 'recoil'
|
||||
import { useRecoilValue, useRecoilState } from 'recoil'
|
||||
import { stuffSearchState } from '@/store/stuffAtom'
|
||||
import { queryStringFormatter, isEmptyArray } from '@/util/common-utils'
|
||||
import dayjs from 'dayjs'
|
||||
@ -15,10 +15,12 @@ dayjs.extend(isLeapYear)
|
||||
|
||||
export default function Stuff() {
|
||||
const stuffSearchParams = useRecoilValue(stuffSearchState)
|
||||
const [stuffSearch, setStuffSearch] = useRecoilState(stuffSearchState)
|
||||
const { getMessage } = useMessage()
|
||||
const [curPage, setCurPage] = useState(1) //현재 페이지 번호
|
||||
const [size, setSize] = useState(100) //페이지 당 게시물 수
|
||||
const { get, del } = useAxios()
|
||||
const [defaultSize, setDefaultSize] = useState(100) //페이지 당 게시물 수
|
||||
const [defaultSortType, setDefaultSortType] = useState('R')
|
||||
const { get } = useAxios()
|
||||
const gridRef = useRef()
|
||||
|
||||
const [gridCount, setGridCount] = useState(0)
|
||||
@ -38,13 +40,26 @@ export default function Stuff() {
|
||||
}
|
||||
}
|
||||
|
||||
//물건번호 복사버튼 옆에 영역
|
||||
const onDoubleClick = (e) => {
|
||||
let objectNo = e.target.innerText
|
||||
console.log(objectNo)
|
||||
if (objectNo.substring(0, 1) === 'R') {
|
||||
console.log('진짜')
|
||||
router.push(`${pathname}/detail?objectNo=${objectNo.toString()}`)
|
||||
} else {
|
||||
console.log('임시')
|
||||
router.push(`${pathname}/tempdetail?objectNo=${objectNo.toString()}`)
|
||||
}
|
||||
}
|
||||
|
||||
const [gridProps, setGridProps] = useState({
|
||||
gridData: [],
|
||||
isPageable: false,
|
||||
// sets 10 rows per page (default is 100)
|
||||
paginationPageSize: 100,
|
||||
// paginationPageSize: 100,
|
||||
// allows the user to select the page size from a predefined list of page sizes
|
||||
paginationPageSizeSelector: [100, 200, 300, 400],
|
||||
// paginationPageSizeSelector: [100, 200, 300, 400],
|
||||
gridColumns: [
|
||||
{
|
||||
field: 'lastEditDatetime',
|
||||
@ -82,7 +97,6 @@ export default function Stuff() {
|
||||
<div>
|
||||
<Button
|
||||
size="sm"
|
||||
// isDisabled={params.data.successful ? false : true}
|
||||
color="default"
|
||||
onPress={() => {
|
||||
copyNo(params.value)
|
||||
@ -90,7 +104,7 @@ export default function Stuff() {
|
||||
>
|
||||
복사
|
||||
</Button>
|
||||
<span>{params.value}</span>
|
||||
<span onDoubleClick={onDoubleClick}>{params.value}</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@ -148,8 +162,15 @@ export default function Stuff() {
|
||||
return
|
||||
} else {
|
||||
console.log(' 상세이동::::::::', event.data)
|
||||
//T 면 임시 R은 진짜
|
||||
if (event.data.objectNo) {
|
||||
router.push(`${pathname}/detail?objectNo=${event.data.objectNo.toString()}`)
|
||||
if (event.data.objectNo.substring(0, 1) === 'R') {
|
||||
console.log('진짜:::::::::')
|
||||
router.push(`${pathname}/detail?objectNo=${event.data.objectNo.toString()}`)
|
||||
} else {
|
||||
console.log('임시:::::::::::::::::')
|
||||
router.push(`${pathname}/tempdetail?objectNo=${event.data.objectNo.toString()}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -175,45 +196,6 @@ export default function Stuff() {
|
||||
errCount++
|
||||
}
|
||||
})
|
||||
|
||||
async function fetchDelete(data) {
|
||||
console.log('물건삭제API호출!!!!!!!!!', data)
|
||||
//행추가말고 api데이터만 보냄
|
||||
// let newData = data.filter((item) => item.company != null)
|
||||
// console.log('삭제에 전송되는 데이타::', newData)
|
||||
// await del({ url: '', data:newData })
|
||||
await get({ url: 'https://www.ag-grid.com/example-assets/space-mission-data.json' })
|
||||
// try {
|
||||
// const res = await del({url:'', data:newData})
|
||||
|
||||
// if(!res || res.length === 0) {
|
||||
|
||||
// } else {
|
||||
fetchData()
|
||||
// }
|
||||
// } catch (error) {
|
||||
// console.error('Data Delete error:', error);
|
||||
// }
|
||||
}
|
||||
|
||||
// 삭제API 완료 후 fetchData Api호출
|
||||
async function fetchData() {
|
||||
console.log('물건삭제후 조회API호출!!!!!!!!!!!!!', stuffSearchParams)
|
||||
const data = await get({ url: 'https://www.ag-grid.com/example-assets/space-mission-data.json' })
|
||||
setGridProps({ ...gridProps, gridData: data, count: data.length })
|
||||
setGridCount(data.length)
|
||||
//data.length = 10
|
||||
//setGridProps({ ...gridProps, gridData: data, count: data.length-1})
|
||||
//setGridCount(data.length - 1 )
|
||||
}
|
||||
|
||||
if (errCount === 0) {
|
||||
// console.log('errCount::::::::', errCount)
|
||||
fetchDelete(data)
|
||||
// fetchData()
|
||||
} else {
|
||||
alert('물건정보가 있는 행만 선택해주세요')
|
||||
}
|
||||
}
|
||||
|
||||
//행추가
|
||||
@ -265,15 +247,14 @@ export default function Stuff() {
|
||||
schDateType: 'U',
|
||||
schFromDt: dayjs(new Date()).add(-1, 'year').format('YYYY-MM-DD'),
|
||||
schToDt: dayjs(new Date()).format('YYYY-MM-DD'),
|
||||
startRow: (curPage - 1) * size + 1,
|
||||
endRow: curPage * size,
|
||||
startRow: (curPage - 1) * defaultSize + 1,
|
||||
endRow: curPage * defaultSize,
|
||||
schSelSaleStoreId: '',
|
||||
schSortType: 'R',
|
||||
}
|
||||
|
||||
async function fetchData() {
|
||||
console.log('화면진입:::::::::::::', params)
|
||||
console.log('현재페이지::::::', curPage)
|
||||
console.log('페이지당 게시물수::::::', size)
|
||||
|
||||
//api에 넘길값 startRow, endRow
|
||||
// let startRow
|
||||
// let endRow
|
||||
@ -288,7 +269,8 @@ export default function Stuff() {
|
||||
// let size
|
||||
// let pageCount
|
||||
|
||||
const apiUrl = `/api/object/list?saleStoreId=201TES01&${queryStringFormatter(params)}`
|
||||
// const apiUrl = `/api/object/list?saleStoreId=201TES01&${queryStringFormatter(params)}`
|
||||
const apiUrl = `/api/object/list?saleStoreId=X167&${queryStringFormatter(params)}`
|
||||
|
||||
await get({
|
||||
url: apiUrl,
|
||||
@ -306,14 +288,21 @@ export default function Stuff() {
|
||||
|
||||
useEffect(() => {
|
||||
if (stuffSearchParams?.code === 'E') {
|
||||
stuffSearchParams.startRow = (curPage - 1) * defaultSize + 1
|
||||
stuffSearchParams.endRow = curPage * defaultSize
|
||||
stuffSearchParams.schSortType = defaultSortType
|
||||
console.log('조회 눌럿을때 ::::::::::::::', stuffSearchParams)
|
||||
async function fetchData() {
|
||||
const apiUrl = `/api/object/list?saleStoreId=201TES01&${queryStringFormatter(stuffSearchParams)}`
|
||||
// const apiUrl = `/api/object/list?saleStoreId=201TES01&${queryStringFormatter(stuffSearchParams)}`
|
||||
const apiUrl = `/api/object/list?saleStoreId=X167&${queryStringFormatter(stuffSearchParams)}`
|
||||
await get({ url: apiUrl }).then((res) => {
|
||||
console.log('API결과:::::::', res)
|
||||
if (!isEmptyArray(res)) {
|
||||
setGridProps({ ...gridProps, gridData: res, count: res.length })
|
||||
setGridCount(res.length)
|
||||
} else {
|
||||
setGridProps({ ...gridProps, gridData: [], count: 0 })
|
||||
setGridCount(0)
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -321,6 +310,58 @@ export default function Stuff() {
|
||||
}
|
||||
}, [stuffSearchParams])
|
||||
|
||||
//페이지 갯수 변경 이벤트
|
||||
const onChangePerPage = (e) => {
|
||||
let startRow = (curPage - 1) * e.target.value + 1
|
||||
stuffSearchParams.startRow = startRow
|
||||
stuffSearchParams.endRow = curPage * e.target.value
|
||||
setDefaultSize(e.target.value)
|
||||
setStuffSearch({
|
||||
...stuffSearch,
|
||||
code: 'S',
|
||||
startRow: startRow,
|
||||
endRow: curPage * e.target.value,
|
||||
})
|
||||
console.log('셋팅된 검색조건:::', stuffSearchParams)
|
||||
//조회API호출
|
||||
// const apiUrl = `/api/object/list?saleStoreId=201TES01&${queryStringFormatter(stuffSearchParams)}`
|
||||
const apiUrl = `/api/object/list?saleStoreId=X167&${queryStringFormatter(stuffSearchParams)}`
|
||||
get({ url: apiUrl }).then((res) => {
|
||||
console.log('보여줄개수바꿨을때 조회 ::::::::::', res)
|
||||
if (!isEmptyArray(res)) {
|
||||
setGridProps({ ...gridProps, gridData: res, count: res.length })
|
||||
setGridCount(res.length)
|
||||
} else {
|
||||
setGridProps({ ...gridProps, gridData: [], count: 0 })
|
||||
setGridCount(0)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
//최근 등록일 수정일 정렬 이벤트
|
||||
const onChangeSortType = (e) => {
|
||||
stuffSearchParams.schSortType = e.target.value
|
||||
console.log('셋팅된 검색조건:::', stuffSearchParams)
|
||||
setDefaultSortType(e.target.value)
|
||||
setStuffSearch({
|
||||
...stuffSearch,
|
||||
code: 'S',
|
||||
schSortType: e.target.value,
|
||||
})
|
||||
// const apiUrl = `/api/object/list?saleStoreId=201TES01&${queryStringFormatter(stuffSearchParams)}`
|
||||
const apiUrl = `/api/object/list?saleStoreId=X167&${queryStringFormatter(stuffSearchParams)}`
|
||||
// console.log('apiUrl::', apiUrl)
|
||||
get({ url: apiUrl }).then((res) => {
|
||||
console.log('정렬바꿨을때 조회 ::::::::::', res)
|
||||
if (!isEmptyArray(res)) {
|
||||
setGridProps({ ...gridProps, gridData: res, count: res.length })
|
||||
setGridCount(res.length)
|
||||
} else {
|
||||
setGridProps({ ...gridProps, gridData: [], count: 0 })
|
||||
setGridCount(0)
|
||||
}
|
||||
})
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<div className="text-2xl">
|
||||
@ -328,6 +369,15 @@ export default function Stuff() {
|
||||
<span>
|
||||
전체 : {gridCount} // 선택 : {selectedRowDataCount}
|
||||
</span>
|
||||
<select className="select" onChange={onChangePerPage}>
|
||||
<option value="100">100</option>
|
||||
<option value="200">200</option>
|
||||
<option value="300">300</option>
|
||||
</select>
|
||||
<select className="select" onChange={onChangeSortType}>
|
||||
<option value="R">최근 등록일</option>
|
||||
<option value="U">최근 수정일</option>
|
||||
</select>
|
||||
<div align="right">
|
||||
{/* <Button
|
||||
color="primary"
|
||||
|
||||
@ -4,13 +4,15 @@ import React, { useState, useEffect } from 'react'
|
||||
import { useRouter, useSearchParams } from 'next/navigation'
|
||||
import { Input, RadioGroup, Radio, Button, Autocomplete, AutocompleteItem, Select, SelectItem, Checkbox, Textarea, button } from '@nextui-org/react'
|
||||
import Link from 'next/link'
|
||||
import { get } from '@/lib/Axios'
|
||||
import { del, get, post } from '@/lib/Axios'
|
||||
import { queryStringFormatter, isEmptyArray } from '@/util/common-utils'
|
||||
import dayjs from 'dayjs'
|
||||
import { useMessage } from '@/hooks/useMessage'
|
||||
import { useForm } from 'react-hook-form'
|
||||
export default function StuffDetail() {
|
||||
const router = useRouter()
|
||||
const searchParams = useSearchParams()
|
||||
const { getMessage } = useMessage()
|
||||
|
||||
//form
|
||||
const formInitValue = {
|
||||
@ -22,8 +24,11 @@ export default function StuffDetail() {
|
||||
objectNameKana: '', //물건명 후리가나
|
||||
saleStoreId: '', //판매점ID
|
||||
saleStoreName: '', //판매점명
|
||||
otherSaleStoreId: '',
|
||||
otherSaleStoreName: '',
|
||||
zipNo: '', //우편번호
|
||||
prefId: '', //도도부현
|
||||
prefName: '',
|
||||
address: '', //주소
|
||||
powerSimArea: '', //발전량시뮬레이션지역
|
||||
windSpeed: '', //기준풍속
|
||||
@ -33,7 +38,7 @@ export default function StuffDetail() {
|
||||
saltAreaChk: false, //염해지역용아이템사용
|
||||
installHeight: '', //설치높이
|
||||
powerConTerms: '0', //계약조건(잉여 / 전량)
|
||||
remark: '', //메모
|
||||
remarks: '', //메모
|
||||
tempFlag: 'T', //임시저장(1) 저장(0)
|
||||
}
|
||||
const { register, setValue, getValues, handleSubmit, resetField, control, watch } = useForm({
|
||||
@ -44,66 +49,111 @@ export default function StuffDetail() {
|
||||
|
||||
const [prefCodeList, setPrefCodeList] = useState([]) //도도부현 코트 리스트
|
||||
const [prefValue, setPrefValue] = useState('')
|
||||
const [saleStoreList, setSaleStoreList] = useState([]) // 판매점 리스트
|
||||
const [otherSaleStoreList, setOtherSaleStoreList] = useState([])
|
||||
|
||||
const [receiveUser, setReceiveUser] = useState('') //담당자
|
||||
const [name2, setName2] = useState('') //물건명
|
||||
const [name3, setName3] = useState('') //물건명후리가나
|
||||
const [zipCode, setZipCode] = useState('') //우편번호
|
||||
const [name5, setName5] = useState('') //수직적설량
|
||||
const [gubun, setGubun] = useState('NEW') //신축 기축
|
||||
const [sel, setSel] = useState('') //경칭선택
|
||||
const [sel2, setSel2] = useState('') //발전량시뮬레이션지역
|
||||
const [sel3, setSel3] = useState('') //기준풍속
|
||||
const [sel4, setSel4] = useState('') //설치높이
|
||||
const [powerSimAreaList, setPowerSimAreaList] = useState([]) //발전시뮬레이션 리스트
|
||||
|
||||
const [errors, setErrors] = useState({})
|
||||
const [isFormValid, setIsFormValid] = useState(false) //임시저장, 진짜저장 버튼 컨트롤
|
||||
const [testSelOption, setTestSelOption] = useState([]) // 테스트용
|
||||
const [autoSelectValue, setAutoSelectValue] = useState('') //판매점명 자동완성
|
||||
const [buttonValid, setButtonValid] = useState(false) //주소검색 활성화 컨트롤
|
||||
const [isSelected, setIsSelected] = useState(false) //한랭지대첵 체크박스
|
||||
const [isSelected2, setIsSelected2] = useState(false) //염해지역용아이템사용 체크박스
|
||||
const [gubun2, setGubun2] = useState('1') //면조도구분 라디오
|
||||
const [gubun3, setGubun3] = useState('A') //계약조건 라디오
|
||||
const [memo, setMemo] = useState('') //메모
|
||||
const objectNo = searchParams.get('objectNo') //url에서 물건번호 꺼내서 바로 set
|
||||
|
||||
// const [address1, setAddress1] = useState('') //우편API리턴 도도부현명
|
||||
// const [address2, setAddress2] = useState('') //우편API리턴 시구정촌명
|
||||
// const [address3, setAddress3] = useState('') //우편API리턴 마을 지역명
|
||||
// const [prefCode, setPrefCode] = useState(1) //우편API prefcode
|
||||
|
||||
const [editMode, setEditMode] = useState('NEW')
|
||||
const [detailData, setDetailData] = useState({})
|
||||
|
||||
useEffect(() => {
|
||||
get({ url: '/api/object/prefecture/list' }).then((res) => {
|
||||
if (!isEmptyArray(res)) {
|
||||
console.log('도도부현API 결과:::', res)
|
||||
setPrefCodeList(res)
|
||||
}
|
||||
})
|
||||
// console.log('상세화면진입:::::::::', searchParams.get('objectNo'))
|
||||
// console.log('물건번호::::', objectNo)
|
||||
|
||||
if (objectNo) {
|
||||
console.log('수정화면')
|
||||
setEditMode('EDIT')
|
||||
|
||||
if (objectNo.substring(0, 1) === 'R') {
|
||||
//진짜
|
||||
setIsFormValid(true)
|
||||
}
|
||||
get({ url: `/api/object/${objectNo}/detail` }).then((res) => {
|
||||
// console.log('물건번호로 상세 API 호출')
|
||||
if (res != null) {
|
||||
// console.log('res:::::::', res)
|
||||
// console.log('상세res:::::::', res)
|
||||
setDetailData(res)
|
||||
|
||||
// 신규 상세 공통APi
|
||||
// 도도부현API
|
||||
get({ url: '/api/object/prefecture/list' }).then((res) => {
|
||||
if (!isEmptyArray(res)) {
|
||||
//console.log('도도부현API 결과:::', res)
|
||||
setPrefCodeList(res)
|
||||
}
|
||||
})
|
||||
// 판매점목록 API /api/object/saleStore/판매점코드/list - 판매점 목록 조회
|
||||
// 임시 1차점 판매점코드 saleStoreId=201TES01
|
||||
// T01
|
||||
//1차점 : X167
|
||||
get({ url: `/api/object/saleStore/X167/list` }).then((res) => {
|
||||
if (!isEmptyArray(res)) {
|
||||
console.log('판매점 결과:::::', res)
|
||||
setSaleStoreList(res)
|
||||
//1차 판매점 자동완성 값 셋팅
|
||||
form.setValue('saleStoreId', res[0].saleStoreId)
|
||||
//1차 판매점 번호 셋팅
|
||||
form.setValue('saleStoreName', res[0].saleStoreId)
|
||||
setOtherSaleStoreList([])
|
||||
}
|
||||
})
|
||||
} else {
|
||||
alert('삭제된 물건입니다')
|
||||
router.push('/management/stuff')
|
||||
}
|
||||
})
|
||||
} else {
|
||||
console.log('신규화면')
|
||||
// 신규 상세 공통APi
|
||||
// 도도부현API
|
||||
get({ url: '/api/object/prefecture/list' }).then((res) => {
|
||||
if (!isEmptyArray(res)) {
|
||||
//console.log('도도부현API 결과:::', res)
|
||||
setPrefCodeList(res)
|
||||
}
|
||||
})
|
||||
// 판매점목록 API /api/object/saleStore/판매점코드/list - 판매점 목록 조회
|
||||
// 임시 1차점 판매점코드 saleStoreId=201TES01
|
||||
// T01
|
||||
//1차점 : X167
|
||||
get({ url: `/api/object/saleStore/X167/list` }).then((res) => {
|
||||
if (!isEmptyArray(res)) {
|
||||
console.log('판매점 결과:::::', res)
|
||||
const firstList = res.filter((row) => row.saleStoreLevel === '1')
|
||||
const otherList = res.filter((row) => row.saleStoreLevel !== '1')
|
||||
console.log('first:::::', firstList)
|
||||
console.log('otherList:::::', otherList)
|
||||
//1차점 셀렉트박스
|
||||
setSaleStoreList(firstList)
|
||||
//1차 판매점 자동완성 값 셋팅
|
||||
form.setValue('saleStoreId', firstList[0].saleStoreId)
|
||||
//1차 판매점 번호 셋팅
|
||||
form.setValue('saleStoreName', firstList[0].saleStoreId)
|
||||
|
||||
//1차점 아닌 판매점 셀렉트박스
|
||||
setOtherSaleStoreList(otherList)
|
||||
}
|
||||
})
|
||||
}
|
||||
}, [objectNo])
|
||||
|
||||
useEffect(() => {
|
||||
// validateForm()
|
||||
}, [receiveUser, name2, name3, gubun, sel, autoSelectValue, zipCode, sel2, sel3, name5, sel4])
|
||||
//1차점 변경 이벤트
|
||||
const onSelectionChange = (key) => {
|
||||
if (key == null) {
|
||||
form.setValue('saleStoreId', '')
|
||||
form.setValue('saleStoreName', '')
|
||||
} else {
|
||||
form.setValue('saleStoreId', key)
|
||||
form.setValue('saleStoreName', key)
|
||||
}
|
||||
}
|
||||
|
||||
//2차점 변경 이벤트
|
||||
const onSelectionChange2 = (key) => {
|
||||
console.log(key)
|
||||
}
|
||||
// 우편번호 숫자만 체크
|
||||
const _zipNo = watch('zipNo')
|
||||
useEffect(() => {
|
||||
@ -114,62 +164,87 @@ export default function StuffDetail() {
|
||||
}
|
||||
}, [_zipNo])
|
||||
|
||||
// 수직적설량 숫자만
|
||||
const textTypeHandler2 = (e) => {
|
||||
if (!e.target.value.match(/[^0-9]/g)) {
|
||||
setName5(e.target.value)
|
||||
}
|
||||
}
|
||||
const validateForm = () => {
|
||||
let errors = {}
|
||||
//임시저장 저장 버튼 컨트롤
|
||||
// dispCompanyName: '', //담당자
|
||||
// objectName: '', //물건명
|
||||
// objectNameOmit: '', //경칭선택
|
||||
// saleStoreId: '', //판매점ID
|
||||
// zipNo: '', //우편번호
|
||||
// prefId: '', //도도부현
|
||||
// address: '', //주소
|
||||
// powerSimArea: '', //발전량시뮬레이션지역
|
||||
// windSpeed: '', //기준풍속
|
||||
// snowCover: '', //수직적설량
|
||||
// coldAreaChk: false, //한랭지대책시행
|
||||
// surfaceType: 'Ⅲ・Ⅳ', //면조도구분(Ⅲ・Ⅳ / Ⅱ)
|
||||
// saltAreaChk: false, //염해지역용아이템사용
|
||||
// installHeight: '', //설치높이
|
||||
// powerConTerms: '0', //계약조건(잉여 / 전량)
|
||||
// remarks: '', //메모
|
||||
// tempFlag: 'T', //임시저장(1) 저장(0)
|
||||
const _dispCompanyName = watch('dispCompanyName')
|
||||
const _objectName = watch('objectName')
|
||||
const _objectNameOmit = watch('objectNameOmit')
|
||||
const _saleStoreId = watch('saleStoreId')
|
||||
const _prefId = watch('prefId')
|
||||
const _address = watch('address')
|
||||
const _powerSimArea = watch('powerSimArea')
|
||||
const _windSpeed = watch('windSpeed')
|
||||
const _snowCover = watch('snowCover')
|
||||
const _installHeight = watch('installHeight')
|
||||
useEffect(() => {
|
||||
// console.log('mode:::::', editMode)
|
||||
if (editMode === 'NEW') {
|
||||
const formData = form.getValues()
|
||||
// console.log('폼::::::::::::', formData)
|
||||
let errors = {}
|
||||
if (!_dispCompanyName || _dispCompanyName.trim().length === 0) {
|
||||
errors.dispCompanyName = true
|
||||
}
|
||||
if (!_objectName || _objectName.trim().length === 0) {
|
||||
errors.objectName = true
|
||||
}
|
||||
if (!_objectNameOmit) {
|
||||
errors.objectNameOmit = true
|
||||
}
|
||||
if (!_saleStoreId) {
|
||||
errors.saleStoreId = true
|
||||
}
|
||||
|
||||
if (!receiveUser || receiveUser.trim().length === 0) {
|
||||
errors.receiveUser = '담당자 is required.'
|
||||
}
|
||||
if (!_zipNo || _zipNo.length != 7) {
|
||||
errors.zipCode = true
|
||||
}
|
||||
|
||||
if (!name2 || name2.trim().length === 0) {
|
||||
errors.name2 = '물건명 is required.'
|
||||
}
|
||||
if (!_prefId) {
|
||||
errors.prefId = true
|
||||
}
|
||||
|
||||
if (!name3 || name3.trim().length === 0) {
|
||||
errors.name3 = '물건명후리가나 is required.'
|
||||
}
|
||||
if (!_address.trim().length === 0) {
|
||||
errors.address = true
|
||||
}
|
||||
|
||||
if (!sel) {
|
||||
errors.sel = '경칭선택 is required'
|
||||
}
|
||||
if (!_powerSimArea) {
|
||||
errors.powerSimArea = true
|
||||
}
|
||||
|
||||
if (!sel2) {
|
||||
errors.sel2 = '발전량시뮬레이션지역 is required'
|
||||
}
|
||||
if (!_windSpeed) {
|
||||
errors.windSpeed = true
|
||||
}
|
||||
|
||||
if (!sel3) {
|
||||
errors.sel3 = '기준풍속 is required'
|
||||
}
|
||||
if (!_snowCover) {
|
||||
errors.snowCover = true
|
||||
}
|
||||
|
||||
if (!sel4) {
|
||||
errors.sel4 = '설치높이 is required'
|
||||
}
|
||||
if (!_installHeight) {
|
||||
errors.installHeight = true
|
||||
}
|
||||
|
||||
if (!autoSelectValue) {
|
||||
errors.autoSelectValue = '판매점ID자동완성 is required'
|
||||
}
|
||||
|
||||
if (!zipCode || zipCode.length != 7) {
|
||||
errors.zipCode = '우편번호 is required.'
|
||||
setButtonValid(true)
|
||||
// console.log('errors::', errors)
|
||||
setIsFormValid(Object.keys(errors).length === 0)
|
||||
} else {
|
||||
setButtonValid(false)
|
||||
// console.log('상세일때 폼체크')
|
||||
}
|
||||
|
||||
if (!name5) {
|
||||
errors.name5 = '수직적설량 is required.'
|
||||
}
|
||||
|
||||
console.log('errors::', errors)
|
||||
setErrors(errors)
|
||||
setIsFormValid(Object.keys(errors).length === 0)
|
||||
}
|
||||
}, [_dispCompanyName, _objectName, _objectNameOmit, _saleStoreId, _zipNo, _prefId, _address, _powerSimArea, _windSpeed, _snowCover, _installHeight])
|
||||
|
||||
// 주소검색 API
|
||||
const onSearchPostNumber = () => {
|
||||
@ -178,22 +253,25 @@ export default function StuffDetail() {
|
||||
}
|
||||
get({ url: `https://zipcloud.ibsnet.co.jp/api/search?${queryStringFormatter(params)}` }).then((res) => {
|
||||
//7830060
|
||||
//9302226
|
||||
if (res.status === 200) {
|
||||
console.log('res.results::', res.results)
|
||||
if (res.results != null) {
|
||||
console.log('res.results::', res.results)
|
||||
// prefId: '', //도도부현
|
||||
// address: '', //주소
|
||||
console.log('prefcode::', res.results[0].prefcode)
|
||||
console.log('address::', res.results[0].address2 + res.results[0].address3)
|
||||
// console.log('주소검색::', res.results)
|
||||
// console.log('prefcode::', res.results[0].prefcode)
|
||||
// console.log('address::', res.results[0].address2 + res.results[0].address3)
|
||||
setPrefValue(res.results[0].prefcode)
|
||||
form.setValue('prefId', res.results[0].prefcode)
|
||||
form.setValue('prefName', res.results[0].address1)
|
||||
form.setValue('address', res.results[0].address2 + res.results[0].address3)
|
||||
} else {
|
||||
alert('등록된 우편번호에서 주소를 찾을 수 없습니다. 다시 입력해주세요.')
|
||||
form.setValue('prefId', '')
|
||||
form.setValue('prefName', '')
|
||||
form.setValue('address', '')
|
||||
form.setValue('zipNo', '')
|
||||
setPrefValue('')
|
||||
setPowerSimAreaList([])
|
||||
form.setValue('powerSimArea', '')
|
||||
}
|
||||
} else {
|
||||
alert(res.message)
|
||||
@ -201,58 +279,118 @@ export default function StuffDetail() {
|
||||
})
|
||||
}
|
||||
|
||||
const onTempSave = () => {
|
||||
console.log('임시저장::', isFormValid)
|
||||
}
|
||||
|
||||
const onSave = () => {
|
||||
console.log('진짜저장isFormValid:::', isFormValid)
|
||||
}
|
||||
|
||||
const moveList = () => {
|
||||
router.push('/management/stuff')
|
||||
}
|
||||
|
||||
const changeAddress2 = (e) => {
|
||||
console.log('e:::::::', e.target.value)
|
||||
}
|
||||
useEffect(() => {
|
||||
if (prefValue !== '') {
|
||||
// console.log('우편번호 검색해서 도도부현골랐을때::::', prefValue)
|
||||
// 발전량시뮬레이션 지역 목록
|
||||
// /api/object/prefecture/도도부현코드/list
|
||||
get({ url: `/api/object/prefecture/${prefValue}/list` }).then((res) => {
|
||||
if (!isEmptyArray(res)) {
|
||||
// console.log('발전시뮬레이션::::::::', res)
|
||||
setPowerSimAreaList(res)
|
||||
}
|
||||
})
|
||||
}
|
||||
}, [prefValue])
|
||||
|
||||
//필수값 다 입력했을때
|
||||
const onValid = (data) => {
|
||||
console.log('data::::::', data)
|
||||
// 수정모드일때는 PUT
|
||||
// console.log('필수값 다 있고 저장')
|
||||
// console.log('data::::::', data)
|
||||
const formData = form.getValues()
|
||||
//console.log('formData::::', formData)
|
||||
const _dispCompanyName = watch('dispCompanyName')
|
||||
const _objectStatusId = watch('objectStatusId')
|
||||
const _objectNameOmit = watch('objectNameOmit')
|
||||
const _zipNo = watch('zipNo')
|
||||
const _prefId = watch('prefId')
|
||||
const _address = watch('address')
|
||||
const _coldAreaChk = watch('coldAreaChk')
|
||||
console.log(_dispCompanyName)
|
||||
console.log(_objectStatusId)
|
||||
console.log(_objectNameOmit)
|
||||
console.log(_zipNo)
|
||||
console.log(_prefId)
|
||||
console.log('prefValue::', prefValue)
|
||||
console.log(_address)
|
||||
console.log('_coldAreaChk::', _coldAreaChk)
|
||||
// console.log('formData::::', formData)
|
||||
// const _dispCompanyName = watch('dispCompanyName')
|
||||
// const _objectStatusId = watch('objectStatusId')
|
||||
// const _objectNameOmit = watch('objectNameOmit')
|
||||
// const _zipNo = watch('zipNo')
|
||||
// const _prefId = watch('prefId')
|
||||
// const _address = watch('address')
|
||||
// const _coldAreaChk = watch('coldAreaChk')
|
||||
// console.log(_dispCompanyName)
|
||||
// console.log(_objectStatusId)
|
||||
// console.log(_objectNameOmit)
|
||||
// console.log(_zipNo)
|
||||
// console.log(_prefId)
|
||||
// console.log('prefValue::', prefValue)
|
||||
// console.log(_address)
|
||||
// console.log('_coldAreaChk::', _coldAreaChk)
|
||||
}
|
||||
|
||||
//필수값 안넣었을때
|
||||
const onInvalid = (errors) => {
|
||||
console.log('실패', errors)
|
||||
//필수값 안넣었을때 임시저장 form required사용시
|
||||
// const onInvalid = (errors) => {
|
||||
// console.log('22222222222222222222222')
|
||||
// const formData = form.getValues()
|
||||
// console.log('임시저장formData::::', formData)
|
||||
// }
|
||||
|
||||
// 임시저장
|
||||
const onTempSave = async () => {
|
||||
const formData = form.getValues()
|
||||
//console.log('임시저장::::::::', formData)
|
||||
|
||||
const params = {
|
||||
saleStoreId: formData.saleStoreId,
|
||||
saleStoreName: formData.saleStoreName,
|
||||
objectStatusId: formData.objectStatusId,
|
||||
objectName: formData.objectName,
|
||||
objectNameOmit: formData.objectNameOmit,
|
||||
objectNameKana: formData.objectNameKana,
|
||||
zipNo: formData.zipNo,
|
||||
prefId: formData.prefId,
|
||||
prefName: formData.prefName,
|
||||
address: formData.address,
|
||||
powerSimArea: formData.powerSimArea,
|
||||
receiveUser: formData.dispCompanyName,
|
||||
installHeight: formData.installHeight,
|
||||
windSpeed: formData.windSpeed,
|
||||
snowCover: formData.snowCover,
|
||||
surfaceType: formData.surfaceType,
|
||||
powerConTerms: formData.powerConTerms,
|
||||
saltAreaChk: formData.saltAreaChk,
|
||||
coldAreaChk: formData.coldAreaChk,
|
||||
tempFlg: '1',
|
||||
workNo: null,
|
||||
workName: null,
|
||||
}
|
||||
console.log('임시저장params::', params)
|
||||
return
|
||||
await post({ url: '/api/object/save-object', data: params }).then((res) => {
|
||||
console.log('res::::::', res)
|
||||
})
|
||||
}
|
||||
|
||||
// 발전량 시뮬레이션 변경
|
||||
const handlePowerSimAreaOnChange = (e) => {
|
||||
// console.log('가지고있는 도도부현코드:::::::::', prefValue)
|
||||
// console.log('발전량시뮬레이션변경:::::::::', e.target.value)
|
||||
//값 set해주고 그거 useEffect로 api호출
|
||||
}
|
||||
|
||||
// 물건삭제
|
||||
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')
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{(editMode === 'NEW' && (
|
||||
<form onSubmit={handleSubmit(onValid, onInvalid)}>
|
||||
<form onSubmit={handleSubmit(onValid)}>
|
||||
<div>
|
||||
<div>(*필수 입력항목)</div>
|
||||
<div className="form-input">
|
||||
<label>담당자*</label>
|
||||
<input type="text" className="input-origin" {...form.register('dispCompanyName', { required: true })} />
|
||||
<input type="text" className="input-origin" {...form.register('dispCompanyName')} />
|
||||
</div>
|
||||
<div className="form-input">
|
||||
<label>물건구분/물건명*</label>
|
||||
@ -260,9 +398,9 @@ export default function StuffDetail() {
|
||||
<label htmlFor="objectStatus0">신축</label>
|
||||
<input type="radio" name="objectStatusId" value="1" id="objectStatus1" {...form.register('objectStatusId')} />
|
||||
<label htmlFor="objectStatus0">기축</label>
|
||||
<input type="text" className="input-origin" {...form.register('objectName', { required: true })} />
|
||||
<input type="text" className="input-origin" {...form.register('objectName')} />
|
||||
<div className="flex w-full max-w-xs flex-col gap-2">
|
||||
<select name="objectNameOmit" {...register('objectNameOmit', { required: true })}>
|
||||
<select name="objectNameOmit" {...register('objectNameOmit')}>
|
||||
<option value="">경칭선택</option>
|
||||
<option value="11">111</option>
|
||||
<option value="22">222</option>
|
||||
@ -272,13 +410,41 @@ export default function StuffDetail() {
|
||||
</div>
|
||||
<div className="form-input">
|
||||
<label>물건명 후리가나</label>
|
||||
<input type="text" className="input-origin" {...form.register('objectNameKana', { required: true })} />
|
||||
<input type="text" className="input-origin" {...form.register('objectNameKana')} />
|
||||
</div>
|
||||
<div className="form-input">
|
||||
<label>1차 판매점명 / ID</label>
|
||||
<div className="flex w-full max-w-xs flex-col gap2">
|
||||
{saleStoreList?.length > 0 && (
|
||||
<Autocomplete
|
||||
className="max-w-xs"
|
||||
defaultItems={saleStoreList}
|
||||
label="판매점ID자동완성"
|
||||
selectedKey={form.watch('saleStoreId')}
|
||||
{...form.register('saleStoreId')}
|
||||
onSelectionChange={onSelectionChange}
|
||||
>
|
||||
{(option) => <AutocompleteItem key={option.saleStoreId}>{option.saleStoreName}</AutocompleteItem>}
|
||||
</Autocomplete>
|
||||
)}
|
||||
<input type="text" className="input-origin" value={form.watch('saleStoreName')} {...form.register('saleStoreName')} disabled />
|
||||
</div>
|
||||
</div>
|
||||
<div className="form-input">
|
||||
<label>2차 판매점명 / ID</label>
|
||||
<div className="flex w-full max-w-xs flex-col gap2">
|
||||
{otherSaleStoreList?.length > 0 && (
|
||||
<Autocomplete
|
||||
className="max-w-xs"
|
||||
defaultItems={otherSaleStoreList}
|
||||
label="2차판매점ID자동완성"
|
||||
{...form.register('otherSaleStoreId')}
|
||||
onSelectionChange={onSelectionChange2}
|
||||
>
|
||||
{(option) => <AutocompleteItem key={option.saleStoreId}>{option.saleStoreName}</AutocompleteItem>}
|
||||
</Autocomplete>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="form-input">
|
||||
<label>우편번호</label>
|
||||
@ -287,7 +453,6 @@ export default function StuffDetail() {
|
||||
className="input-origin"
|
||||
maxLength={7}
|
||||
{...form.register('zipNo', {
|
||||
required: true,
|
||||
minLength: { value: 7, message: '7자리만가능' },
|
||||
pattern: { value: /^[0-9]*$/g, message: '숫자만 입력' },
|
||||
})}
|
||||
@ -301,7 +466,7 @@ export default function StuffDetail() {
|
||||
<label>도도부현 / 주소</label>
|
||||
<div className="flex w-full flex-wrap items-end md:flex-nowrap mb-6 md:mb-0 gap-4">
|
||||
{prefCodeList?.length > 0 && (
|
||||
<Select className="max-w-xs" selectedKeys={prefValue} isDisabled {...form.register('prefId', { required: true })}>
|
||||
<Select className="max-w-xs" selectedKeys={prefValue} isDisabled {...form.register('prefId')}>
|
||||
{prefCodeList.map((row) => {
|
||||
return <SelectItem key={row.prefId}>{row.prefName}</SelectItem>
|
||||
})}
|
||||
@ -313,9 +478,34 @@ export default function StuffDetail() {
|
||||
</div>
|
||||
<div className="form-input">
|
||||
<label>발전량시뮬레이션지역</label>
|
||||
{powerSimAreaList?.length > 0 && (
|
||||
<Select
|
||||
className="max-w-xs"
|
||||
selectedKeys={form.watch('powerSimArea')}
|
||||
{...form.register('powerSimArea')}
|
||||
onChange={handlePowerSimAreaOnChange}
|
||||
>
|
||||
{powerSimAreaList.map((row) => {
|
||||
// console.log('row::', row)
|
||||
return (
|
||||
<SelectItem key={row.prefName} value={row.prefId}>
|
||||
{row.prefName}
|
||||
</SelectItem>
|
||||
)
|
||||
})}
|
||||
</Select>
|
||||
)}
|
||||
</div>
|
||||
<div className="form-input">
|
||||
<label>기준풍속</label>
|
||||
<div className="flex w-full max-w-xs flex-col gap-2">
|
||||
<select name="windSpeed" {...register('windSpeed')}>
|
||||
<option value="">기준풍속</option>
|
||||
<option value="30">30</option>
|
||||
<option value="50">50</option>
|
||||
<option value="60">60</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div className="form-input">
|
||||
<label>수직적설량</label>
|
||||
@ -324,7 +514,6 @@ export default function StuffDetail() {
|
||||
className="input-origin"
|
||||
maxLength={3}
|
||||
{...form.register('snowCover', {
|
||||
required: true,
|
||||
pattern: { value: /^[0-9]*$/g, message: '정수만 입력' },
|
||||
})}
|
||||
/>{' '}
|
||||
@ -354,7 +543,15 @@ export default function StuffDetail() {
|
||||
</Checkbox>
|
||||
</div>
|
||||
<div className="form-input">
|
||||
<label>설치높이 installHeight</label>
|
||||
<label>설치높이</label>
|
||||
<div className="flex w-full max-w-xs flex-col gap-2">
|
||||
<select name="installHeight" {...register('installHeight')}>
|
||||
<option value="">설치높이</option>
|
||||
<option value="11">111</option>
|
||||
<option value="22">222</option>
|
||||
<option value="33">333</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div className="form-input">
|
||||
<label>계약조건</label>
|
||||
@ -371,195 +568,49 @@ export default function StuffDetail() {
|
||||
base: 'max-w-xs',
|
||||
input: 'resize-y min-h-[40px]',
|
||||
}}
|
||||
{...form.register('remark')}
|
||||
{...form.register('remarks')}
|
||||
onValueChange={(e) => {
|
||||
// console.log('e::::', e)
|
||||
form.setValue('remark', e)
|
||||
form.setValue('remarks', e)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit">신규화면임시저장!!!!!!!!!</button>
|
||||
{!isFormValid ? (
|
||||
<>
|
||||
<Button type="submit" onClick={onTempSave}>
|
||||
NEW화면임시저장
|
||||
</Button>
|
||||
</>
|
||||
) : (
|
||||
<button type="submit">NEW화면 저장</button>
|
||||
)}
|
||||
<Link href="/management/stuff">
|
||||
<button type="button">NEW화면 물건목록이동</button>
|
||||
</Link>
|
||||
</form>
|
||||
)) || <div>상세:::::::::::</div>}
|
||||
|
||||
{/* <div className="flex w-full flex-wrap md:flex-nowrap gap-4">
|
||||
<div>
|
||||
<span>물건번호</span>
|
||||
<span>{objectNo}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>사양확정일</span>
|
||||
<span>{detailData?.specDate ? dayjs(detailData.specDate).format('YYYY.MM.DD') : null}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>갱신일시</span>
|
||||
<span>
|
||||
{detailData?.lastEditDatetime
|
||||
? dayjs(detailData.lastEditDatetime).format('YYYY.MM.DD HH:mm:ss')
|
||||
: detailData?.createDatetime
|
||||
? dayjs(detailData.createDatetime).format('YYYY.MM.DD HH:mm:ss')
|
||||
: null}
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>등록일</span>
|
||||
<span></span>
|
||||
</div>
|
||||
</div> */}
|
||||
{/* <div>(*필수 입력항목)</div>
|
||||
|
||||
<div>
|
||||
<input type="text" placeholder="물건명" value={name2} onChange={(e) => setName2(e.target.value)} />
|
||||
</div>
|
||||
<div className="flex w-full max-w-xs flex-col gap-2">
|
||||
<Select label="경칭선택" className="max-w-xs" onChange={(e) => setSel(e.target.value)}>
|
||||
<SelectItem key="1">111</SelectItem>
|
||||
<SelectItem key="2">222</SelectItem>
|
||||
<SelectItem key="3">333</SelectItem>
|
||||
</Select>
|
||||
</div>
|
||||
<div>
|
||||
<span>물건명 후리가나</span>
|
||||
<input type="text" placeholder="물건명 후리가나" value={name3} onChange={(e) => setName3(e.target.value)} />
|
||||
</div>
|
||||
</div> */}
|
||||
{/* <div>
|
||||
<span>판매점명 /ID *</span>
|
||||
<div className="flex w-full max-w-xs flex-col gap-2">
|
||||
<Autocomplete
|
||||
className="max-w-xs"
|
||||
defaultItems={testSelOption}
|
||||
label="판매점ID자동완성으로 바꾸기"
|
||||
selectedKey={autoSelectValue}
|
||||
onSelectionChange={setAutoSelectValue}
|
||||
>
|
||||
{(option) => <AutocompleteItem key={option.id}>{option.name}</AutocompleteItem>}
|
||||
</Autocomplete>
|
||||
</div>
|
||||
</div> */}
|
||||
{/* <div>
|
||||
<span>우편번호*</span>
|
||||
<input type="text" placeholder="숫자7자리 입력여부 체크" value={zipCode} maxLength="7" onChange={textTypeHandler} />
|
||||
<Button onClick={onSearchPostNumber} isDisabled={buttonValid}>
|
||||
주소검색
|
||||
</Button>
|
||||
*우편번호 7자리를 입력한 후, 주소검색 버튼을 클릭해 주십시오
|
||||
</div> */}
|
||||
{/* <div>
|
||||
<span>도도부현 / 주소*</span>
|
||||
<input type="text" placeholder="주소검색 결과 주소 셋팅 칸" value={address2 + address3} onChange={changeAddress2} />
|
||||
</div> */}
|
||||
{/* <div>
|
||||
<span>발전량시뮬레이션지역*</span>
|
||||
<Select label="발전량시뮬레이션지역" className="max-w-xs" onChange={(e) => setSel2(e.target.value)}>
|
||||
<SelectItem key="1">111</SelectItem>
|
||||
<SelectItem key="2">222</SelectItem>
|
||||
<SelectItem key="3">333</SelectItem>
|
||||
</Select>
|
||||
</div>
|
||||
<div>
|
||||
<span>기준풍속*</span>
|
||||
<Select label="기준풍속" className="max-w-xs" onChange={(e) => setSel3(e.target.value)}>
|
||||
<SelectItem key="1">111</SelectItem>
|
||||
<SelectItem key="2">222</SelectItem>
|
||||
<SelectItem key="3">333</SelectItem>
|
||||
</Select>
|
||||
m/s이하
|
||||
</div>
|
||||
<div>
|
||||
<span>수직적설량*</span>
|
||||
<input type="text" placeholder="수직적설량" value={name5} maxLength="3" onChange={textTypeHandler2} /> cm
|
||||
<Checkbox isSelected={isSelected} onValueChange={setIsSelected}>
|
||||
한랭지대책시행
|
||||
</Checkbox>
|
||||
</div> */}
|
||||
{/* <div>
|
||||
<span>면조도구분*</span>
|
||||
<input
|
||||
type="radio"
|
||||
name="radio_gubun2"
|
||||
id="radio_1"
|
||||
value={'1'}
|
||||
checked={gubun2 === '1' ? true : false}
|
||||
onChange={(e) => {
|
||||
setGubun2(e.target.value)
|
||||
}}
|
||||
/>
|
||||
<label htmlFor="radio_1">III·IV</label>
|
||||
<input
|
||||
type="radio"
|
||||
name="radio_gubun2"
|
||||
id="radio_2"
|
||||
value={'2'}
|
||||
checked={gubun2 === '2' ? true : false}
|
||||
onChange={(e) => {
|
||||
setGubun2(e.target.value)
|
||||
}}
|
||||
/>
|
||||
<label htmlFor="radio_2">II</label>
|
||||
<Checkbox isSelected={isSelected2} onValueChange={setIsSelected2}>
|
||||
염해지역용아이템사용
|
||||
</Checkbox>
|
||||
</div>
|
||||
<div>
|
||||
<span>설치높이*</span>
|
||||
<Select label="설치높이" className="max-w-xs" onChange={(e) => setSel4(e.target.value)}>
|
||||
<SelectItem key="1">111</SelectItem>
|
||||
<SelectItem key="2">222</SelectItem>
|
||||
<SelectItem key="3">333</SelectItem>
|
||||
</Select>
|
||||
m
|
||||
</div>
|
||||
<div>
|
||||
<span>계약조건</span>
|
||||
<input
|
||||
type="radio"
|
||||
name="radio_gubun3"
|
||||
id="radio_a"
|
||||
value={'A'}
|
||||
checked={gubun3 === 'A' ? true : false}
|
||||
onChange={(e) => {
|
||||
setGubun3(e.target.value)
|
||||
}}
|
||||
/>
|
||||
<label htmlFor="radio_a">잉여</label>
|
||||
<input
|
||||
type="radio"
|
||||
name="radio_gubun3"
|
||||
id="radio_b"
|
||||
value={'B'}
|
||||
checked={gubun3 === 'B' ? true : false}
|
||||
onChange={(e) => {
|
||||
setGubun3(e.target.value)
|
||||
}}
|
||||
/>
|
||||
<label htmlFor="radio_2">전량</label>
|
||||
</div>
|
||||
<div>
|
||||
<span>메모</span>
|
||||
<Textarea
|
||||
value={memo}
|
||||
onValueChange={setMemo}
|
||||
disableAutosize
|
||||
classNames={{
|
||||
base: 'max-w-xs',
|
||||
input: 'resize-y min-h-[40px]',
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{!isFormValid ? (
|
||||
)) || (
|
||||
<>
|
||||
<Button onClick={onTempSave}>임시저장</Button>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Button onClick={onSave}>진짜저장</Button>
|
||||
{objectNo.substring(0, 1) === 'R' ? (
|
||||
<>
|
||||
<Link href="/management/stuff">
|
||||
<button type="button">R상세:물건목록</button>
|
||||
</Link>
|
||||
<button type="submit">R상세:저장</button>
|
||||
<button type="submit" onClick={onDelete}>
|
||||
R상세:물건삭제
|
||||
</button>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Link href="/management/stuff">
|
||||
<button type="button">T상세:물건목록</button>
|
||||
</Link>
|
||||
<button type="submit">T상세:저장</button>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
<Link href="/management/stuff">
|
||||
<button type="button">물건목록</button>
|
||||
</Link> */}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@ -2,10 +2,12 @@
|
||||
|
||||
import React, { useEffect } from 'react'
|
||||
import { useState } from 'react'
|
||||
import { Input, RadioGroup, Radio, Button } from '@nextui-org/react'
|
||||
import { Input, RadioGroup, Radio, Button, Autocomplete, AutocompleteItem } from '@nextui-org/react'
|
||||
import RangeDatePicker from '@/components/common/datepicker/RangeDatePicker'
|
||||
import { useRecoilState, useResetRecoilState } from 'recoil'
|
||||
import { stuffSearchState } from '@/store/stuffAtom'
|
||||
import { isEmptyArray } from '@/util/common-utils'
|
||||
import { get } from '@/lib/Axios'
|
||||
import dayjs from 'dayjs'
|
||||
import isLeapYear from 'dayjs/plugin/isLeapYear' // 윤년 판단 플러그인
|
||||
dayjs.extend(isLeapYear)
|
||||
@ -33,13 +35,16 @@ export default function StuffSearchCondition() {
|
||||
const [receiveUser, setReceiveUser] = useState('') //담당자
|
||||
const [dispCompanyName, setDispCompanyName] = useState('') //견적처
|
||||
const [dateType, setDateType] = useState('U') //갱신일(U)/등록일(R)
|
||||
const [schSelSaleStoreId, setSchSelSaleStoreId] = useState('') //판매대리점 선택
|
||||
|
||||
const [schSelSaleStoreList, setSchSelSaleStoreList] = useState([]) //판매대리점 자동완성 SELECT
|
||||
// 조회
|
||||
const onSubmit = () => {
|
||||
let diff = dayjs(endRangeDate).diff(startRangeDate, 'day')
|
||||
if (diff > 366) {
|
||||
return alert('최대1년 조회 가능합니다.')
|
||||
}
|
||||
|
||||
setStuffSearch({
|
||||
schObjectNo: stuffSearch?.schObjectNo ? stuffSearch.schObjectNo : objectNo,
|
||||
schSaleStoreId: stuffSearch?.schSaleStoreId ? stuffSearch.schSaleStoreId : saleStoreId,
|
||||
@ -53,6 +58,10 @@ export default function StuffSearchCondition() {
|
||||
schFromDt: dayjs(startRangeDate).format('YYYY-MM-DD'),
|
||||
schToDt: dayjs(endRangeDate).format('YYYY-MM-DD'),
|
||||
code: 'E',
|
||||
schSelSaleStoreId: stuffSearch?.schSelSaleStoreId ? stuffSearch.schSelSaleStoreId : schSelSaleStoreId,
|
||||
startRow: stuffSearch?.startRow ? stuffSearch.startRow : 1,
|
||||
endRow: stuffSearch?.endRow ? stuffSearch.endRow : 100,
|
||||
schSortType: stuffSearch?.schSortType ? stuffSearch.schSortType : 'R',
|
||||
})
|
||||
}
|
||||
|
||||
@ -68,9 +77,31 @@ export default function StuffSearchCondition() {
|
||||
setDispCompanyName('')
|
||||
setDateType('U')
|
||||
setDateRange([dayjs(new Date()).add(-1, 'year').format('YYYY-MM-DD'), dayjs(new Date()).format('YYYY-MM-DD')])
|
||||
setSchSelSaleStoreId('')
|
||||
resetStuffRecoil()
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
get({ url: `/api/object/saleStore/201TES01/list` }).then((res) => {
|
||||
if (!isEmptyArray(res)) {
|
||||
// console.log('판매점 결과:::::', res)
|
||||
setSchSelSaleStoreList(res)
|
||||
}
|
||||
})
|
||||
}, [])
|
||||
|
||||
//판매대리점 자동완성 변경
|
||||
const onSelectionChange = (key) => {
|
||||
// console.log('자동완성값변경', key)
|
||||
if (key == null) {
|
||||
setSchSelSaleStoreId('')
|
||||
setStuffSearch({ ...stuffSearch, schSelSaleStoreId: '' })
|
||||
} else {
|
||||
setSchSelSaleStoreId(key)
|
||||
setStuffSearch({ ...stuffSearch, schSelSaleStoreId: key })
|
||||
}
|
||||
}
|
||||
|
||||
//x로 날짜 비웠을때 기본값으로 셋팅
|
||||
useEffect(() => {
|
||||
if (!startRangeDate && !endRangeDate) {
|
||||
@ -88,7 +119,7 @@ export default function StuffSearchCondition() {
|
||||
return (
|
||||
<>
|
||||
<div align="right">
|
||||
<Link href="/management/stuff/detail">
|
||||
<Link href="/management/stuff/tempdetail">
|
||||
<button type="button">물건신규등록</button>
|
||||
</Link>
|
||||
<Button size="sm" onClick={onSubmit}>
|
||||
@ -126,10 +157,10 @@ export default function StuffSearchCondition() {
|
||||
<input
|
||||
type="text"
|
||||
placeholder="물건주소 입력"
|
||||
value={stuffSearch?.address ? stuffSearch.address : address}
|
||||
value={stuffSearch?.schAddress ? stuffSearch.schAddress : address}
|
||||
onChange={(e) => {
|
||||
setAddress(e.target.value)
|
||||
setStuffSearch({ ...stuffSearch, code: 'S', address: e.target.value })
|
||||
setStuffSearch({ ...stuffSearch, code: 'S', schAddress: e.target.value })
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
@ -220,6 +251,17 @@ export default function StuffSearchCondition() {
|
||||
setStuffSearch({ ...stuffSearch, code: 'S', schDispCompanyName: e.target.value })
|
||||
}}
|
||||
/>
|
||||
{schSelSaleStoreList?.length > 0 && (
|
||||
<Autocomplete
|
||||
className="max-w-xs"
|
||||
label="판매대리점선택"
|
||||
defaultItems={schSelSaleStoreList}
|
||||
selectedKey={stuffSearch?.schSelSaleStoreId ? stuffSearch.schSelSaleStoreId : schSelSaleStoreId}
|
||||
onSelectionChange={onSelectionChange}
|
||||
>
|
||||
{(option) => <AutocompleteItem key={option.saleStoreId}>{option.saleStoreName}</AutocompleteItem>}
|
||||
</Autocomplete>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
} else {
|
||||
|
||||
5
src/components/ui/Loading.jsx
Normal file
5
src/components/ui/Loading.jsx
Normal file
@ -0,0 +1,5 @@
|
||||
import style from '@/components/ui/Loading.module.css'
|
||||
|
||||
export default function Loading() {
|
||||
return <span className={style.loader}></span>
|
||||
}
|
||||
35
src/components/ui/Loading.module.css
Normal file
35
src/components/ui/Loading.module.css
Normal file
@ -0,0 +1,35 @@
|
||||
.loader {
|
||||
position: relative;
|
||||
font-size: 48px;
|
||||
letter-spacing: 6px;
|
||||
}
|
||||
.loader:before {
|
||||
content: 'Loading';
|
||||
color: #fff;
|
||||
}
|
||||
.loader:after {
|
||||
content: '';
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background-color: #ff3d00;
|
||||
background-image: radial-gradient(circle 2px, #fff4 100%, transparent 0), radial-gradient(circle 1px, #fff3 100%, transparent 0);
|
||||
background-position:
|
||||
14px -4px,
|
||||
12px -1px;
|
||||
border-radius: 50%;
|
||||
position: absolute;
|
||||
margin: auto;
|
||||
top: -5px;
|
||||
right: 66px;
|
||||
transform-origin: center bottom;
|
||||
animation: fillBaloon 1s ease-in-out infinite alternate;
|
||||
}
|
||||
|
||||
@keyframes fillBaloon {
|
||||
0% {
|
||||
transform: scale(1);
|
||||
}
|
||||
100% {
|
||||
transform: scale(3);
|
||||
}
|
||||
}
|
||||
@ -38,6 +38,10 @@ export function useAxios() {
|
||||
.catch(console.error)
|
||||
}
|
||||
|
||||
const promiseGet = async ({ url }) => {
|
||||
return await getInstances(url).get(url)
|
||||
}
|
||||
|
||||
const post = async ({ url, data }) => {
|
||||
return await getInstances(url)
|
||||
.post(url, data)
|
||||
@ -70,5 +74,5 @@ export function useAxios() {
|
||||
.catch(console.error)
|
||||
}
|
||||
|
||||
return { get, post, promisePost, put, patch, del }
|
||||
return { get, promiseGet, post, promisePost, put, patch, del }
|
||||
}
|
||||
|
||||
@ -1,11 +1,13 @@
|
||||
import { useEffect, useRef } from 'react'
|
||||
import { useRecoilValue } from 'recoil'
|
||||
import { canvasState, stepState } from '@/store/canvasAtom'
|
||||
import { canvasState, currentMenuState } from '@/store/canvasAtom'
|
||||
import { fabric } from 'fabric'
|
||||
|
||||
export function useEvent() {
|
||||
const canvas = useRecoilValue(canvasState)
|
||||
const step = useRecoilValue(stepState)
|
||||
const currentMenu = useRecoilValue(currentMenuState)
|
||||
const keyboardEventListeners = useRef([])
|
||||
const mouseEventListeners = useRef([])
|
||||
|
||||
useEffect(() => {
|
||||
if (!canvas) {
|
||||
@ -16,47 +18,56 @@ export function useEvent() {
|
||||
canvas.off(key)
|
||||
}
|
||||
})
|
||||
removeAllKeyboardEventListeners()
|
||||
addEvent(step)
|
||||
}, [step])
|
||||
removeAllMouseEventListeners()
|
||||
removeAllDocumentEventListeners()
|
||||
addDefaultEvent()
|
||||
}, [currentMenu, canvas])
|
||||
|
||||
const addEvent = (step) => {
|
||||
const addDefaultEvent = () => {
|
||||
//default Event 추가
|
||||
canvas?.on('mouse:move', defaultMouseMoveEvent)
|
||||
addKeyboardEventListener('keydown', document, defaultKeyboardEvent)
|
||||
addCanvasMouseEventListener('mouse:move', defaultMouseMoveEvent)
|
||||
addCanvasMouseEventListener('mouse:out', defaultMouseOutEvent)
|
||||
addDocumentEventListener('keydown', document, defaultKeyboardEvent)
|
||||
}
|
||||
|
||||
if (step === 1) {
|
||||
canvas?.on('mouse:down', (e) => {
|
||||
canvas?.add(new fabric.Rect({ width: 100, height: 100, fill: 'red', left: e.pointer.x, top: e.pointer.y }))
|
||||
})
|
||||
addKeyboardEventListener('keydown', document, (e) => {
|
||||
if (e.key === 'Escape') {
|
||||
console.log(1111)
|
||||
}
|
||||
})
|
||||
} else if (step === 2) {
|
||||
canvas?.on('mouse:down', (e) => {
|
||||
canvas?.add(new fabric.Circle({ radius: 50, fill: 'blue', left: e.pointer.x, top: e.pointer.y }))
|
||||
})
|
||||
addKeyboardEventListener('keydown', document, (e) => {
|
||||
if (e.key === 'Escape') {
|
||||
console.log(2222)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
canvas?.on('mouse:down', (e) => {
|
||||
canvas?.add(new fabric.Triangle({ width: 100, height: 100, fill: 'green', left: e.pointer.x, top: e.pointer.y }))
|
||||
})
|
||||
addKeyboardEventListener('keydown', document, (e) => {
|
||||
if (e.key === 'Escape') {
|
||||
console.log(333)
|
||||
}
|
||||
})
|
||||
}
|
||||
const defaultMouseOutEvent = (e) => {
|
||||
removeMouseLine()
|
||||
}
|
||||
|
||||
const defaultMouseMoveEvent = (e) => {
|
||||
console.log('defaultMouseMoveEvent')
|
||||
removeMouseLine()
|
||||
// 가로선
|
||||
const pointer = canvas.getPointer(e.e)
|
||||
const horizontalLine = new fabric.Line([0, pointer.y, 2 * canvas.width, pointer.y], {
|
||||
stroke: 'red',
|
||||
strokeWidth: 1,
|
||||
selectable: false,
|
||||
name: 'mouseLine',
|
||||
})
|
||||
|
||||
// 세로선
|
||||
const verticalLine = new fabric.Line([pointer.x, 0, pointer.x, 2 * canvas.height], {
|
||||
stroke: 'red',
|
||||
strokeWidth: 1,
|
||||
selectable: false,
|
||||
name: 'mouseLine',
|
||||
})
|
||||
|
||||
// 선들을 캔버스에 추가합니다.
|
||||
canvas?.add(horizontalLine, verticalLine)
|
||||
|
||||
// 캔버스를 다시 그립니다.
|
||||
canvas?.renderAll()
|
||||
}
|
||||
|
||||
const removeMouseLine = () => {
|
||||
// 캔버스에서 마우스 선을 찾아 제거합니다.
|
||||
canvas
|
||||
?.getObjects()
|
||||
.filter((obj) => obj.name === 'mouseLine')
|
||||
.forEach((line) => {
|
||||
canvas?.remove(line)
|
||||
})
|
||||
}
|
||||
|
||||
const defaultKeyboardEvent = (e) => {
|
||||
@ -65,21 +76,42 @@ export function useEvent() {
|
||||
}
|
||||
}
|
||||
|
||||
const addCanvasMouseEventListener = (eventType, handler) => {
|
||||
canvas.on(eventType, handler)
|
||||
mouseEventListeners.current.push({ eventType, handler })
|
||||
}
|
||||
|
||||
const removeAllMouseEventListeners = () => {
|
||||
mouseEventListeners.current.forEach(({ eventType, handler }) => {
|
||||
canvas.off(eventType, handler)
|
||||
})
|
||||
mouseEventListeners.current.length = 0 // 배열 초기화
|
||||
}
|
||||
|
||||
/**
|
||||
* document 키보드 이벤트 임의로 직접 등록한 이벤트의 경우 remove가 안되기 때문에 이 함수를 통해서만 등록해야 함.
|
||||
* document 이벤트의 경우 이 함수를 통해서만 등록
|
||||
* @param eventType
|
||||
* @param element
|
||||
* @param handler
|
||||
*/
|
||||
function addKeyboardEventListener(eventType, element, handler) {
|
||||
const addDocumentEventListener = (eventType, element, handler) => {
|
||||
element.addEventListener(eventType, handler)
|
||||
keyboardEventListeners.current.push({ eventType, element, handler })
|
||||
}
|
||||
|
||||
function removeAllKeyboardEventListeners() {
|
||||
/**
|
||||
* document에 등록되는 event 제거
|
||||
*/
|
||||
const removeAllDocumentEventListeners = () => {
|
||||
keyboardEventListeners.current.forEach(({ eventType, element, handler }) => {
|
||||
element.removeEventListener(eventType, handler)
|
||||
})
|
||||
keyboardEventListeners.current.length = 0 // 배열 초기화
|
||||
}
|
||||
|
||||
return {
|
||||
addDocumentEventListener,
|
||||
addCanvasMouseEventListener,
|
||||
removeAllDocumentEventListeners,
|
||||
}
|
||||
}
|
||||
|
||||
43
src/hooks/useLine.js
Normal file
43
src/hooks/useLine.js
Normal file
@ -0,0 +1,43 @@
|
||||
import { useRecoilValue } from 'recoil'
|
||||
import { canvasState, fontSizeState } from '@/store/canvasAtom'
|
||||
|
||||
export const useLine = () => {
|
||||
const canvas = useRecoilValue(canvasState)
|
||||
const fontSize = useRecoilValue(fontSizeState)
|
||||
|
||||
const addLineText = (line) => {
|
||||
removeLineText(line)
|
||||
|
||||
const text = new fabric.Text(getLengthByLine(line).toFixed(0), {
|
||||
left: (line.x2 + line.x1) / 2,
|
||||
top: (line.y2 + line.y1) / 2,
|
||||
parent: line,
|
||||
name: 'lengthTxt',
|
||||
fontSize: fontSize,
|
||||
})
|
||||
|
||||
canvas?.add(text)
|
||||
}
|
||||
|
||||
const removeLineText = (line) => {
|
||||
canvas?.remove(canvas?.getObjects().find((obj) => obj.parent === line))
|
||||
}
|
||||
|
||||
const getLengthByLine = (line) => {
|
||||
const scaleX = line.scaleX
|
||||
const scaleY = line.scaleY
|
||||
const x1 = line.left
|
||||
const y1 = line.top
|
||||
const x2 = line.left + line.width * scaleX
|
||||
const y2 = line.top + line.height * scaleY
|
||||
const dx = x2 - x1
|
||||
const dy = y2 - y1
|
||||
|
||||
return Number(Math.sqrt(dx * dx + dy * dy).toFixed(0)) * 10
|
||||
}
|
||||
|
||||
return {
|
||||
addLineText,
|
||||
removeLineText,
|
||||
}
|
||||
}
|
||||
8
src/hooks/usePolygon.js
Normal file
8
src/hooks/usePolygon.js
Normal file
@ -0,0 +1,8 @@
|
||||
import { canvasState } from '@/store/canvasAtom'
|
||||
import { useRecoilValue } from 'recoil'
|
||||
|
||||
export const usePolygon = () => {
|
||||
const canvas = useRecoilValue(canvasState)
|
||||
|
||||
return {}
|
||||
}
|
||||
@ -4,9 +4,7 @@ import { cookies } from 'next/headers'
|
||||
import { redirect } from 'next/navigation'
|
||||
|
||||
import { getIronSession } from 'iron-session'
|
||||
|
||||
import { getUserByIdAndPassword } from './user'
|
||||
import { defaultSession, sessionOptions } from './session'
|
||||
import { sessionOptions } from './session'
|
||||
|
||||
export async function logout() {
|
||||
const session = await getSession()
|
||||
@ -27,6 +25,15 @@ export async function getSession() {
|
||||
return session
|
||||
}
|
||||
|
||||
export async function checkSession() {
|
||||
const session = await getSession()
|
||||
|
||||
// if (!session.isLoggedIn) {
|
||||
// redirect('/login')
|
||||
// }
|
||||
return session.isLoggedIn
|
||||
}
|
||||
|
||||
export async function setSession(data) {
|
||||
const session = await getSession()
|
||||
|
||||
|
||||
@ -15,21 +15,28 @@
|
||||
"header.stem": "ステム",
|
||||
"plan.menu.plan.drawing": "도면작성",
|
||||
"plan.menu.placement.surface.initial.setting": "配置面 初期設定",
|
||||
"plan.menu.root.cover": "지붕덮개",
|
||||
"plan.menu.root.cover.outline.drawing": "외벽선 그리기",
|
||||
"modal.cover.outline.drawing": "외벽선 그리기",
|
||||
"modal.cover.outline": "외벽선",
|
||||
"modal.cover.outline.right.angle": "직각",
|
||||
"modal.cover.outline2": "이구배",
|
||||
"modal.cover.outline.angle": "각도",
|
||||
"modal.cover.outline.diagonal": "대각선",
|
||||
"plan.menu.roof.cover": "지붕덮개",
|
||||
"plan.menu.roof.cover.outline.drawing": "外壁線を描",
|
||||
"plan.menu.roof.cover.roof.shape.setting": "屋根形状設定",
|
||||
"plan.menu.roof.cover.roof.shape.edit": "지붕형상 편집",
|
||||
"plan.menu.roof.cover.auxiliary.line.drawing": "補助線を描",
|
||||
"plan.menu.roof.cover.roof.surface.alloc": "지붕면 할당",
|
||||
"modal.cover.outline.drawing": "外壁線を描",
|
||||
"modal.cover.outline": "外壁線",
|
||||
"modal.cover.outline.right.angle": "直角",
|
||||
"modal.cover.outline2": "イ・グベ",
|
||||
"modal.cover.outline.angle": "角度",
|
||||
"modal.cover.outline.diagonal": "対角線",
|
||||
"modal.cover.outline.setting": "설정",
|
||||
"modal.cover.outline.length": "길이",
|
||||
"modal.cover.outline.arrow": "방향(화살표)",
|
||||
"modal.cover.outline.fix": "외벽선 확정",
|
||||
"plan.menu.root.cover.roof.setting": "屋根形状設定",
|
||||
"plan.menu.root.cover.roof.edit": "지붕형상 편집",
|
||||
"plan.menu.root.cover.sub.line": "補助線を描",
|
||||
"modal.cover.outline.length": "長さ (mm)",
|
||||
"modal.cover.outline.arrow": "方向 (矢印)",
|
||||
"modal.cover.outline.fix": "外壁線確定",
|
||||
"modal.cover.outline.rollback": "一変戦に戻る",
|
||||
"modal.cover.outline.remove": "外壁の削除",
|
||||
"modal.cover.outline.select.move": "外壁の選択、移動",
|
||||
"plan.menu.roof.cover.roof.setting": "屋根形状設定",
|
||||
"plan.menu.roof.cover.roof.edit": "지붕형상 편집",
|
||||
"plan.menu.roof.cover.sub.line": "補助線を描",
|
||||
"plan.menu.placement.surface": "配置面",
|
||||
"plan.menu.placement.surface.drawing": "배치면 그리기",
|
||||
"plan.menu.placement.surface.surface": "면형상 배치",
|
||||
@ -49,6 +56,18 @@
|
||||
"modal.canvas.setting": "Canvas設定",
|
||||
"modal.canvas.setting.display": "ディスプレイ設定",
|
||||
"modal.canvas.setting.font.plan": " フォントと図面サイズの設定",
|
||||
"modal.canvas.setting.font.plan.edit": "フォントとサイズの変更",
|
||||
"modal.canvas.setting.font.plan.edit.word": "文字フォントの変更",
|
||||
"modal.canvas.setting.font.plan.edit.flow": "フロー方向フォントの変更",
|
||||
"modal.canvas.setting.font.plan.edit.dimension": "寸法フォントの変更",
|
||||
"modal.canvas.setting.font.plan.edit.circuit.num": "回路番号フォントの変更",
|
||||
"modal.canvas.setting.font.plan.absorption": "吸着範囲の設定",
|
||||
"modal.canvas.setting.font.plan.absorption.small": "極小",
|
||||
"modal.canvas.setting.font.plan.absorption.small.semi": "牛",
|
||||
"modal.canvas.setting.font.plan.absorption.medium": "中",
|
||||
"modal.canvas.setting.font.plan.absorption.large": "ティーン",
|
||||
"modal.canvas.setting.font.plan.absorption.dimension.line": "寸法線の設定",
|
||||
"modal.canvas.setting.font.plan.absorption.plan.size.setting": "図面サイズの設定",
|
||||
"modal.canvas.setting.first.option.info": "※図面に表示する項目をクリックすると適用されます。",
|
||||
"modal.canvas.setting.first.option.alloc": "할당표시",
|
||||
"modal.canvas.setting.first.option.outline": "외벽선표시",
|
||||
|
||||
@ -15,21 +15,25 @@
|
||||
"header.stem": "Stem",
|
||||
"plan.menu.plan.drawing": "도면작성",
|
||||
"plan.menu.placement.surface.initial.setting": "배치면 초기 설정",
|
||||
"plan.menu.root.cover": "지붕덮개",
|
||||
"plan.menu.root.cover.outline.drawing": "외벽선 그리기",
|
||||
"modal.cover.outline.drawing": "외벽선 그리기",
|
||||
"plan.menu.roof.cover": "지붕덮개",
|
||||
"plan.menu.roof.cover.outline.drawing": "외벽선 그리기",
|
||||
"plan.menu.roof.cover.roof.shape.setting": "지붕형상 설정",
|
||||
"plan.menu.roof.cover.roof.shape.edit": "지붕형상 편집",
|
||||
"plan.menu.roof.cover.auxiliary.line.drawing": "보조선 그리기",
|
||||
"plan.menu.roof.cover.roof.surface.alloc": "지붕면 할당",
|
||||
"modal.cover.outline.drawing": "외벽선 작성",
|
||||
"modal.cover.outline": "외벽선",
|
||||
"modal.cover.outline.right.angle": "직각",
|
||||
"modal.cover.outline2": "이구배",
|
||||
"modal.cover.outline.angle": "각도",
|
||||
"modal.cover.outline.diagonal": "대각선",
|
||||
"modal.cover.outline.setting": "설정",
|
||||
"modal.cover.outline.length": "길이",
|
||||
"modal.cover.outline.length": "길이 (mm)",
|
||||
"modal.cover.outline.arrow": "방향(화살표)",
|
||||
"modal.cover.outline.fix": "외벽선 확정",
|
||||
"plan.menu.root.cover.roof.setting": "지붕형상 설정",
|
||||
"plan.menu.root.cover.roof.edit": "지붕형상 편집",
|
||||
"plan.menu.root.cover.sub.line": "보조선 그리기",
|
||||
"modal.cover.outline.rollback": "일변전으로 돌아가기",
|
||||
"modal.cover.outline.remove": "외벽 제거",
|
||||
"modal.cover.outline.select.move": "외벽 선택, 이동",
|
||||
"plan.menu.placement.surface": "배치면",
|
||||
"plan.menu.placement.surface.drawing": "배치면 그리기",
|
||||
"plan.menu.placement.surface.surface": "면형상 배치",
|
||||
@ -49,6 +53,18 @@
|
||||
"modal.canvas.setting": "Canvas 설정",
|
||||
"modal.canvas.setting.display": "디스플레이 설정",
|
||||
"modal.canvas.setting.font.plan": "글꼴 및 도면 크기 설정",
|
||||
"modal.canvas.setting.font.plan.edit": "글꼴 및 크기 변경",
|
||||
"modal.canvas.setting.font.plan.edit.word": "문자 글꼴 변경",
|
||||
"modal.canvas.setting.font.plan.edit.flow": "흐름 방향 글꼴 변경",
|
||||
"modal.canvas.setting.font.plan.edit.dimension": "치수 글꼴변경",
|
||||
"modal.canvas.setting.font.plan.edit.circuit.num": "회로번호 글꼴변경",
|
||||
"modal.canvas.setting.font.plan.absorption": "흡착범위 설정",
|
||||
"modal.canvas.setting.font.plan.absorption.small": "극소",
|
||||
"modal.canvas.setting.font.plan.absorption.small.semi": "소",
|
||||
"modal.canvas.setting.font.plan.absorption.medium": "중",
|
||||
"modal.canvas.setting.font.plan.absorption.large": "대",
|
||||
"modal.canvas.setting.font.plan.absorption.dimension.line": "치수선 설정",
|
||||
"modal.canvas.setting.font.plan.absorption.plan.size.setting": "도면크기 설정",
|
||||
"modal.canvas.setting.first.option.info": "※도면에 표시하는 항목을 클릭하면 적용됩니다.",
|
||||
"modal.canvas.setting.first.option.alloc": "할당표시",
|
||||
"modal.canvas.setting.first.option.outline": "외벽선표시",
|
||||
@ -103,7 +119,7 @@
|
||||
"common.message.multi.insert": "Total {0} cases ({1} successes, {2} failures {3})",
|
||||
"common.message.error": "Error occurred, please contact site administrator.",
|
||||
"common.message.data.save": "Do you want to save it?",
|
||||
"common.message.data.delete": "Do you want to delete it?",
|
||||
"common.message.data.delete": "정말로 삭제하시겠습니까?",
|
||||
"common.message.data.exists": "{0} is data that already exists.",
|
||||
"common.message.data.no.exists": "{0} is data that does not exist.",
|
||||
"common.message.all": "All",
|
||||
|
||||
@ -1,27 +1,27 @@
|
||||
import { createI18nMiddleware } from 'next-international/middleware'
|
||||
// import { createI18nMiddleware } from 'next-international/middleware'
|
||||
|
||||
const I18nMiddleware = createI18nMiddleware({
|
||||
locales: ['ko', 'ja'],
|
||||
defaultLocale: 'ko',
|
||||
})
|
||||
// const I18nMiddleware = createI18nMiddleware({
|
||||
// locales: ['ko', 'ja'],
|
||||
// defaultLocale: 'ko',
|
||||
// })
|
||||
|
||||
export function middleware(request) {
|
||||
return I18nMiddleware(request)
|
||||
}
|
||||
// export function middleware(request) {
|
||||
// return I18nMiddleware(request)
|
||||
// }
|
||||
|
||||
export const config = {
|
||||
matcher: ['/((?!api|static|.*\\..*|_next|favicon.ico|robots.txt).*)'],
|
||||
}
|
||||
|
||||
// import { NextRequest, NextResponse } from 'next/server'
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
|
||||
// export function middleware(request) {
|
||||
// const requestHeaders = new Headers(request.headers)
|
||||
// requestHeaders.set('x-pathname', request.nextUrl.pathname)
|
||||
export function middleware(request) {
|
||||
const requestHeaders = new Headers(request.headers)
|
||||
requestHeaders.set('x-pathname', request.nextUrl.pathname)
|
||||
|
||||
// return NextResponse.next({
|
||||
// request: {
|
||||
// headers: requestHeaders,
|
||||
// },
|
||||
// })
|
||||
// }
|
||||
return NextResponse.next({
|
||||
request: {
|
||||
headers: requestHeaders,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { atom } from 'recoil'
|
||||
import { MENU } from '@/common/common'
|
||||
|
||||
export const canvasState = atom({
|
||||
key: 'canvasState',
|
||||
@ -180,7 +181,7 @@ export const objectPlacementModeState = atom({
|
||||
default: { width: 0, height: 0, areaBoundary: false, inputType: 'free', batchType: 'opening' },
|
||||
})
|
||||
|
||||
export const stepState = atom({
|
||||
key: 'step',
|
||||
default: 0,
|
||||
export const currentMenuState = atom({
|
||||
key: 'currentMenu',
|
||||
default: MENU.INITIAL_CANVAS_SETTING,
|
||||
})
|
||||
|
||||
65
src/store/outerLineAtom.js
Normal file
65
src/store/outerLineAtom.js
Normal file
@ -0,0 +1,65 @@
|
||||
import { atom, selector } from 'recoil'
|
||||
|
||||
export const OUTER_LINE_TYPE = {
|
||||
OUTER_LINE: 'outerLine', // 외벽선
|
||||
RIGHT_ANGLE: 'rightAngle', // 직각
|
||||
LEE_GUBAE: 'leeGubae', // 이구배
|
||||
ANGLE: 'angle', // 각도
|
||||
DIAGONAL_LINE: 'diagonalLine', // 대각선
|
||||
}
|
||||
|
||||
/**
|
||||
* 외벽선 작성에서 사용하는 recoilState
|
||||
*/
|
||||
|
||||
export const outerLineLength1State = atom({
|
||||
//길이1
|
||||
key: 'outerLineLength1State',
|
||||
default: 0,
|
||||
})
|
||||
|
||||
export const outerLineLength2State = atom({
|
||||
// 길이2
|
||||
key: 'outerLineLength2State',
|
||||
default: 0,
|
||||
})
|
||||
|
||||
export const outerLineArrow1State = atom({
|
||||
// 방향1
|
||||
key: 'outerLineArrow1State',
|
||||
default: '',
|
||||
})
|
||||
|
||||
export const outerLineArrow2State = atom({
|
||||
// 방향2
|
||||
key: 'outerLineArrow2State',
|
||||
default: '',
|
||||
})
|
||||
|
||||
export const outerLineAngle1State = atom({
|
||||
// 각도1
|
||||
key: 'outerLineAngle1State',
|
||||
default: 0,
|
||||
})
|
||||
|
||||
export const outerLineAngle2State = atom({
|
||||
// 각도2
|
||||
key: 'outerLineAngle2State',
|
||||
default: 0,
|
||||
})
|
||||
|
||||
export const outerLineDiagonalState = atom({
|
||||
// 대각선
|
||||
key: 'outerLineDiagonalState',
|
||||
default: 0,
|
||||
})
|
||||
|
||||
export const outerLineTypeState = atom({
|
||||
key: 'outerLineTypeState',
|
||||
default: OUTER_LINE_TYPE.OUTER_LINE,
|
||||
})
|
||||
|
||||
export const outerLinePointsState = atom({
|
||||
key: 'outerLinePointsState',
|
||||
default: [],
|
||||
})
|
||||
@ -4,22 +4,22 @@ export const settingModalFirstOptionsState = atom({
|
||||
key: 'settingModalFirstOptions',
|
||||
default: {
|
||||
option1: [
|
||||
{ id: 1, name: 'modal.canvas.setting.first.option.alloc', selected: false },
|
||||
{ id: 2, name: 'modal.canvas.setting.first.option.outline', selected: false },
|
||||
{ id: 3, name: 'modal.canvas.setting.first.option.plan', selected: false },
|
||||
{ id: 4, name: 'modal.canvas.setting.first.option.roof.line', selected: false },
|
||||
{ id: 5, name: 'modal.canvas.setting.first.option.grid', selected: false },
|
||||
{ id: 6, name: 'modal.canvas.setting.first.option.circuit.num', selected: false },
|
||||
{ id: 7, name: 'modal.canvas.setting.first.option.word', selected: false },
|
||||
{ id: 8, name: 'modal.canvas.setting.first.option.trestle', selected: false },
|
||||
{ id: 9, name: 'modal.canvas.setting.first.option.flow', selected: false },
|
||||
{ id: 10, name: 'modal.canvas.setting.first.option.total', selected: false },
|
||||
{ id: 11, name: 'modal.canvas.setting.first.option.corridor.dimension', selected: false },
|
||||
{ id: 1, column: 'assignDisplay', name: 'modal.canvas.setting.first.option.alloc', selected: false },
|
||||
{ id: 2, column: 'drawDisplay', name: 'modal.canvas.setting.first.option.outline', selected: false },
|
||||
{ id: 3, column: 'gridDisplay', name: 'modal.canvas.setting.first.option.plan', selected: false },
|
||||
{ id: 4, column: 'charDisplay', name: 'modal.canvas.setting.first.option.roof.line', selected: false },
|
||||
{ id: 5, column: 'flowDisplay', name: 'modal.canvas.setting.first.option.grid', selected: false },
|
||||
{ id: 6, column: 'hallwayDimenDisplay', name: 'modal.canvas.setting.first.option.circuit.num', selected: false },
|
||||
{ id: 7, column: 'actualDimenDisplay', name: 'modal.canvas.setting.first.option.word', selected: false },
|
||||
{ id: 8, column: 'noDimenDisplay', name: 'modal.canvas.setting.first.option.trestle', selected: false },
|
||||
{ id: 9, column: 'trestleDisplay', name: 'modal.canvas.setting.first.option.flow', selected: false },
|
||||
{ id: 10, column: 'coordiDisplay', name: 'modal.canvas.setting.first.option.total', selected: false },
|
||||
{ id: 11, column: 'drawConverDisplay', name: 'modal.canvas.setting.first.option.corridor.dimension', selected: false },
|
||||
],
|
||||
option2: [
|
||||
{ id: 1, name: 'modal.canvas.setting.first.option.border', selected: false },
|
||||
{ id: 2, name: 'modal.canvas.setting.first.option.line', selected: false },
|
||||
{ id: 3, name: 'modal.canvas.setting.first.option.all', selected: false },
|
||||
{ id: 1, column: 'onlyBorder', name: 'modal.canvas.setting.first.option.border', selected: false },
|
||||
{ id: 2, column: 'lineHatch', name: 'modal.canvas.setting.first.option.line', selected: false },
|
||||
{ id: 3, column: 'allPainted', name: 'modal.canvas.setting.first.option.all', selected: false },
|
||||
],
|
||||
},
|
||||
dangerouslyAllowMutability: true,
|
||||
@ -29,16 +29,16 @@ export const settingModalSecondOptionsState = atom({
|
||||
key: 'settingModalSecondOptions',
|
||||
default: {
|
||||
option1: [
|
||||
{ id: 1, name: '文字フォントの変更' },
|
||||
{ id: 2, name: 'フロー方向フォントの変更' },
|
||||
{ id: 3, name: '寸法フォントの変更' },
|
||||
{ id: 4, name: '回路番号フォントの変更' },
|
||||
{ id: 1, name: 'modal.canvas.setting.font.plan.edit.word' },
|
||||
{ id: 2, name: 'modal.canvas.setting.font.plan.edit.flow' },
|
||||
{ id: 3, name: 'modal.canvas.setting.font.plan.edit.dimension' },
|
||||
{ id: 4, name: 'modal.canvas.setting.font.plan.edit.circuit.num' },
|
||||
],
|
||||
option2: [
|
||||
{ id: 1, name: '極小', selected: false },
|
||||
{ id: 2, name: '牛', selected: false },
|
||||
{ id: 3, name: '中', selected: false },
|
||||
{ id: 4, name: 'ティーン', selected: false },
|
||||
{ id: 1, name: 'modal.canvas.setting.font.plan.absorption.small', selected: false },
|
||||
{ id: 2, name: 'modal.canvas.setting.font.plan.absorption.small.semi', selected: false },
|
||||
{ id: 3, name: 'modal.canvas.setting.font.plan.absorption.medium', selected: false },
|
||||
{ id: 4, name: 'modal.canvas.setting.font.plan.absorption.large', selected: false },
|
||||
],
|
||||
},
|
||||
dangerouslyAllowMutability: true,
|
||||
|
||||
@ -17,6 +17,10 @@ export const stuffSearchState = atom({
|
||||
schFromDt: dayjs(new Date()).add(-1, 'year').format('YYYY-MM-DD'), //시작일
|
||||
schToDt: dayjs(new Date()).format('YYYY-MM-DD'), //종료일
|
||||
code: 'S',
|
||||
schSelSaleStoreId: '', //판매대리점 선택
|
||||
startRow: 1,
|
||||
endRow: 100,
|
||||
schSortType: 'R', //정렬조건 (R:최근등록일 U:최근수정일)
|
||||
},
|
||||
dangerouslyAllowMutability: true,
|
||||
})
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
height: calc(100vh - 47px);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: #fff;
|
||||
|
||||
.canvas-content {
|
||||
flex: 1 1 auto;
|
||||
|
||||
@ -1,199 +1,199 @@
|
||||
@font-face {
|
||||
font-family: 'Noto Sans JP';
|
||||
src: url('/fonts/NotoSansJP-ExtraBold.woff2') format('woff2'),
|
||||
url('/fonts/NotoSansJP-ExtraBold.woff') format('woff');
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
font-family: 'Noto Sans JP';
|
||||
src: url('/fonts/NotoSansJP-ExtraBold.woff2') format('woff2'),
|
||||
url('/fonts/NotoSansJP-ExtraBold.woff') format('woff');
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Noto Sans JP';
|
||||
src: url('/fonts/NotoSansJP-Bold.woff2') format('woff2'),
|
||||
url('/fonts/NotoSansJP-Bold.woff') format('woff');
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
font-family: 'Noto Sans JP';
|
||||
src: url('/fonts/NotoSansJP-Bold.woff2') format('woff2'),
|
||||
url('/fonts/NotoSansJP-Bold.woff') format('woff');
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Noto Sans JP';
|
||||
src: url('/fonts/NotoSansJP-Black.woff2') format('woff2'),
|
||||
url('/fonts/NotoSansJP-Black.woff') format('woff');
|
||||
font-weight: 900;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
font-family: 'Noto Sans JP';
|
||||
src: url('/fonts/NotoSansJP-Black.woff2') format('woff2'),
|
||||
url('/fonts/NotoSansJP-Black.woff') format('woff');
|
||||
font-weight: 900;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Noto Sans JP';
|
||||
src: url('/fonts/NotoSansJP-ExtraLight.woff2') format('woff2'),
|
||||
url('/fonts/NotoSansJP-ExtraLight.woff') format('woff');
|
||||
font-weight: 200;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
font-family: 'Noto Sans JP';
|
||||
src: url('/fonts/NotoSansJP-ExtraLight.woff2') format('woff2'),
|
||||
url('/fonts/NotoSansJP-ExtraLight.woff') format('woff');
|
||||
font-weight: 200;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Noto Sans JP';
|
||||
src: url('/fonts/NotoSansJP-Light.woff2') format('woff2'),
|
||||
url('/fonts/NotoSansJP-Light.woff') format('woff');
|
||||
font-weight: 300;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
font-family: 'Noto Sans JP';
|
||||
src: url('/fonts/NotoSansJP-Light.woff2') format('woff2'),
|
||||
url('/fonts/NotoSansJP-Light.woff') format('woff');
|
||||
font-weight: 300;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Noto Sans JP';
|
||||
src: url('/fonts/NotoSansJP-Medium.woff2') format('woff2'),
|
||||
url('/fonts/NotoSansJP-Medium.woff') format('woff');
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
font-family: 'Noto Sans JP';
|
||||
src: url('/fonts/NotoSansJP-Medium.woff2') format('woff2'),
|
||||
url('/fonts/NotoSansJP-Medium.woff') format('woff');
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Noto Sans JP';
|
||||
src: url('/fonts/NotoSansJP-Regular.woff2') format('woff2'),
|
||||
url('/fonts/NotoSansJP-Regular.woff') format('woff');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
font-family: 'Noto Sans JP';
|
||||
src: url('/fonts/NotoSansJP-Regular.woff2') format('woff2'),
|
||||
url('/fonts/NotoSansJP-Regular.woff') format('woff');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Noto Sans JP';
|
||||
src: url('/fonts/NotoSansJP-SemiBold.woff2') format('woff2'),
|
||||
url('/fonts/NotoSansJP-SemiBold.woff') format('woff');
|
||||
font-weight: 600;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
font-family: 'Noto Sans JP';
|
||||
src: url('/fonts/NotoSansJP-SemiBold.woff2') format('woff2'),
|
||||
url('/fonts/NotoSansJP-SemiBold.woff') format('woff');
|
||||
font-weight: 600;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Noto Sans JP';
|
||||
src: url('/fonts/NotoSansJP-Thin.woff2') format('woff2'),
|
||||
url('/fonts/NotoSansJP-Thin.woff') format('woff');
|
||||
font-weight: 100;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
font-family: 'Noto Sans JP';
|
||||
src: url('/fonts/NotoSansJP-Thin.woff2') format('woff2'),
|
||||
url('/fonts/NotoSansJP-Thin.woff') format('woff');
|
||||
font-weight: 100;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
// pretendard
|
||||
@font-face {
|
||||
font-family: 'Pretendard';
|
||||
src: url('/fonts/Pretendard-Bold.woff2') format('woff2'),
|
||||
url('/fonts/Pretendard-Bold.woff') format('woff');
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
font-family: 'Pretendard';
|
||||
src: url('/fonts/Pretendard-Bold.woff2') format('woff2'),
|
||||
url('/fonts/Pretendard-Bold.woff') format('woff');
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Pretendard';
|
||||
src: url('/fonts/Pretendard-ExtraBold.woff2') format('woff2'),
|
||||
url('/fonts/Pretendard-ExtraBold.woff') format('woff');
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
font-family: 'Pretendard';
|
||||
src: url('/fonts/Pretendard-ExtraBold.woff2') format('woff2'),
|
||||
url('/fonts/Pretendard-ExtraBold.woff') format('woff');
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Pretendard';
|
||||
src: url('/fonts/Pretendard-ExtraBold.woff2') format('woff2'),
|
||||
url('/fonts/Pretendard-ExtraBold.woff') format('woff');
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
font-family: 'Pretendard';
|
||||
src: url('/fonts/Pretendard-ExtraBold.woff2') format('woff2'),
|
||||
url('/fonts/Pretendard-ExtraBold.woff') format('woff');
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Pretendard';
|
||||
src: url('/fonts/Pretendard-ExtraLight.woff2') format('woff2'),
|
||||
url('/fonts/Pretendard-ExtraLight.woff') format('woff');
|
||||
font-weight: 200;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
font-family: 'Pretendard';
|
||||
src: url('/fonts/Pretendard-ExtraLight.woff2') format('woff2'),
|
||||
url('/fonts/Pretendard-ExtraLight.woff') format('woff');
|
||||
font-weight: 200;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Pretendard';
|
||||
src: url('/fonts/Pretendard-ExtraLight.woff2') format('woff2'),
|
||||
url('/fonts/Pretendard-ExtraLight.woff') format('woff');
|
||||
font-weight: 200;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
font-family: 'Pretendard';
|
||||
src: url('/fonts/Pretendard-ExtraLight.woff2') format('woff2'),
|
||||
url('/fonts/Pretendard-ExtraLight.woff') format('woff');
|
||||
font-weight: 200;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Pretendard';
|
||||
src: url('/fonts/Pretendard-Light.woff2') format('woff2'),
|
||||
url('/fonts/Pretendard-Light.woff') format('woff');
|
||||
font-weight: 300;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
font-family: 'Pretendard';
|
||||
src: url('/fonts/Pretendard-Light.woff2') format('woff2'),
|
||||
url('/fonts/Pretendard-Light.woff') format('woff');
|
||||
font-weight: 300;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Pretendard';
|
||||
src: url('/fonts/Pretendard-Light.woff2') format('woff2'),
|
||||
url('/fonts/Pretendard-Light.woff') format('woff');
|
||||
font-weight: 300;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
font-family: 'Pretendard';
|
||||
src: url('/fonts/Pretendard-Light.woff2') format('woff2'),
|
||||
url('/fonts/Pretendard-Light.woff') format('woff');
|
||||
font-weight: 300;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Pretendard';
|
||||
src: url('/fonts/Pretendard-Medium.woff2') format('woff2'),
|
||||
url('/fonts/Pretendard-Medium.woff') format('woff');
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
font-family: 'Pretendard';
|
||||
src: url('/fonts/Pretendard-Medium.woff2') format('woff2'),
|
||||
url('/fonts/Pretendard-Medium.woff') format('woff');
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Pretendard';
|
||||
src: url('/fonts/Pretendard-Medium.woff2') format('woff2'),
|
||||
url('/fonts/Pretendard-Medium.woff') format('woff');
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
font-family: 'Pretendard';
|
||||
src: url('/fonts/Pretendard-Medium.woff2') format('woff2'),
|
||||
url('/fonts/Pretendard-Medium.woff') format('woff');
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Pretendard';
|
||||
src: url('/fonts/Pretendard-Regular.woff2') format('woff2'),
|
||||
url('/fonts/Pretendard-Regular.woff') format('woff');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
font-family: 'Pretendard';
|
||||
src: url('/fonts/Pretendard-Regular.woff2') format('woff2'),
|
||||
url('/fonts/Pretendard-Regular.woff') format('woff');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Pretendard';
|
||||
src: url('/fonts/Pretendard-Black.woff2') format('woff2'),
|
||||
url('/fonts/Pretendard-Black.woff') format('woff');
|
||||
font-weight: 900;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
font-family: 'Pretendard';
|
||||
src: url('/fonts/Pretendard-Black.woff2') format('woff2'),
|
||||
url('/fonts/Pretendard-Black.woff') format('woff');
|
||||
font-weight: 900;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Pretendard';
|
||||
src: url('/fonts/Pretendard-Black.woff2') format('woff2'),
|
||||
url('/fonts/Pretendard-Black.woff') format('woff');
|
||||
font-weight: 900;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
font-family: 'Pretendard';
|
||||
src: url('/fonts/Pretendard-Black.woff2') format('woff2'),
|
||||
url('/fonts/Pretendard-Black.woff') format('woff');
|
||||
font-weight: 900;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Pretendard';
|
||||
src: url('/fonts/Pretendard-Bold.woff2') format('woff2'),
|
||||
url('/fonts/Pretendard-Bold.woff') format('woff');
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
font-family: 'Pretendard';
|
||||
src: url('/fonts/Pretendard-Bold.woff2') format('woff2'),
|
||||
url('/fonts/Pretendard-Bold.woff') format('woff');
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
|
||||
@ -1,216 +1,250 @@
|
||||
.wrap{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 1600px;
|
||||
min-height: 100vh;
|
||||
overflow-x: hidden;
|
||||
.wrap {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 1600px;
|
||||
min-height: 100vh;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
.content{
|
||||
flex: 1 1 auto;
|
||||
padding-top: 46px;
|
||||
|
||||
.content {
|
||||
position: relative;
|
||||
flex: 1 1 auto;
|
||||
padding-top: 46px;
|
||||
background-color: #F4F4F7;
|
||||
}
|
||||
|
||||
// header
|
||||
// nav item 공통
|
||||
@mixin navitem(){
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 14px;
|
||||
color: #fff;
|
||||
font-weight: 500;
|
||||
height: 100%;
|
||||
padding-right: 12px;
|
||||
transition: color .17s ease-in-out;
|
||||
}
|
||||
header{
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
min-width: 1600px;
|
||||
height: 46px;
|
||||
background-color: #1C1C1C;
|
||||
border-bottom: 1px solid #000;
|
||||
z-index: 9999;
|
||||
.header-inner{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
padding: 0 40px;
|
||||
.header-right{
|
||||
display: flex;
|
||||
height: 100%;
|
||||
align-items: center;
|
||||
.logo{
|
||||
a{
|
||||
display: block;
|
||||
width: 232px;
|
||||
height: 30px;
|
||||
background: url(/static/images/common/Logo.svg)no-repeat center;
|
||||
background-size: contain;
|
||||
}
|
||||
}
|
||||
nav{
|
||||
margin-left: 50px;
|
||||
height: 100%;
|
||||
.nav-list{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
.nav-item{
|
||||
position: relative;
|
||||
margin-right: 62px;
|
||||
height: 100%;
|
||||
a{
|
||||
@include navitem;
|
||||
}
|
||||
button{
|
||||
@include navitem;
|
||||
&:after{
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 0;
|
||||
transform: translateY(-50%);
|
||||
width: 6px;
|
||||
height: 10px;
|
||||
background: url(/static/images/common/nav-arr.svg)no-repeat center;
|
||||
transition: all .17s ease-in-out;
|
||||
}
|
||||
}
|
||||
&:last-child{
|
||||
margin-right: 0;
|
||||
}
|
||||
.nav-depth2{
|
||||
position: absolute;
|
||||
top: calc(100% - 2px);
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
min-width: 100px;
|
||||
background-color: #1C1C1C;
|
||||
border: 1px solid #464646;
|
||||
padding: 24px;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
transition: all .17s ease-in-out;
|
||||
.nav-depth2-item{
|
||||
margin-bottom: 10px;
|
||||
transition: all .17s ease-in-out;
|
||||
a{
|
||||
font-size: 13px;
|
||||
font-weight: normal;
|
||||
white-space: nowrap;
|
||||
}
|
||||
&:last-child{
|
||||
margin-bottom: 0;
|
||||
}
|
||||
&.mouse{
|
||||
opacity: 0.55;
|
||||
}
|
||||
}
|
||||
&::before{
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: -5px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%) rotate(45deg);
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
background-color: #1c1c1c;
|
||||
border-top: 1px solid #464646;
|
||||
border-left: 1px solid #464646;
|
||||
}
|
||||
}
|
||||
&.mouse{
|
||||
> a{
|
||||
color: rgba(255, 255, 255, 0.30);
|
||||
}
|
||||
> button{
|
||||
color: rgba(255, 255, 255, 0.30);
|
||||
&:after{
|
||||
opacity: 0.3;
|
||||
}
|
||||
}
|
||||
}
|
||||
&:hover{
|
||||
.nav-depth2{
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
}
|
||||
> button{
|
||||
&:after{
|
||||
transform: translateY(-50%) rotate(90deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.header-left{
|
||||
margin-left: auto;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.profile-box{
|
||||
position: relative;
|
||||
padding-left: 30px;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-right: 20px;
|
||||
cursor: pointer;
|
||||
.profile{
|
||||
font-size: 13px;
|
||||
font-weight: normal;
|
||||
color: #fff;
|
||||
}
|
||||
&::after{
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
left: 0;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
background: url(/static/images/common/profile_icon.svg)no-repeat center;
|
||||
background-size: cover;
|
||||
}
|
||||
}
|
||||
.sign-out-box{
|
||||
position: relative;
|
||||
padding-left: 30px;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-right: 20px;
|
||||
cursor: pointer;
|
||||
.sign-out{
|
||||
font-size: 13px;
|
||||
font-weight: normal;
|
||||
color: #fff;
|
||||
}
|
||||
&::after{
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
left: 0;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
background: url(../../public/static/images/common/signout_icon.svg)no-repeat center;
|
||||
background-size: cover;
|
||||
}
|
||||
}
|
||||
.select-box{
|
||||
min-width: 165px;
|
||||
margin-right: 8px;
|
||||
>div{
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@mixin navitem() {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 14px;
|
||||
color: #fff;
|
||||
font-weight: 500;
|
||||
height: 100%;
|
||||
padding-right: 12px;
|
||||
transition: color .17s ease-in-out;
|
||||
}
|
||||
|
||||
header {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
min-width: 1600px;
|
||||
height: 46px;
|
||||
background-color: #1C1C1C;
|
||||
border-bottom: 1px solid #000;
|
||||
z-index: 9999;
|
||||
|
||||
.header-inner {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
padding: 0 40px;
|
||||
|
||||
.header-right {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
align-items: center;
|
||||
|
||||
.logo {
|
||||
a {
|
||||
display: block;
|
||||
width: 232px;
|
||||
height: 30px;
|
||||
background: url(/static/images/common/Logo.svg) no-repeat center;
|
||||
background-size: contain;
|
||||
}
|
||||
}
|
||||
|
||||
nav {
|
||||
margin-left: 50px;
|
||||
height: 100%;
|
||||
|
||||
.nav-list {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
|
||||
.nav-item {
|
||||
position: relative;
|
||||
margin-right: 62px;
|
||||
height: 100%;
|
||||
|
||||
a {
|
||||
@include navitem;
|
||||
}
|
||||
|
||||
button {
|
||||
@include navitem;
|
||||
|
||||
&:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 0;
|
||||
transform: translateY(-50%);
|
||||
width: 6px;
|
||||
height: 10px;
|
||||
background: url(/static/images/common/nav-arr.svg) no-repeat center;
|
||||
transition: all .17s ease-in-out;
|
||||
}
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.nav-depth2 {
|
||||
position: absolute;
|
||||
top: calc(100% - 2px);
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
min-width: 100px;
|
||||
background-color: #1C1C1C;
|
||||
border: 1px solid #464646;
|
||||
padding: 24px;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
transition: all .17s ease-in-out;
|
||||
|
||||
.nav-depth2-item {
|
||||
margin-bottom: 10px;
|
||||
transition: all .17s ease-in-out;
|
||||
|
||||
a {
|
||||
font-size: 13px;
|
||||
font-weight: normal;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
&.mouse {
|
||||
opacity: 0.55;
|
||||
}
|
||||
}
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: -5px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%) rotate(45deg);
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
background-color: #1c1c1c;
|
||||
border-top: 1px solid #464646;
|
||||
border-left: 1px solid #464646;
|
||||
}
|
||||
}
|
||||
|
||||
&.mouse {
|
||||
> a {
|
||||
color: rgba(255, 255, 255, 0.30);
|
||||
}
|
||||
|
||||
> button {
|
||||
color: rgba(255, 255, 255, 0.30);
|
||||
|
||||
&:after {
|
||||
opacity: 0.3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.nav-depth2 {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
> button {
|
||||
&:after {
|
||||
transform: translateY(-50%) rotate(90deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.header-left {
|
||||
margin-left: auto;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.profile-box {
|
||||
position: relative;
|
||||
padding-left: 30px;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-right: 20px;
|
||||
cursor: pointer;
|
||||
|
||||
.profile {
|
||||
font-size: 13px;
|
||||
font-weight: normal;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
left: 0;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
background: url(/static/images/common/profile_icon.svg) no-repeat center;
|
||||
background-size: cover;
|
||||
}
|
||||
}
|
||||
|
||||
.sign-out-box {
|
||||
position: relative;
|
||||
padding-left: 30px;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-right: 20px;
|
||||
cursor: pointer;
|
||||
|
||||
.sign-out {
|
||||
font-size: 13px;
|
||||
font-weight: normal;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
left: 0;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
background: url(../../public/static/images/common/signout_icon.svg) no-repeat center;
|
||||
background-size: cover;
|
||||
}
|
||||
}
|
||||
|
||||
.select-box {
|
||||
min-width: 165px;
|
||||
margin-right: 8px;
|
||||
|
||||
> div {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
0
src/styles/_main.scss
Normal file
0
src/styles/_main.scss
Normal file
@ -1,91 +1,144 @@
|
||||
@keyframes mountpop{
|
||||
from{opacity: 0; scale: 0.95;}
|
||||
to{opacity: 1; scale: 1;}
|
||||
}
|
||||
@keyframes unmountpop{
|
||||
from{opacity: 1; scale: 1;}
|
||||
to{opacity: 0; scale: 0.95;}
|
||||
@keyframes mountpop {
|
||||
from {
|
||||
opacity: 0;
|
||||
scale: 0.95;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
scale: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-pop-wrap{
|
||||
position: fixed;
|
||||
top: 200px;
|
||||
right: 100px;
|
||||
width: 100%;
|
||||
min-width: 380px;
|
||||
max-width: fit-content;
|
||||
height: -webkit-fit-content;
|
||||
height: -moz-fit-content;
|
||||
height: fit-content;
|
||||
border: 1px solid #000;
|
||||
border-radius: 4px;
|
||||
background-color: #272727;
|
||||
z-index: 9999999;
|
||||
&.sm{
|
||||
max-width: 450px;
|
||||
}
|
||||
&.mount{
|
||||
animation: mountpop .17s ease-in-out forwards;
|
||||
}
|
||||
&.unmount{
|
||||
animation: unmountpop .17s ease-in-out forwards;
|
||||
}
|
||||
@keyframes unmountpop {
|
||||
from {
|
||||
opacity: 1;
|
||||
scale: 1;
|
||||
}
|
||||
to {
|
||||
opacity: 0;
|
||||
scale: 0.95;
|
||||
}
|
||||
}
|
||||
.modal-head{
|
||||
|
||||
.modal-pop-wrap {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
min-width: 380px;
|
||||
max-width: fit-content;
|
||||
height: -webkit-fit-content;
|
||||
height: -moz-fit-content;
|
||||
height: fit-content;
|
||||
border: 1px solid #000;
|
||||
border-radius: 4px;
|
||||
background-color: #272727;
|
||||
z-index: 9999999;
|
||||
|
||||
&.sm {
|
||||
max-width: 450px;
|
||||
}
|
||||
|
||||
&.ssm {
|
||||
max-width: 380px;
|
||||
}
|
||||
|
||||
&.mount {
|
||||
animation: mountpop .17s ease-in-out forwards;
|
||||
}
|
||||
|
||||
&.unmount {
|
||||
animation: unmountpop .17s ease-in-out forwards;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 10px 24px;
|
||||
background-color: #000;
|
||||
cursor: pointer;
|
||||
|
||||
h1.title {
|
||||
font-size: 13px;
|
||||
color: #fff;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.modal-close {
|
||||
margin-left: auto;
|
||||
color: #fff;
|
||||
text-indent: -999999999px;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
background: url(../../public/static/images/canvas/modal_close.svg) no-repeat center;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
padding: 15px;
|
||||
|
||||
.modal-btn-wrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 10px 24px;
|
||||
background-color: #000;
|
||||
cursor: pointer;
|
||||
h1.title{
|
||||
font-size: 13px;
|
||||
color: #fff;
|
||||
font-weight: 700;
|
||||
gap: 5px;
|
||||
|
||||
button {
|
||||
flex: 1;
|
||||
}
|
||||
.modal-close{
|
||||
margin-left: auto;
|
||||
color: #fff;
|
||||
text-indent: -999999999px;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
background: url(../../public/static/images/canvas/modal_close.svg)no-repeat center;
|
||||
}
|
||||
|
||||
.modal-check-btn-wrap {
|
||||
margin-top: 15px;
|
||||
|
||||
.check-wrap-title {
|
||||
font-size: 12px;
|
||||
color: #fff;
|
||||
font-weight: 600;
|
||||
|
||||
&.light {
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
}
|
||||
.modal-body{
|
||||
padding: 15px;
|
||||
.modal-btn-wrap{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
button{
|
||||
flex: 1;
|
||||
|
||||
.flex-check-box {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
margin-top: 15px;
|
||||
|
||||
&.for2 {
|
||||
button {
|
||||
width: calc(50% - 5px);
|
||||
}
|
||||
}
|
||||
.modal-check-btn-wrap{
|
||||
margin-top: 15px;
|
||||
.check-wrap-title{
|
||||
font-size: 12px;
|
||||
color: #fff;
|
||||
font-weight: 600;
|
||||
&.light{
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
&.btn {
|
||||
gap: 5px;
|
||||
|
||||
button {
|
||||
width: calc(50% - 2.5px);
|
||||
}
|
||||
}
|
||||
.flex-check-box{
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
margin-top: 15px;
|
||||
&.for2{
|
||||
button{
|
||||
width: calc(50% - 5px);
|
||||
}
|
||||
}
|
||||
&.for-line{
|
||||
button{
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.for-line {
|
||||
button {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.outer-line-wrap {
|
||||
border-top: 1px solid #3C3C3C;
|
||||
margin-top: 10px;
|
||||
padding-top: 15px;
|
||||
margin-bottom: 15px;
|
||||
|
||||
> div {
|
||||
margin-bottom: 15px;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,3 +1 @@
|
||||
@import '_layout.scss';
|
||||
@import '_contents.scss';
|
||||
@import '_modal.scss';
|
||||
@import '_main.scss';
|
||||
@ -992,7 +992,7 @@ export const splitPolygonWithLines = (polygon) => {
|
||||
/**
|
||||
* 좌표 테스트용
|
||||
*/
|
||||
allLines.forEach((line) => {
|
||||
/*allLines.forEach((line) => {
|
||||
const text = new fabric.Text(`(${line.startPoint.x},${line.startPoint.y})`, {
|
||||
left: line.startPoint.x,
|
||||
top: line.startPoint.y,
|
||||
@ -1021,7 +1021,7 @@ export const splitPolygonWithLines = (polygon) => {
|
||||
|
||||
polygon.canvas.add(text)
|
||||
polygon.canvas.renderAll()
|
||||
})
|
||||
})*/
|
||||
/**
|
||||
* 좌표 테스트용 끝
|
||||
*/
|
||||
@ -2732,6 +2732,7 @@ const setGableRoof = (polygon, ridge, hip1, hip2, offset, canvas) => {
|
||||
if (ridge.direction === 'top') {
|
||||
if (ridge.y1 > y1 && ridge.y2 > y1) {
|
||||
offset = Math.abs(ridge.y1 - y1) - offset
|
||||
offset = offset < 0 ? 0 : offset
|
||||
ridge.set({
|
||||
x1: ridge.x1,
|
||||
y1: ridge.y1,
|
||||
@ -2763,6 +2764,7 @@ const setGableRoof = (polygon, ridge, hip1, hip2, offset, canvas) => {
|
||||
}
|
||||
if (ridge.y1 < y1 && ridge.y2 < y1) {
|
||||
offset = Math.abs(ridge.y2 - y1) - offset
|
||||
offset = offset < 0 ? 0 : offset
|
||||
ridge.set({
|
||||
x1: ridge.x1,
|
||||
y1: ridge.y1 - offset,
|
||||
@ -2795,6 +2797,7 @@ const setGableRoof = (polygon, ridge, hip1, hip2, offset, canvas) => {
|
||||
if (ridge.direction === 'bottom') {
|
||||
if (ridge.y1 > y1 && ridge.y2 > y1) {
|
||||
offset = Math.abs(ridge.y1 - y1) - offset
|
||||
offset = offset < 0 ? 0 : offset
|
||||
ridge.set({
|
||||
x1: ridge.x1,
|
||||
y1: ridge.y1 - offset,
|
||||
@ -2825,6 +2828,7 @@ const setGableRoof = (polygon, ridge, hip1, hip2, offset, canvas) => {
|
||||
}
|
||||
if (ridge.y1 < y1 && ridge.y2 < y1) {
|
||||
offset = Math.abs(ridge.y2 - y1) - offset
|
||||
offset = offset < 0 ? 0 : offset
|
||||
ridge.set({
|
||||
x1: ridge.x1,
|
||||
y1: ridge.y1,
|
||||
@ -2858,6 +2862,7 @@ const setGableRoof = (polygon, ridge, hip1, hip2, offset, canvas) => {
|
||||
if (ridge.direction === 'right') {
|
||||
if (ridge.x1 > x1 && ridge.x2 > x1) {
|
||||
offset = Math.abs(ridge.x1 - x1) - offset
|
||||
offset = offset < 0 ? 0 : offset
|
||||
ridge.set({
|
||||
x1: ridge.x1 - offset,
|
||||
y1: ridge.y1,
|
||||
@ -2888,6 +2893,7 @@ const setGableRoof = (polygon, ridge, hip1, hip2, offset, canvas) => {
|
||||
}
|
||||
if (ridge.x1 < x1 && ridge.x2 < x1) {
|
||||
offset = Math.abs(ridge.x2 - x1) - offset
|
||||
offset = offset < 0 ? 0 : offset
|
||||
ridge.set({
|
||||
x1: ridge.x1,
|
||||
y1: ridge.y1,
|
||||
@ -2920,6 +2926,7 @@ const setGableRoof = (polygon, ridge, hip1, hip2, offset, canvas) => {
|
||||
if (ridge.direction === 'left') {
|
||||
if (ridge.x1 > x1 && ridge.x2 > x1) {
|
||||
offset = Math.abs(ridge.x1 - x1) - offset
|
||||
offset = offset < 0 ? 0 : offset
|
||||
ridge.set({
|
||||
x1: ridge.x1,
|
||||
y1: ridge.y1,
|
||||
@ -2950,6 +2957,7 @@ const setGableRoof = (polygon, ridge, hip1, hip2, offset, canvas) => {
|
||||
}
|
||||
if (ridge.x1 < x1 && ridge.x2 < x1) {
|
||||
offset = Math.abs(ridge.x2 - x1) - offset
|
||||
offset = offset < 0 ? 0 : offset
|
||||
ridge.set({
|
||||
x1: ridge.x1 - offset,
|
||||
y1: ridge.y1,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user