
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
<template>
<div class="container">
<div class="page-titleZone flex justify-between align-start">
<p class="main-title">데이터 현황관리 차트 등록</p>
<!-- <button @click="test">test</button> -->
<PageNavigation />
</div>
<div class="content-wrap content">
<div class="row">
<JobContainer :jobGroup="jobGroup" @getDataTable="getResult" />
</div>
<div class="row custom-tab">
<div class="content-box flex justify-between align-start">
<div
:class="{
'tab-zone': true,
flex40: accordion === false,
flex5: accordion === true,
}"
>
<div class="tab-nav flex justify-between align-center">
<ul
class="flex justify-start"
:style="accordion === true ? { display: 'none' } : {}"
>
<li
v-for="(tab, idx) in tabMenu"
:key="idx"
@click="showTab(tab.tabNic)"
>
<a :class="{ activeTab: activeTab === tab.tabNic }">{{
tab.tabName
}}</a>
</li>
</ul>
<button @click="accordionToggle">
<svg-icon type="mdi" :path="path" :color="'#333'"></svg-icon>
</button>
</div>
<div
class="tab-content"
:style="accordion === true ? { display: 'none' } : {}"
>
<div class="content-box flex" v-show="activeTab === 'columnList'">
<div
class="content-list layout flex-column justify-between flex40"
>
<div class="layout-tree">
<span class="section-title mb10">레이아웃 리스트</span>
<ul class="" style="height: 30%"></ul>
</div>
<div class="layout-zone">
<span class="section-title mb10">레이아웃</span>
<ul class="layout-content flex justify-center align-center">
<li
id="horizontal-btn"
class="cursor"
@click="addSplitterLayout"
title="수직레이아웃"
>
<!-- 레이아웃 id 부여 -->
<p
class="vertical-icon flex justify-around align-center"
>
<span></span>
<span></span>
</p>
</li>
<li
id="vertical-btn"
class="cursor"
@click="addSplitterLayout"
title="수평레이아웃"
>
<!-- 레이아웃 id 부여 -->
<p
class="flex-column justify-around align-center horizental-icon"
>
<span></span>
<span></span>
</p>
</li>
</ul>
</div>
<div class="btn-wrap">
<button @click="optionModal" class="blue-btn large-btn">
레이아웃 옵션
</button>
</div>
</div>
<div class="layout-option flex-column justify-between flex60">
<div class="modal-title">
<div class="flex justify-between align-center">
<span class="section-title">레이아웃 옵션</span>
<button class="close-btn" @click="closeModal">
<svg-icon
type="mdi"
:width="20"
:height="20"
:path="closePath"
></svg-icon>
</button>
</div>
</div>
<div class="modal-content-monthly">
<CellOption />
<BackgroundOption />
</div>
<div class="modal-end flex justify-end">
<button class="gray-border-btn small-btn">취소</button>
<button class="blue-border-btn small-btn">적용</button>
</div>
</div>
</div>
<div class="content-box" v-show="activeTab === 'viewSetting'">
<div class="content-list">
<div class="component-zone">
<details>
<summary>요소 선택</summary>
<ul class="component-content">
<li
id="HorizentalTwoData"
class="flex align-center cursor"
@click="addComponent"
>
<img
src="../../../resources/img/componentIcon/icon2.png"
/>
</li>
<li
id="ThreeData"
class="flex align-center cursor"
@click="addComponent"
>
<img
src="../../../resources/img/componentIcon/icon1.png"
/>
</li>
<li
id="HorizentalThreeData"
class="flex align-center cursor"
@click="addComponent"
>
<img
src="../../../resources/img/componentIcon/icon5.png"
/>
</li>
<li
id="TableData"
class="flex align-center cursor"
@click="addComponent"
>
<img
src="../../../resources/img/componentIcon/icon3.png"
/>
</li>
<li class="flex align-center cursor">
<img
src="../../../resources/img/componentIcon/icon4.png"
/>
</li>
<!-- 2024.02.16 PJH -->
<li
id="equipmentData"
class="flex align-center cursor"
@click="reOption"
>
<img
src="../../../resources/img/componentIcon/equipment.png"
/>
</li>
</ul>
</details>
</div>
<div class="chart-zone">
<details>
<summary>chart 선택</summary>
<ul class="component-content flex justify-between">
<li class="flex30">
<img
src="../../../resources/img/chartIcon/bar_b.png"
/>
</li>
<li id="HorizentalTwoData" class="flex30">
<img
src="../../../resources/img/chartIcon/rowbar_b.png"
/>
</li>
<li id="ThreeData" class="flex30">
<img
src="../../../resources/img/chartIcon/line_b.png"
/>
</li>
<li id="HorizentalThreeData" class="flex30">
<img
src="../../../resources/img/chartIcon/pie_b.png"
/>
</li>
<li id="TableData" class="flex30">
<img
src="../../../resources/img/chartIcon/dounet_b.png"
/>
</li>
<li class="flex30">
<img
src="../../../resources/img/chartIcon/colbarline_b.png"
/>
</li>
<li class="flex30">
<img
src="../../../resources/img/chartIcon/barline_b.png"
/>
</li>
<li class="flex30">
<img
src="../../../resources/img/chartIcon/brokenline_b.png"
/>
</li>
<li class="flex30">
<img
src="../../../resources/img/chartIcon/line2_b.png"
/>
</li>
</ul>
</details>
</div>
</div>
</div>
</div>
</div>
<!-- 미리보기 -->
<div
:class="{
'preview-zone': true,
flex60: accordion === false,
flex95: accordion === true,
}"
>
<div
id="splitter-container"
ref="splitterContainer"
@click="handleSplitterComponentClick"
:class="{ active: clickElement === 'splitter-container' }"
>
<SplitterLayout
v-if="showSplit"
id="SplitterLayout"
:splitInfo="splitInfo"
:clickElement="clickElement"
:optionChangeClick="optionChangeClick"
:componentOptn="componentOptn"
:inputVal="inputVal"
@parentInfo="parentInfo"
>
</SplitterLayout>
</div>
<div class="flex justify-end" id="buttonZone">
<button
class="blue-border-btn small-btn"
id="registerButton"
@click="registerLayout"
>
등록
</button>
<button
class="orange-border-btn small-btn"
id="editButton"
style="display: none"
>
수정
</button>
<button
class="darkg-border-btn small-btn"
id="resetButton"
@click="resetLayout"
>
초기화
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import SplitterLayout from "../../component/SplitterLayout.vue";
import JobContainer from "../../component/connection/jobContainer.vue";
import axios from "axios";
import store from "../AppStore";
import SvgIcon from "@jamescoyle/vue-icon";
import { mdiChevronLeftBox, mdiChevronRightBox, mdiClose } from "@mdi/js";
import BackgroundOption from "../../component/style/BackgroundOption.vue";
import CellOption from "../../component/style/CellOption.vue";
export default {
openPopup: {
type: Boolean,
default: false,
},
data() {
return {
closePath: mdiClose,
// store: store,
tabMenu: [
{ tabName: "레이아웃", tabNic: "columnList" },
{ tabName: "컴포넌트", tabNic: "viewSetting" },
],
activeTab: "columnList",
showSplit: false, // splitterLayout 태그 렌더링 여부
clickElement: null, // 클릭한 요소의 id 값 들어가는 변수
layoutVal: null, // 레이아웃 클릭에 따른 layoutNm 값을 위한 변수
option2: false,
option1: true,
// 최상위 레이아웃 정보 담는 객체
splitInfo: {
splitterId: null, // splitter 고유 id
layoutNm: null, // splitter 고유 id
type: null, // s, p
parentId: null, // 부모 splitterId, 없는 경우 null
children: [], // 자식 splitter, panel 정보
index: null, // 위치 index
minWidth: 0,
minHeight: 0,
layoutType: null, // horizontal, vertical
sizes: [], // splitter 사이즈
componentNm: null, // 컴포넌트 이름
componentOption: {}, // 컴포넌트 옵션 정보
},
// 레이아웃 기본 정보 담는 객체
splitChildInfo: {
layoutNm: null, // splitter 고유 id
type: null, // s, p
parentId: null, // 부모 splitterId, 없는 경우 null
children: [], // 자식 splitter, panel 정보
index: null, // 위치 index
minWidth: 0,
minHeight: 0,
layoutType: null, // horizontal, vertical
sizes: [], // splitter 사이즈
componentNm: null, // 컴포넌트 이름
componentOption: {}, // 컴포넌트 옵션 정보
},
splitDepth: 0, // splitter 고유 id 생성을 위한 깊이
// 요소 옵션 정보
componentOptn: {
key: null,
parent: null,
textData: "new title",
columnData: 0,
unitData: "%",
textSize: 16,
textAlign: null,
textStyle: null,
backColor: null,
},
clickComponentParentInfo: null,
jobGroup: {},
getDataTable: {},
columnList: [],
// 게시판 정보
customTitle: null, // 제목
customComment: null, // 설명
// 클릭한 요소의 data-type 값
selectedOptionDataset: null,
selectedLayout: null,
isbackColor: false,
istextCk: true,
// 2024.02.16 PJH
// Unity project 호출 정보
projectInfo: {
command: "getProject",
projectId: "project1",
objectList: [
{
command: "getObj",
projectId: "project1",
objectId: "object1",
presetId: "preset5",
position: { x: 0, y: 0.5, z: 0 },
rotation: { x: 0, y: 0, z: 0 },
pointList: [],
},
],
},
projects: [],
objects: [],
points: [],
sensors: [],
message: {},
changeInfo: null,
selectPointId: null,
nowSensorId: null,
pageId: null,
selectPointId: null,
nowSensorId: null,
path: mdiChevronLeftBox,
accordion: false,
};
},
methods: {
showTab: function (tabName) {
this.activeTab = tabName;
},
accordionToggle: function () {
this.accordion = !this.accordion;
if (!this.accordion) {
this.path = mdiChevronLeftBox;
} else {
this.path = mdiChevronRightBox;
}
},
// 2024.02.16 PJH
fetchData: function () {
let projectData = [
{ projectId: "project1", projectName: "모델1" },
{ projectId: "project2", projectName: "모델2" },
];
this.projects = projectData;
let objectData = [
{
projectId: "project1",
objectId: "object1",
objectName: "오브젝트1",
presetId: "preset5",
position: { x: 0, y: 0.5, z: 0 },
rotation: { x: 0, y: 0, z: 0 },
},
{
projectId: "project2",
objectId: "object2",
objectName: "오브젝트2",
presetId: "preset1",
position: { x: 0, y: 0.5, z: 0 },
rotation: { x: 0, y: 0, z: 0 },
},
];
this.objects = objectData;
let sensorData = [
{ sensorId: "component5", sensorName: "PM2 평량", sensorUse: false },
{ sensorId: "component6", sensorName: "PM2 수분", sensorUse: false },
{
sensorId: "component7",
sensorName: "PM2 사용스팀",
sensorUse: false,
},
{ sensorId: "component8", sensorName: "PM2 보류제", sensorUse: false },
{
sensorId: "component9",
sensorName: "PM2 벤토나이트",
sensorUse: false,
},
{ sensorId: "component10", sensorName: "PM2 지력제", sensorUse: false },
{ sensorId: "component13", sensorName: "PM3 평량", sensorUse: false },
{ sensorId: "component14", sensorName: "PM3 수분", sensorUse: false },
{
sensorId: "component15",
sensorName: "PM3 사용스팀",
sensorUse: false,
},
{ sensorId: "component16", sensorName: "PM3 보류제", sensorUse: false },
{
sensorId: "component17",
sensorName: "PM3 벤토나이트",
sensorUse: false,
},
{ sensorId: "component18", sensorName: "PM3 지력제", sensorUse: false },
];
this.sensors = sensorData;
},
reOption(e) {
this.selectedLayout = this.clickElement;
const clickBtn = e.currentTarget.id;
if (!this.showSplit) {
alert("요소를 삽입할 레이아웃을 선택해주세요");
return;
}
this.addComponentRecursiveFunc(this.splitInfo, clickBtn);
this.option1 = !this.option1;
this.option2 = true;
},
// 클릭한 요소의 부모 정보를 받아오는 이벤트
parentInfo: function (parentInfoq) {
this.clickComponentParentInfo = parentInfoq;
},
// 레이아웃 아이콘 클릭에 따른 이벤트
addSplitterLayout: function (e) {
const vm = this;
// vertical-btn, Horizon-btn 클릭에 따른 layoutVal 값 변경
const clickBtn = e.currentTarget.id;
// 기존 active 제거
if (this.activeElement) {
this.activeElement.classList.remove("active-layout");
}
// 클릭된 요소에 active-layout 클래스 추가
const targetClass = e.currentTarget.classList;
targetClass.add("active-layout");
this.activeElement = e.currentTarget;
if (clickBtn == "horizontal-btn") {
vm.layoutVal = "horizontal";
} else if (clickBtn == "vertical-btn") {
vm.layoutVal = "vertical";
}
// 첫 요소가 생기지 않은 상태
if (!vm.showSplit) {
const createParentId = "split" + vm.splitDepth;
//부모의 정보 담기
vm.splitInfo["layoutNm"] = createParentId;
vm.splitInfo["type"] = "s";
vm.splitInfo["parentId"] = null;
vm.splitInfo["index"] = 1;
vm.splitInfo["minWidth"] = 0;
vm.splitInfo["minHeight"] = 0;
vm.splitInfo["layoutType"] = vm.layoutVal;
vm.splitInfo["sizes"] = [50, 50];
vm.splitInfo["componentNm"] = null;
vm.splitInfo["componentOption"] = [];
for (let i = 0; i < 2; i++) {
const createChileId = createParentId + "-panel-" + (i + 1);
vm.splitChildInfo["layoutNm"] = createChileId;
vm.splitChildInfo["type"] = "s";
vm.splitChildInfo["parentId"] = createParentId;
vm.splitChildInfo["index"] = i + 1;
vm.splitChildInfo["minWidth"] = 0;
vm.splitChildInfo["minHeight"] = 0;
vm.splitChildInfo["layoutType"] = null;
vm.splitChildInfo["sizes"] = [];
vm.splitChildInfo["componentNm"] = null;
vm.splitChildInfo["componentOption"] = [];
vm.splitInfo["children"].push(
JSON.parse(JSON.stringify(vm.splitChildInfo))
);
vm.resetChildrenInfo();
}
vm.showSplit = true;
vm.splitDepth++;
} else {
// 최상위 레이아웃 변경 적용
// SplitterLayout 하위가 있는지 확인
if (
vm.clickElement === null ||
vm.clickElement == "splitter-container"
) {
vm.splitInfo["layoutType"] = vm.layoutVal;
return;
}
// 재귀함수 호출
this.recursiveFunc(vm.splitInfo);
}
},
// 재귀함수 정의
recursiveFunc: function (info) {
const vm = this;
//클릭된 요소가 '나'고 자식이 존재하면 layoutNm 변경
if (
info["layoutNm"] === this.clickElement &&
info["children"].length !== 0
) {
const childLayout = info["children"][0];
childLayout["layoutType"] = vm.layoutVal;
return;
}
//클릭된 요소가 '나'고 자식이 없으면 자식을 추가
if (
info["layoutNm"] === this.clickElement &&
info["children"].length === 0
) {
if (info["componentNm"] !== null) {
if (
confirm(
"삽입된 요소가 있습니다. 레이아웃을 변경하시겠습니까? /n 변경하면 삽인된 요소는 삭제됩니다."
) === false
) {
return;
}
}
const myId = "split" + vm.splitDepth;
// 값을 추가해줘야함
vm.splitChildInfo["layoutNm"] = myId;
vm.splitChildInfo["type"] = "s";
vm.splitChildInfo["parentId"] = vm.clickElement;
vm.splitChildInfo["index"] = 1;
vm.splitChildInfo["minWidth"] = 0;
vm.splitChildInfo["minHeight"] = 0;
vm.splitChildInfo["layoutType"] = vm.layoutVal;
vm.splitChildInfo["sizes"] = [50, 50];
vm.splitChildInfo["componentNm"] = null;
vm.splitChildInfo["componentOption"] = [];
info["children"].push(JSON.parse(JSON.stringify(vm.splitChildInfo)));
const myInfo = info["children"][0];
for (let n = 0; n < 2; n++) {
const childId = myId + "-panel-" + (n + 1);
vm.splitChildInfo["layoutNm"] = childId;
vm.splitChildInfo["type"] = "p";
vm.splitChildInfo["parentId"] = myId;
vm.splitChildInfo["index"] = n + 1;
vm.splitChildInfo["children"] = [];
vm.splitChildInfo["minWidth"] = 0;
vm.splitChildInfo["minHeight"] = 0;
vm.splitChildInfo["layoutType"] = null;
vm.splitChildInfo["sizes"] = [];
vm.splitChildInfo["componentNm"] = null;
vm.splitChildInfo["componentOption"] = [];
myInfo["children"].push(
JSON.parse(JSON.stringify(vm.splitChildInfo))
);
vm.resetChildrenInfo();
}
vm.splitDepth++;
return;
}
for (let i = 0; i < info["children"].length; i++) {
this.recursiveFunc(info["children"][i]);
}
},
// 요소 삽입을 위한 재귀 함수
addComponentRecursiveFunc: function (info, clickBtn) {
//클릭된 요소 componentName 변경
if (
info["layoutNm"] === this.clickElement &&
info["children"].length === 0
) {
info["componentNm"] = clickBtn;
} else if (
info["layoutNm"] === this.clickElement &&
info["children"].length !== 0
) {
return;
}
for (let i = 0; i < info["children"].length; i++) {
this.addComponentRecursiveFunc(info["children"][i], clickBtn);
}
},
// 요소 선택 이벤트 구현
addComponent: function (e) {
// 요소를 넣을 레이아웃 id값 저장 TODO: 레이아웃 영역만 저장되는가?
this.selectedLayout = this.clickElement;
const clickBtn = e.currentTarget.id;
if (!this.showSplit) {
alert("요소를 삽입할 레이아웃을 선택해주세요");
return;
}
//클릭된 element 에 요소 컴포넌트 추가
this.addComponentRecursiveFunc(this.splitInfo, clickBtn);
this.option2 = !this.option2;
this.option1 = true;
},
// input 값 저장
saveInput: function (key, value) {
this.parentInfo["componentOption"][this.clickElement] = {};
this.componentOptn[key] = value;
let isExist = this.parentInfo["componentOption"].hasOwnProperty(
this.clickElement
);
if (isExist) {
let currentOption =
this.parentInfo["componentOption"][this.clickElement];
currentOption.textData = this.componentOptn.textData;
currentOption.columnData = this.componentOptn.columnData;
currentOption.unitData = this.componentOptn.unitData;
currentOption.unitCk = this.componentOptn.unitCk;
currentOption.textSize = this.componentOptn.textSize;
currentOption.textAlign = this.componentOptn.textAlign;
currentOption.textStyle = this.componentOptn.textStyle;
currentOption.backColor = this.componentOptn.backColor;
} else {
this.parentInfo["componentOption"][this.clickElement] =
this.componentOptn;
}
this.parentInfo["componentOption"][this.clickElement] =
this.componentOptn;
},
// 미리보기 내부 splitter / component 클릭 이벤트
handleSplitterComponentClick: function (e) {
const eventTarget = e.target.id;
this.clickElement = eventTarget;
},
registerLayout: function () {
const vm = this;
if (this.customTitle === null || this.customTitle === "") {
alert("제목을 입력해주세요");
return;
}
if (!this.showSplit) {
alert("레이아웃 추가해 주세요");
return;
}
axios({
url: "/custom/insert",
method: "post",
headers: {
"Content-Type": "application/json; charset=UTF-8",
},
data: {
ttl: vm.customTitle,
cn: vm.customComment,
wrt_id: store.state.loginUser.user_id,
/* jobGroup:this.jobGroup,
getDataTable: this.getDataTable,*/
splitInfo: vm.splitInfo,
},
})
.then(function (response) {
alert("등록되었습니다.");
})
.catch(function (error) {
this.$showAlert(
"에러 발생",
"에러가 발생했습니다. 관리자에게 문의해 주세요."
);
});
},
optionChangeClick: function (e) {
// 요소 내 input 클릭 시 옵션 선택 탭으로 이동
this.showTab("option");
this.option2 = !this.option2;
this.option1 = true;
//배경색상 커스텀
if (e.target.dataset.isback) {
this.isbackColor = true;
} else {
this.isbackColor = false;
}
//텍스트 여부 체크
if (e.target.dataset.type === "text") {
this.istextCk = true;
} else {
this.istextCk = false;
}
const targetId = e.target.id;
// 클릭한 요소의 데이터를 input에 적용
// key를 통해 있으면 데이터 가져와 적용 / 없으면 새로운 데이터 생성
let isExist = this.parentInfo["componentOption"].hasOwnProperty(targetId);
// 요소 옵션 초기값으로 설정
if (!isExist) {
this.componentOptn = {
columnData: "",
textData: "new Title",
textSize: null,
textAlign: "",
textStyle: "",
unitData: "%",
unitCk: true,
};
} else {
// 있으면 해당 위치 찾아서 데이터 대입
const currentOption = this.parentInfo["componentOption"][targetId];
this.componentOptn = {
columnData: currentOption.columnData,
textData: currentOption.textData,
textSize: currentOption.textSize,
textAlign: currentOption.textAlign,
textStyle: currentOption.textStyle,
unitData: currentOption.unitData,
unitCk: currentOption.unitCk,
};
}
},
// 초기화 버튼 클릭 시 최상위 splitInfo 초기화 이벤트
resetLayout: function () {
this.showSplit = false;
this.splitInfo = {
layoutNm: null,
parentId: null,
type: null, // s, p
children: [],
index: null,
componentNm: null,
componentOption: [],
};
this.splitDepth = 0;
this.clickElement = "";
},
resetChildrenInfo: function () {
let vm = this;
vm.splitChildInfo.layoutNm = null;
vm.splitChildInfo.type = null;
vm.splitChildInfo.parentId = null;
vm.splitChildInfo.children = [];
vm.splitChildInfo.index = null;
vm.splitChildInfo.minWidth = 0;
vm.splitChildInfo.minHeight = 0;
vm.splitChildInfo.layoutType = null;
vm.splitChildInfo.sizes = [];
vm.splitChildInfo.componentNm = null;
vm.splitChildInfo.componentOption = {};
},
// jobContainer에서 받은 데이터 테이블 정보
getResult: function (table) {
this.columnList = [];
for (let i = 0; i < table.columnDatas.length; i++) {
// rowData와 columnNm을 포함한 객체 생성
let obj = {
rowData: table.rowData[0][i],
columnNm: table.columnDatas[i].columnNm,
};
this.columnList.push(obj);
}
},
selectJobGroup: function () {
let vm = this;
axios({
url: "/job/selectJobGroup.json",
method: "post",
headers: {
"Content-Type": "application/json; charset=UTF-8",
},
data: JSON.stringify({ group_id: "JOBGROUP_2024020517352987547982" }),
})
.then(function (response) {
vm.jobGroup = response.data.resultData.jobGroup;
})
.catch(function (error) {
this.$showAlert(
"에러 발생",
"에러가 발생했습니다. 관리자에게 문의해 주세요."
);
});
},
optionModal: function () {
this.isModal = !this.isModal;
},
},
components: {
SplitterLayout,
JobContainer: JobContainer,
SvgIcon: SvgIcon,
BackgroundOption: BackgroundOption,
CellOption: CellOption,
},
mounted() {
this.activeTab;
this.jobGroup = this.$getDefaultJobGroup().jobGroup;
this.pageId = this.$route.query.pageId;
},
};
</script>
<style scoped>
#splitter-container {
width: 100%;
height: calc(100% - 50px);
border: 1px solid #aaa;
margin-bottom: 20px;
}
#SplitterLayout {
width: 100%;
height: 100%;
}
#splitter-container.active {
border: 3px dotted red;
}
#customComment {
height: 99px;
}
.table-padding {
padding: 15px 0;
}
.paletteLi {
display: inline-block;
margin-right: 10px;
}
</style>