Merge branch 'dev' into dev-yj

This commit is contained in:
yjnoh 2024-09-09 14:55:59 +09:00
commit bab7a1a36d
10 changed files with 491 additions and 61 deletions

View 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>
</>
)
}

View File

@ -10,6 +10,7 @@ export default function Headers() {
<div className="space-x-4 text-xl"> <div className="space-x-4 text-xl">
<Link href="/intro">Intro</Link> <Link href="/intro">Intro</Link>
<Link href="/playground">Playground</Link> <Link href="/playground">Playground</Link>
<Link href="/initSettingsModal">Basic Settings</Link>
<Link href="/settings">Canvas Settings</Link> <Link href="/settings">Canvas Settings</Link>
<Link href="/roof">Roof</Link> <Link href="/roof">Roof</Link>
<Link href="/roof2">Roof2</Link> <Link href="/roof2">Roof2</Link>

View File

@ -1,22 +1,31 @@
'use client'
import { useEffect, useState, memo, useCallback } from 'react' import { useEffect, useState, memo, useCallback } from 'react'
import { Button, Checkbox, CheckboxGroup, RadioGroup, Radio, Input, Select, SelectItem } from '@nextui-org/react' import { Button, Checkbox, CheckboxGroup, RadioGroup, Radio, Input, Select, SelectItem } from '@nextui-org/react'
import { useRecoilState, useRecoilValue } from 'recoil' import { useRecoilState, useRecoilValue } from 'recoil'
import { modalContent, modalState } from '@/store/modalAtom' import { modalContent, modalState } from '@/store/modalAtom'
import { canvasSettingState } from '@/store/canvasAtom' import { canvasSettingState } from '@/store/canvasAtom'
import { useAxios } from '@/hooks/useAxios' import { useAxios } from '@/hooks/useAxios'
import { get, post } from '@/lib/Axios'
export default function InitSettingsModal(props) { export default function InitSettingsModal(props) {
const [objectNo, setObjectNo] = useState('test123240909001') //
const [open, setOpen] = useRecoilState(modalState) const [open, setOpen] = useRecoilState(modalState)
const [canvasSetting, setCanvasSetting] = useRecoilState(canvasSettingState) const [canvasSetting, setCanvasSetting] = useRecoilState(canvasSettingState)
const [roofMaterials, setRoofMaterials] = useState([]) const [roofMaterials, setRoofMaterials] = useState([])
const [basicSetting, setBasicSettings] = useState({ const [basicSetting, setBasicSettings] = useState({
type: '1', roofDrawingSet: '1',
inputType: '1', roofSizeSet: '1',
angleType: 'slope', roofAngleSet: 'slope',
roofs: [], roofs: [],
}) })
const { get, post } = useAxios() const modelProps = {
open,
setOpen,
}
//const { get, post } = useAxios()
useEffect(() => { useEffect(() => {
get({ url: '/api/roof-material/roof-material-infos' }).then((res) => { get({ url: '/api/roof-material/roof-material-infos' }).then((res) => {
@ -26,6 +35,41 @@ export default function InitSettingsModal(props) {
setRoofMaterials(res) setRoofMaterials(res)
}) })
get({ url: `/api/canvas-management/canvas-basic-settings/by-object/${objectNo}` }).then((res) => {
if (!res) return
// 'roofs'
const roofsRow = res.map((item) => {
return {
roofDrawingSet: String(item.roofDrawingSet),
roofSizeSet: String(item.roofSizeSet),
roofAngleSet: item.roofAngleSet,
}
})
const roofsArray = res.map((item) => {
return {
roofSeq: String(item.roofSeq),
roofType: String(item.roofType),
roofWidth: String(item.roofWidth),
roofHeight: String(item.roofHeight),
roofGap: String(item.roofGap),
roofLayout: item.roofLayout,
}
})
// 'roofs' patternData
const patternData = {
roofDrawingSet: roofsRow[0].roofDrawingSet, //
roofSizeSet: roofsRow[0].roofSizeSet, //
roofAngleSet: roofsRow[0].roofAngleSet, //
roofs: roofsArray, // roofs
}
//
setBasicSettings({ ...patternData })
})
if (!(Object.keys(canvasSetting).length === 0 && canvasSetting.constructor === Object)) { if (!(Object.keys(canvasSetting).length === 0 && canvasSetting.constructor === Object)) {
setBasicSettings({ ...canvasSetting }) setBasicSettings({ ...canvasSetting })
} }
@ -46,12 +90,12 @@ export default function InitSettingsModal(props) {
// //
const newRoofSettings = { const newRoofSettings = {
id: basicSetting.roofs.length + 1, roofSeq: basicSetting.roofs.length + 1,
roofId: '3', roofType: '3',
width: '200', roofWidth: '200',
height: '200', roofHeight: '200',
gap: '0', roofGap: '0',
layout: 'parallel', roofLayout: 'parallel',
} }
setBasicSettings((prevState) => ({ setBasicSettings((prevState) => ({
@ -62,19 +106,45 @@ export default function InitSettingsModal(props) {
// //
const handleRoofSettings = (id, event) => { const handleRoofSettings = (id, event) => {
const roof = basicSetting.roofs.map((roof, i) => (id === roof.id ? { ...roof, [event.target.name]: event.target.value } : roof)) const roof = basicSetting.roofs.map((roof, i) => (id === roof.roofSeq ? { ...roof, [event.target.name]: event.target.value } : roof))
setBasicSettings((prevState) => ({ setBasicSettings((prevState) => ({
...prevState, ...prevState,
roofs: [...roof], roofs: [...roof],
})) }))
} }
const submitCanvasConfig = () => { //
post({ url: '/api/canvas-config', data: basicSetting }).then((res) => { const submitCanvasConfig = async () => {
if (!res) { if (!objectNo) {
setCanvasSetting({ ...basicSetting }) alert('object_no를 입력하세요.')
} return
}) }
const patternData = {
objectNo,
roofDrawingSet: basicSetting.roofDrawingSet,
roofSizeSet: basicSetting.roofSizeSet,
roofAngleSet: basicSetting.roofAngleSet,
roofMaterialsAddList: basicSetting.roofs,
}
await post({ url: `/api/canvas-management/canvas-basic-settings`, data: patternData })
//Recoil
setCanvasSetting({ ...basicSetting })
//
//await handleSelect()
}
// id targetId
const onRemove = async (targetId) => {
console.log(targetId)
setBasicSettings((prevState) => ({
...prevState,
roofs: prevState.roofs.filter((roof) => roof.roofSeq !== targetId),
}))
// setBasicSettings({ ...newRoofSettings }) // setData()
} }
return ( return (
@ -84,7 +154,13 @@ export default function InitSettingsModal(props) {
<div className="mb-6"> <div className="mb-6">
<div className="flex space-x-4"> <div className="flex space-x-4">
<RadioGroup label="도면 작성방법" name="type" orientation="horizontal" value={basicSetting.type} onChange={handleBasicSetting}> <RadioGroup
label="도면 작성방법"
name="roofDrawingSet"
orientation="horizontal"
value={basicSetting.roofDrawingSet}
onChange={handleBasicSetting}
>
<Radio value="1">치수 입력에 의한 물건작성</Radio> <Radio value="1">치수 입력에 의한 물건작성</Radio>
</RadioGroup> </RadioGroup>
</div> </div>
@ -92,7 +168,13 @@ export default function InitSettingsModal(props) {
<div className="mb-6"> <div className="mb-6">
<div className="flex space-x-4"> <div className="flex space-x-4">
<RadioGroup label="치수 입력방법" name="inputType" orientation="horizontal" value={basicSetting.inputType} onChange={handleBasicSetting}> <RadioGroup
label="치수 입력방법"
name="roofSizeSet"
orientation="horizontal"
value={basicSetting.roofSizeSet}
onChange={handleBasicSetting}
>
<Radio value="1">복사도 입력</Radio> <Radio value="1">복사도 입력</Radio>
<Radio value="2">실측값 입력</Radio> <Radio value="2">실측값 입력</Radio>
<Radio value="3">육지붕</Radio> <Radio value="3">육지붕</Radio>
@ -102,13 +184,20 @@ export default function InitSettingsModal(props) {
<div className="mb-6"> <div className="mb-6">
<div className="flex space-x-4"> <div className="flex space-x-4">
<RadioGroup label="지붕각도 설정" name="angleType" orientation="horizontal" value={basicSetting.angleType} onChange={handleBasicSetting}> <RadioGroup
label="지붕각도 설정"
name="roofAngleSet"
orientation="horizontal"
value={basicSetting.roofAngleSet}
onChange={handleBasicSetting}
>
<Radio value="slope">경사</Radio> <Radio value="slope">경사</Radio>
<Radio value="angle">각도</Radio> <Radio value="angle">각도</Radio>
</RadioGroup> </RadioGroup>
</div> </div>
</div> </div>
<div className="flex space-x-4">지붕재 추가(단위 : mm)</div>
<div className="flex items-center mb-4"> <div className="flex items-center mb-4">
<button className="px-3 py-1 bg-blue-500 text-white rounded mr-3" onClick={addRoofSetting}> <button className="px-3 py-1 bg-blue-500 text-white rounded mr-3" onClick={addRoofSetting}>
Add Add
@ -118,7 +207,7 @@ export default function InitSettingsModal(props) {
{basicSetting.roofs && {basicSetting.roofs &&
basicSetting.roofs.map((roof, index) => { basicSetting.roofs.map((roof, index) => {
return <RoofSelectBox roofMaterials={roofMaterials} roof={roof} key={index} onChange={handleRoofSettings} /> return <RoofSelectBox roofMaterials={roofMaterials} roof={roof} key={index} onChange={handleRoofSettings} onRemove={onRemove} />
})} })}
<div className="flex gap-4 items-right"> <div className="flex gap-4 items-right">
@ -128,6 +217,7 @@ export default function InitSettingsModal(props) {
<Button size="sm" onClick={() => setOpen(!open)}> <Button size="sm" onClick={() => setOpen(!open)}>
취소 취소
</Button> </Button>
<input type="text" placeholder="Object No 입력" value={objectNo} onChange={(e) => setObjectNo(e.target.value)} />
</div> </div>
</div> </div>
</> </>
@ -137,15 +227,16 @@ export default function InitSettingsModal(props) {
const RoofSelectBox = (props) => { const RoofSelectBox = (props) => {
return ( return (
<div className="mb-4 flex flex-wrap items-center space-x-4" style={{ border: '1px solid black' }}> <div className="mb-4 flex flex-wrap items-center space-x-4" style={{ border: '1px solid black' }}>
<span> 타입 : </span>
<Select <Select
aria-label="roofMaterial" aria-label="roofMaterial"
className={'w-52'} className={'w-52'}
name="roofId" name="roofType"
onChange={(e) => props.onChange(props.roof.id, e)} onChange={(e) => props.onChange(props.roof.roofSeq, e)}
items={props.roofMaterials} items={props.roofMaterials}
defaultSelectedKeys={props.roof.roofId ? props.roof.roofId : ''} defaultSelectedKeys={props.roof.roofType ? props.roof.roofType : ''}
selectedKeys={props.roof.roofId} selectedKeys={props.roof.roofType}
value={props.roof.roofId} value={props.roof.roofType}
> >
{(roofMaterial) => ( {(roofMaterial) => (
<SelectItem key={roofMaterial.id} value={roofMaterial.id}> <SelectItem key={roofMaterial.id} value={roofMaterial.id}>
@ -153,37 +244,58 @@ const RoofSelectBox = (props) => {
</SelectItem> </SelectItem>
)} )}
</Select> </Select>
<span> 너비 : </span>
<Input <Input
type="text" type="text"
name="width" name="roofWidth"
placeholder="너비" placeholder="너비"
value={props.roof.width} value={props.roof.roofWidth}
className="w-24" className="w-24"
onChange={(e) => props.onChange(props.roof.id, e)} onChange={(e) => props.onChange(props.roof.roofSeq, e)}
/>
<Input
type="text"
name="height"
placeholder="높이"
value={props.roof.height}
className="w-24"
onChange={(e) => props.onChange(props.roof.id, e)}
/> />
mm mm
<Input type="text" name="gap" placeholder="간격" value={props.roof.gap} className="w-24" onChange={(e) => props.onChange(props.roof.id, e)} /> <span> 높이 : </span>
<Input
type="text"
name="roofHeight"
placeholder="높이"
value={props.roof.roofHeight}
className="w-24"
onChange={(e) => props.onChange(props.roof.roofSeq, e)}
/>
mm
<span> 서까래 간격 : </span>
<Input
type="text"
name="roofGap"
placeholder="간격"
value={props.roof.roofGap}
className="w-24"
onChange={(e) => props.onChange(props.roof.roofSeq, e)}
/>
mm mm
<div className="flex space-x-4"> <div className="flex space-x-4">
<RadioGroup <RadioGroup
orientation="horizontal" orientation="horizontal"
name="layout" name="roofLayout"
value={props.roof.layout} value={props.roof.roofLayout}
defaultValue="parallel" defaultValue="parallel"
onChange={(e) => props.onChange(props.roof.id, e)} onChange={(e) => props.onChange(props.roof.roofSeq, e)}
> >
<Radio value="parallel">병렬식</Radio> <Radio value="parallel">병렬식</Radio>
<Radio value="cascade">계단식</Radio> <Radio value="cascade">계단식</Radio>
</RadioGroup> </RadioGroup>
</div> </div>
<div className="flex space-x-4">
<Button
size="sm"
onClick={() => {
props.onRemove(props.roof.roofSeq)
}}
>
삭제
</Button>
</div>
</div> </div>
) )
} }

View File

@ -6,12 +6,57 @@ import { Button } from '@nextui-org/react'
import { get, post } from '@/lib/Axios' import { get, post } from '@/lib/Axios'
import { useRecoilState } from 'recoil' import { useRecoilState } from 'recoil'
import { customSettingsState } from '@/store/canvasAtom' import { customSettingsState } from '@/store/canvasAtom'
import { modalContent, modalState } from '@/store/modalAtom'
import ColorPicker from './common/color-picker/ColorPicker'
export default function Settings() { export default function Settings() {
const [objectNo, setObjectNo] = useState('test123240829010') const [objectNo, setObjectNo] = useState('test123240829010')
const [error, setError] = useState(null) const [error, setError] = useState(null)
const [customSettings, setCustomSettings] = useRecoilState(customSettingsState) const [customSettings, setCustomSettings] = useRecoilState(customSettingsState)
const [color, setColor] = useState('#ff0000')
const [open, setOpen] = useRecoilState(modalState)
const [contents, setContent] = useRecoilState(modalContent)
const handleSavePopup = () => {
console.log('color ', color)
}
const handleClosePopup = () => {
setContent('')
setOpen(false)
console.log('colorSetting ', color)
}
const colorSetting = (
<>
<br />
<h1>React ColorPicker</h1>
<ColorPicker color={color} setColor={setColor} />
<div className="p-4">{color}</div>
<div>
<button onClick={handleSavePopup}>저장</button> <p />
<button onClick={handleClosePopup}>취소</button>
</div>
</>
)
const customStyles = {
overlay: {
backgroundColor: 'rgba(0,0,0,0.5)',
},
content: {
width: '300px',
height: '400px',
margin: 'auto',
borderRadius: '4px',
boxShadow: '0 2px 4px rgba(0,0,0,0.2)',
padding: '20px',
},
}
// //
const [settings, setSettings] = useState({ const [settings, setSettings] = useState({
display1: Array(11).fill(false), // 1 display1: Array(11).fill(false), // 1
@ -48,6 +93,21 @@ export default function Settings() {
// //
const handleToggle = (type, index) => { const handleToggle = (type, index) => {
// ' '
if (type === 'gridSettings' && gridItems.gridSettings[index] === '실선 그리드') {
//openGridPopup()
}
// ' '
if (type === 'gridSettings' && gridItems.gridSettings[index] === '그리드 색 설정') {
//setSelectedGridSetting(gridItems.gridSettings[index])
//setIsPopupOpen(true)
//return prevSettings //
setOpen(true)
setContent({ ...colorSetting })
}
setSettings((prevSettings) => { setSettings((prevSettings) => {
// prevSettings[type] , // prevSettings[type] ,
let updated = Array.isArray(prevSettings[type]) ? [...prevSettings[type]] : [] let updated = Array.isArray(prevSettings[type]) ? [...prevSettings[type]] : []
@ -61,6 +121,24 @@ export default function Settings() {
}) })
} }
// ' '
const openGridPopup = () => {
const popupWidth = 500
const popupHeight = 300
//
const left = window.innerWidth / 2 - popupWidth / 2
const top = window.innerHeight / 2 - popupHeight / 2
//
window
.open
//'./components/intro', // URL
//'_blank', //
//`width=${popupWidth},height=${popupHeight},top=${top},left=${left}`, //
()
}
// Canvas Setting // Canvas Setting
const handleSelect = async () => { const handleSelect = async () => {
try { try {
@ -221,6 +299,10 @@ export default function Settings() {
<div className="grid-item">흡착점 ON</div> <div className="grid-item">흡착점 ON</div>
</div> </div>
<h1>[그리드 설정]</h1> <h1>[그리드 설정]</h1>
<div>
<ColorPicker color={color} setColor={setColor} />
<div className="p-4">{color}</div>
</div>
<div className="grid-container2"> <div className="grid-container2">
{gridItems.gridSettings.map((item, index) => ( {gridItems.gridSettings.map((item, index) => (
<div <div

View File

@ -127,6 +127,9 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
this.on('modified', (e) => { this.on('modified', (e) => {
this.addLengthText() this.addLengthText()
if (this.arrow) {
drawDirectionArrow(this)
}
}) })
this.on('selected', () => { this.on('selected', () => {
@ -144,6 +147,17 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
this.canvas.remove(text) this.canvas.remove(text)
}) })
this.texts = null this.texts = null
if (this.arrow) {
this.canvas.remove(this.arrow)
this.canvas
.getObjects()
.filter((obj) => obj.name === 'directionText' && obj.parent === this.arrow)
.forEach((text) => {
this.canvas.remove(text)
})
this.arrow = null
}
}) })
// polygon.fillCell({ width: 50, height: 30, padding: 10 }) // polygon.fillCell({ width: 50, height: 30, padding: 10 })

View File

@ -32,7 +32,7 @@ import {
import { QLine } from '@/components/fabric/QLine' import { QLine } from '@/components/fabric/QLine'
import { fabric } from 'fabric' import { fabric } from 'fabric'
import { QPolygon } from '@/components/fabric/QPolygon' import { QPolygon } from '@/components/fabric/QPolygon'
import offsetPolygon from '@/util/qpolygon-utils' import offsetPolygon, { inPolygon } from '@/util/qpolygon-utils'
import { isObjectNotEmpty } from '@/util/common-utils' import { isObjectNotEmpty } from '@/util/common-utils'
import * as turf from '@turf/turf' import * as turf from '@turf/turf'
import { Mode } from '@/common/common' import { Mode } from '@/common/common'
@ -1061,8 +1061,25 @@ export function useMode() {
origY: 0, origY: 0,
down: (o) => { down: (o) => {
if (mode !== Mode.OPENING) return if (mode !== Mode.OPENING) return
mouseEvent.openingMode.isDown = true const roofs = canvas?._objects.filter((obj) => obj.name === 'roof')
if (roofs.length === 0) {
alert('지붕을 먼저 그려주세요')
setMode(Mode.DEFAULT)
return
}
const pointer = canvas.getPointer(o.e) const pointer = canvas.getPointer(o.e)
let selectRoof = null
roofs.forEach((roof) => {
if (roof.inPolygon({ x: pointer.x, y: pointer.y })) {
selectRoof = roof
}
})
if (!selectRoof) {
alert('지붕 내부에만 생성 가능합니다.')
return
}
mouseEvent.openingMode.isDown = true
mouseEvent.openingMode.origX = pointer.x mouseEvent.openingMode.origX = pointer.x
mouseEvent.openingMode.origY = pointer.y mouseEvent.openingMode.origY = pointer.y
mouseEvent.openingMode.rect = new fabric.Rect({ mouseEvent.openingMode.rect = new fabric.Rect({
@ -1123,17 +1140,21 @@ export function useMode() {
return false return false
} }
const rectPoints = [
{ x: rect.left, y: rect.top },
{ x: rect.left, y: rect.top + rect.height },
{ x: rect.left + rect.width, y: rect.top + rect.height },
{ x: rect.left + rect.width, y: rect.top },
]
for (let i = 0; i < openings.length; i++) { for (let i = 0; i < openings.length; i++) {
const rect2 = openings[i] const rect2 = openings[i]
// Check if one rectangle is to the left of the other const rect2Points = [
if (rect.x + rect.width <= rect2.x || rect2.x + rect2.width <= rect.x) { { x: rect2.left, y: rect2.top },
return true { x: rect2.left, y: rect2.top + rect2.height },
} { x: rect2.left + rect2.width, y: rect2.top + rect2.height },
{ x: rect2.left + rect2.width, y: rect2.top },
// Check if one rectangle is above the other ]
if (rect.y + rect.height <= rect2.y || rect2.y + rect2.height <= rect.y) {
return true
}
} }
return false return false
@ -1147,6 +1168,7 @@ export function useMode() {
canvas?.remove(rect) canvas?.remove(rect)
return false return false
} }
return result return result
} }

View File

@ -1,3 +1,90 @@
{ {
"hi": "こんにちは" "hi": "こんにちは",
"common.message.no.data": "No data",
"common.message.no.dataDown": "ダウンロードするデータがありません",
"common.message.noData": "表示するデータがありません",
"common.message.search": "search success",
"common.message.insert": "insert success",
"common.message.update": "update success",
"common.message.delete": "削除",
"common.message.restoration": "復元",
"common.message.cancel": "キャンセル",
"common.message.send": "メールを送信しました.",
"common.message.no.delete": "削除するデータがありません",
"common.message.save": "保存",
"common.message.transfer": "転送",
"common.message.batch.exec": "batch success",
"common.message.not.mov": "移動できません.",
"common.message.required.data": "{0} は入力必須項目となります。",
"common.message.save.error": "データの保存中にエラーが発生しました。 サイト管理者にお問い合わせください。",
"common.message.transfer.error": "データの転送中にエラーが発生しました。 サイト管理者にお問い合わせください。",
"common.message.delete.error": "データの削除中にエラーが発生しました。 サイト管理者にお問い合わせください。",
"common.message.batch.error": "バッチの実行中にエラーが発生しました。 サイト管理者に連絡してください。",
"common.message.send.error": "データの送信中にエラーが発生しました。サイト管理者にお問い合わせください",
"common.message.communication.error": "ネットワークエラーが発生しました。サイト管理者に連絡してください。",
"common.message.data.error": "{0} はデータ形式が無効です。",
"common.message.data.setting.error": "{0} は削除されたか、すでに構成されているデータです。",
"common.message.parameter.error": "パラメータエラー",
"common.message.product.parameter.error": "存在しない製品があります。",
"common.message.customer.parameter.error": "存在しない顧客があります。",
"common.message.file.exists.error": "ファイルが正常にアップロードされないためにエラーが発生しました",
"common.message.file.download.exists": "ファイルが存在しません。",
"common.message.file.download.error": "ァイルのダウンロードエラー",
"common.message.file.template.validation01": "フォルダをアップロードできません",
"common.message.file.template.validation02": "アップロードできるのはExcelファイルのみです。",
"common.message.file.template.validation03": "登録できない拡張子です",
"common.message.file.template.validation04": "容量を超えています アップロード可能な容量:{0} MB",
"common.message.file.template.validation05": "アップロードファイルを選択して下さい",
"common.message.multi.insert": "合計 {0} 件数 ({1}成功、 {2} 失敗 {3})",
"common.message.error": "エラーが発生しました。サイト管理者に連絡してください。",
"common.message.data.save": "保存しますか?",
"common.message.data.delete": " 削除しますか?",
"common.message.data.exists": "{0} はすでに存在するデータです。",
"common.message.data.no.exists": "{0} は存在しないデータです。",
"common.message.all": "All",
"common.message.tab.close.all": "すべてのタブを閉じますか?",
"common.message.transfer.save": "{0}件転送しますか?",
"common.message.confirm.save": "保存しますか?",
"common.message.confirm.confirm": "承認しますか?",
"common.message.confirm.request": "承認リクエストしますか?",
"common.message.confirm.delete": "削除しますか?",
"common.message.confirm.close": "閉じますか?",
"common.message.confirm.unclose": "クローズ中止しますか?",
"common.message.confirm.cancel": "キャンセルしますか?",
"common.message.confirm.uncancel": "キャンセル中止しますか?",
"common.message.confirm.copy": "コピーしますか?",
"common.message.confirm.createSo": "S/O作成しますか",
"common.message.confirm.mark": "保存完了",
"common.message.confirm.mail": "メールを送信しますか?",
"common.message.confirm.printPriceItem": "価格を印刷しますか?",
"common.message.confirm.allAppr ": "Do you want to Batch approve the selected data?",
"common.message.confirm.deliveryFee": "送料を登録しますか?",
"common.message.success.delete": "削除完了",
"common.message.success.close": "閉じる",
"common.message.success.unclose": "キャンセルしました",
"common.message.validation.date": "終了日を開始日より前にすることはできません。 もう一度入力してください。",
"common.message.no.editfield": "フィールドを編集できません",
"common.message.success.rmmail": "リスク管理チームにメールを送信しました。",
"common.message.password.validation01": "パスワードの変更が一致しません。",
"common.message.password.validation02": "英語、数字、特殊文字を組み合わせた8桁以上を入力してください。",
"common.message.password.validation03": "パスワードをIDと同じにすることはできません。",
"common.message.menu.validation01": "注文を保存するメニューはありません.",
"common.message.menu.validation02": "The same sort order exists.",
"common.message.menuCode.check01": "登録可能",
"common.message.menuCode.check02": "登録できません",
"common.message.pleaseSelect": "{0}を選択してください",
"common.message.pleaseInput": "{0}を入力してください。",
"common.message.pleaseInputOr": "{0}または{1}を入力してください。",
"common.message.approved ": "承認済み",
"common.message.errorFieldExist": "エラー項目が存在します",
"common.message.storeIdExist ": "既に利用されている販売店IDです",
"common.message.userIdExist ": "すでに使用しているユーザーID。",
"common.message.noExists ": "削除された掲示物です",
"common.message.emailReqTo": "メール宛先が必要です",
"common.message.downloadPeriod": "ダウンロード検索期間を{0}日以内に選択してください。",
"common.message.backToSubmit": "販売店ブロック解除実行しますか?",
"common.message.backToG3": "Back to G3処理実行しますか",
"common.message.writeToConfirm": "作成解除を実行しますか?",
"common.message.password.init.success": "パスワード [{0}] に初期化されました。",
"common.message.no.edit.save": "この文書は変更できません。"
} }

View File

@ -1,3 +1,90 @@
{ {
"hi": "안녕하세요" "hi": "안녕하세요",
"common.message.no.data": "No data",
"common.message.no.dataDown": "No data to download",
"common.message.noData": "No data to display",
"common.message.search": "search success",
"common.message.insert": "insert success",
"common.message.update": "update success",
"common.message.delete": "Deleted",
"common.message.restoration": "Restored",
"common.message.cancel": "Canceled",
"common.message.send": "The mail has been sent.",
"common.message.no.delete": "There is no data to delete.",
"common.message.save": "Saved.",
"common.message.transfer": "Transfered",
"common.message.batch.exec": "batch success",
"common.message.not.mov": "Its impossible to move.",
"common.message.required.data": "{0} is required input value.",
"common.message.save.error": "An error occurred while saving the data. Please contact site administrator.",
"common.message.transfer.error": "An error occurred while transfer the data. Please contact site administrator.",
"common.message.delete.error": "An error occurred while deleting data. Please contact site administrator.",
"common.message.batch.error": "An error occurred while executing the batch. Please contact site administrator.",
"common.message.send.error": "Error sending data, please contact your administrator.",
"common.message.communication.error": "Network error occurred. \n Please contact site administrator.",
"common.message.data.error": "{0} The data format is not valid.",
"common.message.data.setting.error": "{0} is data that has been deleted or already configured.",
"common.message.parameter.error": "Parameter Error",
"common.message.product.parameter.error": "존재하지 않는 제품이 있습니다.",
"common.message.customer.parameter.error": "존재하지 않는 고객이 있습니다.",
"common.message.file.exists.error": "Error due to file not uploading normally",
"common.message.file.download.exists": "File does not exist.",
"common.message.file.download.error": "File download error",
"common.message.file.template.validation01": "Unable to upload folder",
"common.message.file.template.validation02": "Only Excel files can be uploaded.",
"common.message.file.template.validation03": "Non-registerable extension",
"common.message.file.template.validation04": "Exceed capacity \n Uploadable capacity : {0} MB",
"common.message.file.template.validation05": "업로드 파일을 선택해주세요.",
"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.exists": "{0} is data that already exists.",
"common.message.data.no.exists": "{0} is data that does not exist.",
"common.message.all": "All",
"common.message.tab.close.all": "Close all tabs?",
"common.message.transfer.save": "Want to {0} transfer it?",
"common.message.confirm.save": "Want to save it?",
"common.message.confirm.confirm": "Want to approve?",
"common.message.confirm.request": "Would you like to request a Approval?",
"common.message.confirm.delete": "Do you want to delete it?",
"common.message.confirm.close": "Want to close?",
"common.message.confirm.unclose": "Do you want to cancel the close?",
"common.message.confirm.cancel": "Want to cancellation?",
"common.message.confirm.uncancel": "Do you want to cancel the cancellation?",
"common.message.confirm.copy": "Do you want to copy?",
"common.message.confirm.createSo": "Create Sales Order?",
"common.message.confirm.mark": "Saved.",
"common.message.confirm.mail": "Do you want to send mail?",
"common.message.confirm.printPriceItem": "Would you like to print item price?",
"common.message.confirm.allAppr ": "Do you want to Batch approve the selected data?",
"common.message.confirm.deliveryFee": "Do you want to register shipping fee?",
"common.message.success.delete": "Deleted.",
"common.message.success.close": "Closed.",
"common.message.success.unclose": "Cancel Closed.",
"common.message.validation.date": "The end date cannot be earlier than the start date. Please enter it again.",
"common.message.no.editfield": "Can not edit field",
"common.message.success.rmmail": "You have successfully sent mail to the Risk Management team.",
"common.message.password.validation01": "Change passwords do not match.",
"common.message.password.validation02": "Please enter at least 8 digits combining English, numbers, and special characters.",
"common.message.password.validation03": "Password cannot be the same as ID.",
"common.message.menu.validation01": "There is no menu to save the order.",
"common.message.menu.validation02": "The same sort order exists.",
"common.message.menuCode.check01": "Registerable",
"common.message.menuCode.check02": "Unable to register",
"common.message.pleaseSelect": "Please Select {0}",
"common.message.pleaseInput": "Please Input a {0}.",
"common.message.pleaseInputOr": "Please Input a {0} or {1}.",
"common.message.approved ": "Approved.",
"common.message.errorFieldExist": "Error Field Exist",
"common.message.storeIdExist ": "이미 사용하고 있는 판매점 ID 입니다.",
"common.message.userIdExist ": "이미 사용하고 있는 사용자 ID 입니다.",
"common.message.noExists ": "삭제된 게시물 입니다.",
"common.message.emailReqTo": "Email To is required",
"common.message.downloadPeriod": "Please select the download search period within {0} days.",
"common.message.backToSubmit": "판매점 블록 해제를 실행하시겠습니까?",
"common.message.backToG3": "Back to G3 처리를 실행하시겠습니까?",
"common.message.writeToConfirm": "작성 해제를 실행하시겠습니까?",
"common.message.password.init.success": "비밀번호 [{0}]로 초기화 되었습니다.",
"common.message.no.edit.save": "This document cannot be changed."
} }

View File

@ -171,5 +171,5 @@ export const surfacePlacementModeState = atom({
// 오브젝트 배치 모드 // 오브젝트 배치 모드
export const objectPlacementModeState = atom({ export const objectPlacementModeState = atom({
key: 'objectPlacementMode', key: 'objectPlacementMode',
default: { width: 0, height: 0, areaBoundary: true, inputType: 'free', batchType: 'opening' }, default: { width: 0, height: 0, areaBoundary: false, inputType: 'free', batchType: 'opening' },
}) })

View File

@ -2714,6 +2714,12 @@ export const drawDirectionArrow = (polygon) => {
if (!direction) { if (!direction) {
return return
} }
polygon.canvas
.getObjects()
.filter((obj) => obj.name === 'directionText' && obj.parent === polygon.arrow)
.forEach((obj) => polygon.canvas.remove(obj))
let arrow = null let arrow = null
let points = [] let points = []
@ -2721,13 +2727,13 @@ export const drawDirectionArrow = (polygon) => {
polygon.canvas.remove(polygon.arrow) polygon.canvas.remove(polygon.arrow)
} }
let centerPoint = polygon.getCenterPoint() let centerPoint = { x: polygon.width / 2 + polygon.left, y: polygon.height / 2 + polygon.top }
let stickeyPoint let stickeyPoint
const polygonMaxX = Math.max(...polygon.points.map((point) => point.x)) const polygonMaxX = Math.max(...polygon.getCurrentPoints().map((point) => point.x))
const polygonMinX = Math.min(...polygon.points.map((point) => point.x)) const polygonMinX = Math.min(...polygon.getCurrentPoints().map((point) => point.x))
const polygonMaxY = Math.max(...polygon.points.map((point) => point.y)) const polygonMaxY = Math.max(...polygon.getCurrentPoints().map((point) => point.y))
const polygonMinY = Math.min(...polygon.points.map((point) => point.y)) const polygonMinY = Math.min(...polygon.getCurrentPoints().map((point) => point.y))
switch (direction) { switch (direction) {
case 'north': case 'north':
@ -2800,6 +2806,7 @@ export const drawDirectionArrow = (polygon) => {
polygon.arrow = arrow polygon.arrow = arrow
polygon.canvas.add(arrow) polygon.canvas.add(arrow)
polygon.canvas.renderAll() polygon.canvas.renderAll()
drawDirectionStringToArrow(polygon.canvas, 0)
} }
/** /**
@ -2807,7 +2814,7 @@ export const drawDirectionArrow = (polygon) => {
* @param canvas * @param canvas
* @param compass * @param compass
*/ */
export const drawDirectionStringToArrow = (canvas, compass, fontSize) => { export const drawDirectionStringToArrow = (canvas, compass = 0) => {
const arrows = canvas?.getObjects().filter((obj) => obj.name === 'arrow') const arrows = canvas?.getObjects().filter((obj) => obj.name === 'arrow')
if (arrows.length === 0) { if (arrows.length === 0) {
@ -3000,8 +3007,10 @@ const addTextByArrows = (arrows, txt, canvas) => {
originX: 'center', originX: 'center',
originY: 'center', originY: 'center',
name: 'directionText', name: 'directionText',
selectable: false,
left: arrow.stickeyPoint.x, left: arrow.stickeyPoint.x,
top: arrow.stickeyPoint.y, top: arrow.stickeyPoint.y,
parent: arrow,
}) })
canvas.add(text) canvas.add(text)
}) })