Files
sdl_base/doc/시스템공통/공통컴포넌트&유틸.adoc
2026-05-29 17:49:25 +09:00

1217 lines
23 KiB
Plaintext

= 공통컴포넌트 & 유틸
== DatePicker
=== DatePicker Component 사용방법
template에 component 추가
[source, html]
----
<template>
<sdl-datepicker
v-model="searchPeriod"
:period="searchPeriod">
</sdl-datepicker>
</template>
----
props 설명
[%header,cols=3*]
|===
|props명
|설명
|예
|refKey
|component Reference Key
|
|period
|type: Object, //기간 정보
|
|minimumView
|type: String, //최소 표현 단위 - ex) month로 설정 시 '월' 단위로 picker 선택 가능
default: 'day',
|
|wrapClass
|type: String, //class명
default: 'wd150',
|
|disabled
|type: Boolean, //달력 선택 가능여부
|default: false,
|===
== Excel Download Button
=== Excel Download Component 사용방법
template에 component 추가
[source, html]
----
<template>
<sdl-exceldownloadbtn
:excelInfo="excelInfo"
:btnClass="btnClass"
:before-click="beforeClick"
/>
</template>
----
props 설명
[%header,cols=3*]
|===
|props명
|설명
|예
|btnLabel
|type: String, //버튼 label 정의
default:'sdp.common.label.excelDownload'
|
|excelInfo
|type: Object
|excelInfo: {
columnInfoFile:'externalUser',
fileName:'externalUser', //다운받을 엑셀파일명
queryId:'selectUser', //쿼리 아이디
sheetName:'외부 사용자', //sheet명
useNumberField:'Y', //엑셀 처음 컬럼에 넘버링 사용 여부
param: { deleted: '0', activeFlag: '1', externalUser: '1' },
}
|beforeClick
|엑셀 다운로드 전에 체크하고자 하는 로직이 있을 경우 사용
다운로드 가능할 경우 true 리턴
|template :
<sdl-exceldownloadbtn :before-click="beforeClick"/>
method :
beforeClick() {
return true;
},
default: false,
|btnClass
|type: String, //버튼 class 정의
default: 'btn btn-secondary'
|
|===
== Excel Upload Button
=== Excel Upload Component 사용방법
template에 component 추가
[source, html]
----
<template>
<sdl-exceluploadbtn
:excelInfo="excelUpInfo"
@after-upload="afterUpload"
:btnClass="btnClass"
:before-click="beforeClick"
/>
</template>
----
props 설명
[%header,cols=3*]
|===
|props명
|설명
|예
|btnLabel
|type: String, //버튼 label 정의
default:'sdp.common.label.excelUpload'
|
|excelInfo
|type: Object
|excelInfo:{
columnInfoFile:'largeExcelupload', //Column Info XML 파일
queryId:'selectUser', //실행할 query Id
returnPath:'', //엑셀 저장 후 이동할 페이지 경로('after-upload' event로 대체)
startRow:4, //저장할 데이터의 첫 Row
useObjectName:'com.samsung.sample.entity.ExcelTestObject', //데이터를 처리하기 위한 자바 객체
},
|beforeClick
|엑셀 업로드 전에 체크하고자 하는 로직이 있을 경우 사용
업로드 가능할 경우 true 리턴
|template :
<sdl-exceluploadbtn :before-click="beforeClick"/>
method :
beforeClick() {
return true;
},
|btnClass
|type: String, //버튼 class 정의
default: 'btn btn-secondary'
|
|===
event 설명
[%header,cols=3*]
|===
|event명
|설명
|예
|after-upload
|엑셀 업로드 후 진행할 로직을 추가
|template :
<sdl-exceldownloadbtn @after-upload="afterUpload"/>
method :
afterUpload(rtn){
console.log(rtn);
SDLUtil.alert('excel upload 완료. 다음 작업 할것');
},
|===
== File Component
=== File Component 사용방법
- template에 component 추가
[source, html]
----
<template>
<sdl-fileuploader
style="width:1532px"
ref="uploader1"
:fileList="fileList"
@complete="rtnUploadList"
downloadType="A"
:maxTotalSize="uploadFileSize"
:modifyFlag="true"
useExtList="zip"
multiFileNm="정test"
></sdl-fileuploader>
</template>
----
- 선택 파일 다운로드 시 파일별다운로드(default) 및 압축파일다운로드 기능 제공
- MultipleFileUploader.vue 파일 내 checkedDownload method 부분 참고
props 설명
[%header,cols=3*]
|===
|props명
|설명
|예
|modifyFlag
|type: Boolean, //true(등록/삭제 가능), false(다운로드만 가능)
default: true,
|
|uploadURL
|type: String, //업로드할 url 등록
default: '${SDLUtil.API_URL}/resource/attachments/multifile-upload' //SDL 사용시 default
|
|multiFileNm(필수)
|type: String //멀티 다운로드시 대표 이름
|
|downloadType
|type: String //file component를 한 vue에서 여러개 사용할 경우 downloadType으로 구분한다.
ex) 'A', 'B',... or 'F', 'I'
|
|fileList
|type: Array //파일 리스트를 component에 전달(SDL을 사용할 경우 API에서 넘어온 리스트 그대로 전달할것)
|fileList: [
{
firstRegDatetime:1563412831556,
firstRegrId:'sdp-front',
lastModDatetime:1563412831556,
lastModrId:'sdp-front',
fileId:'AWwCqp1KAADw5f1I',
fileName:'정sdl_html_20190708.zip',
filePathName:'C:\\NAS\\SDL\\upload',
fileSize:14154292,
fileExtensionName:'b518546c12f1482a87ce44772fd56057',
fileMimeTypeName:'application/x-zip-compressed',
deleted:false,
downloadType:'A',
orderIdx:0,
},
|useExtList
|type: String, //업로드할 파일 확장자를 세팅
default: 'zip,xlsx,xls,ppt,pptx'
|
|maxItems
|type: Number, //최대 업로드 가능한 파일 갯수 세팅
default: 30
|
|maxTotalSize
|type: Number, //최대 첨부파일 용량을 세팅
default: 1073741824
|
|===
event 설명
[%header,cols=3*]
|===
|event명
|설명
|예
|complete
|업로드 후 업로드한 파일 리스트를 return 해준다.
|template :
<sdl-fileuploader @complete="rtnUploadList"/>
method :
rtnUploadList(downloadType, fileList) {
console.log('downloadType:', downloadType);
console.log('rtnUploadList:', fileList);
SDLUtil.alert('받은 업로드 리스트 다음 작업 할것');
},
|init
|파일 컴퍼넌트를 init 처리한다.
|template :
<sdl-fileuploader ref="uploader1"/>
method :
this.$refs.uploader1.init()
|onUpload
|추가한 첨부파일을 업로드 한다. 업로드 후 complete에 지정한 메소드로 리스트 return 해줌
|template :
<sdl-fileuploader ref="uploader1"/>
method :
this.$refs.uploader1.onUpload()
|===
== Modal
Modal 팝업 띄우기
image::front_01_01.png[]
* 형식 : SDLUtil.show(import된 컴포넌트, 컴포넌트에 전달할 인자, modal properties, events)
props 설명
[%header,cols=5*]
|===
|props명
|필수여부
|Type
|Default
|설명
|name
|true
|[String, Number]
|
|모달 명
|resizable
|false
|Boolean
|false
|resize 가능여부
|draggable
|false
|[Boolean, String]
|false
|drag 가능 여부
|scrollable
|false
|Boolean
|false
|스크롤 가능 여부
|width
|false
|[String, Number]
|600
|
|height
|false
|[String, Number]
|300
|
|minWidth
|false
|Number (px)
|0
|
|minHeight
|false
|Number (px)
|0
|
|maxWidth
|false
|Number (px)
|Infinity
|
|maxHeight
|false
|Number (px)
|Infinity
|
|===
event 설명
[%header,cols=2*]
|===
|event 명
|설명
|before-open
|모달 오픈전 실행할 이벤트 정의
|opened
|모달 오픈후 실행할 이벤트 정의
|before-close
|모달 닫기전 실행할 이벤트 정의
|closed
|모달 닫기 후 실행할 이벤트 정의
|===
== Pagination
=== Pagination Component 사용방법
template에 component 추가
[source, html]
----
<template>
<sdl-pagination
:current-page="currentPage"
:total-rows="records"
:per-page="pageSize"
@change="onSearch"
align="center"
/>
</template>
----
props 설명
[%header,cols=3*]
|===
|props명
|설명
|비고
|currentPage
|type: Number //현재 페이지
|
|totalRows
|type: Number //총 데이터 갯수
|
|perPage
|type: Number //한 페이지에 보여질 데이터 갯수
|
|limit
|type: Number, //페이징 영역내에 보여질 페이지 숫자 갯수
default: 10
|
|===
== Tree
=== Tree Component 사용 방법
template에 component 추가
[source, html]
----
<template>
<sdl-tree
ref="tree"
:data="data"
:showCheckbox="false"
:item-events="itemEvents"
show-checkbox
:multiple="false"
allow-batch
whole-row
draggable
@item-click="itemClick"
@item-drag-start="itemDragStart"
@item-drag-end="itemDragEnd"
@item-drop-before="itemDropBefore"
@item-drop="itemDrop"
>
</sdl-tree>
</template>
----
props 설명
[%header,cols=4*]
|===
|props명
|Type
|Default
|설명
|data
|Array
|
|set tree data
|size
|String
|
|set tree item size , value : 'large' or '' or ''small'
|show-checkbox
|Boolean
|false
|set it show checkbox
|allow-transition
|Boolean
|true
|allow use transition animation
|whole-row
|Boolean
|false
|use whole row state
|no-dots
|Boolean
|false
|show or hide dots
|collapse
|Boolean
|false
|set all tree item collapse state
|multiple
|Boolean
|false
|set multiple selected tree item
|allow-batch
|Boolean
|false
|in multiple choices. allow batch select
|text-field-name
|String
|'text'
|set tree item display field
|value-field-name
|String
|'value'
|set tree item value field
|children-field-name
|String
|'children'
|set tree item children field
|item-events
|Object
|{}
|register any event to tree item, example
|async
|Function
|
|async load callback function , if node is a leaf ,you can set 'isLeaf: true' in data
|loading-text
|String
|'Loading'
|set loading text
|draggable
|Boolean
|false
|set tree item can be dragged , selective drag and drop can set 'dragDisabled: true' and 'dropDisabled: true' , all default value is 'false'
|drag-over-background-color
|String
|'#C9FDC9'
|set drag over background color
|klass
|String
|
|set append tree class
|===
node.model 의 method
[%header,cols=2*]
|===
|method 명
|params
|addChild
|(object) newDataItem
|addAfter
|(object) newDataItem, (object) selectedNode
|addBefore
|(object) newDataItem, (object) selectedNode
|openChildren
|
|closeChildren
|
|===
event 설명
[%header,cols=2*]
|===
|event 명
|설명
|item-click
|item-click(node, item, e)
|item-toggle
|item-toggle(node, item, e)
|item-drag-start
|item-drag-start(node, item, e)
|item-drag-end
|item-drag-end(node, item, e)
|item-drop-before
|item-drop-before(node, item, draggedItem, e)
|item-drop
|item-drop(node, item, draggedItem, e)
|node
|current node vue object
|item
|current node data item object
|===
data item의 properties
[%header,cols=4*]
|===
|properties명
|type
|default
|설명
|icon
|String
|
|custom icon css class
|opened
|Boolean
|false
|set leaf opened
|selected
|Boolean
|false
|set node selected
|disabled
|Boolean
|false
|set node disabled
|isLeaf
|Boolean
|false
|if node is a leaf , set true can hide '+'
|dragDisabled
|Boolean
|false
|selective drag
|dropDisabled
|Boolean
|false
|selective drop
|===
== SDLUtil 사용 방법
=== SDL 공통 Util 사용방법
[source, javascript]
----
import SDLUtil from '@/utils/SDLUtil';
// 또는
import { SDLUtil, StringUtil } from '@/utils';
// import 후 사용
----
[%header,cols=3*]
|===
|method 명
|설명
|예
|getLoginedUserInfo
|로그인한 사용자 정보
|
|getMsgProp
|메시지 프로퍼티에서 값 가져오기
|SDLUtil.getMsgProp('sdl.user.label.work', ['하나', '둘'])
|alert
|레이어 alert
|SDLUtil.alert({
msg:'I am a tiny dialog box.<br/>And I render <b>HTML!</b>',
title:'alert',
okLabel:'ok',
onOkEvt: () => console.log('ok'),
});
SDLUtil.alert("메시지"); //이 경우 나머지 입력값들은 default로 세팅되고 msg만 입력됨
|confirm
|레이어 confirm
|SDLUtil.confirm({
msg: 'confirm body',
title: 'confirm title',
okLabel: 'ok label',
cancelLabel: 'cancel label',
onOkEvt: () => console.log('ok'),
onCancelEvt: () => console.log('cancel'),
});
|showLoadingBar
|default loading bar show/hide
|SDLUtil.showLoadingBar(true);
|getCommCodeList
|로딩시 가져온 전체 코드리스트에서 특정 parentId에 대한 코드 리스트 return
|const codelist = SDLUtil.getCommCodeList({ commCodeTypeId: 'MENUTYPE' });
console.log(codelist);
|openUserPopup
|사용자 검색 팝업
|SDLUtil.openUserPopup({
searchColumn: 'userName',
searchTxt: this.searchUserNm,
rtnFunc: this.getUserList,
knoxSearch: !this.internalFlag,
});
|isLogin
|로그인 여부
|
|getI18nLanguage
|현재 로케일 정보
|
|setI18nLanguage
|로케일 변경
|
|show
|모달창 오픈
|SDLUtil.show(
WorkgroupPopup,
{
rtnFunc: args => {
this.checkRoleWorkgroupList(args);
},
},
{ width: '850px', height: 'auto' },
);
|loadAllCommCodeList
|전체 공통코드 리스트 load
|
|formParameters
|object 를 formData로 변경
|
|===
== StringUtil 사용 방법
=== StringUtil 사용방법
[source, javascript]
----
import StringUtil from '@/utils/stringUtil';
// 또는
import { SDLUtil, StringUtil } from '@/utils';
// import 후 사용
----
[%header,cols=3*]
|===
|method 명
|설명
|예
|queryStringfy
|url 쿼리 문자열로 변경
|
|checkPatternUrl
|입력된 문자열이 url 패턴인지 체크
|
|===
== DateUtil 사용 방법
=== DateUtil 사용방법
[source, javascript]
----
import DateUtil from '@/utils/DateUtil';
// import 후 사용
----
IMPORTANT: DateUtil의 기본 데이터 포맷은 'YYYY-MM-DD' 형식이며, 국가별 언어에 따른 message.data-format.properties 는 사용자에게 보여줄 때의 형식이다.
[%header,cols=3*]
|===
|method 명
|설명
|예
|now
|현재 날짜
|
|addDate
|현재 날짜 기준 이후 데이터
|.addDate(1, 'M') 현재 날짜에서 한 달을 더한 날
|subDate
|날짜 기준 이전 데이터
|.subDate(1, 'M') 현재 날짜에서 한 달을 뺀 날
|stdFormat
|표준 포맷으로 변환
|Backend로 데이터를 보낼때의 표준 포맷(YYYY-MM-DD 순)
|===
== 공통 validation
필수 입력값 validation을 onBlur 시 그리고 저장/수정 시 하기 위해서는 아래와 같은 방법으로 처리한다.
image::front_01_02.png[]
validation 하고자 하는 tag 에 v-validation(directive) 이용(errorMessage 를 지정하지 않을 경우 default로 표시 됨, default message의 경우 다국어 지원이 되지 않음)
* 팝업 없는 화면인 경우(directive 지정시 별도 내용 없이 처리)
[source, html]
----
<div class="mb-2" style="position:relative;">
<label for="title">{{ $t('sdl.approval.label.title') }} <span class="text-required">&#42;</span></label>
<input
id="title"
type="text"
class="form-control"
v-model="apprDoc.title"
:readonly="apprDoc.docStatus !== ''"
v-validation=""
:errorMessage="$t('sdl.department.message.requiredValue')"
/>
</div>
----
* 등록 화면에 팝업 등록이 또 있는 경우(groupId 를 다르게 써서 체크)
[source, html]
----
<tr>
<th class="text-nowrap" scope="row">
{{ $t('sdl.commonCode.label.order') }}
<span class="text-required">*</span>
</th>
<td>
<input type="number" min="0" max="99999" class="form-control" v-model.number="code.ord" v-validation="{ groupId: 'popup' }" />
</td>
</tr>
----
* 값이 있고 없고 외에 별도 처리의 경우 함수와 에러메시지를 배열로 정의
[source, html]
----
<tr>
<th class="text-nowrap" scope="row">URL<span class="text-required">*</span></th>
<td>
<input
id="linkSiteUrl"
type="text"
class="form-control"
placeholder=""
v-model.trim="linkInfo.url"
v-validation="{
groupId: '',
valids: [
{
validFuncs: () => {
return linkInfo.url.length <= 250;
},
errorMessage: 'test err',
},
{
validFuncs: () => {
return !checkPatternUrl(linkInfo.url);
},
errorMessage: 'sdl.samsung.validate.url',
},
],
}"
:errorMessage="'sdl.department.message.requiredValue'"
/>
</td>
</tr>
----
* 저장/수정 버튼 클릭 시 directive로 지정한 tag들의 일괄 validation 처리(groupId가 있을 경우 넣고 없으면 안 넣어도 됨)
[source, javascript]
----
if (SDLUtil.onSubmitValidation('popup')) return;
----
IMPORTANT: Bootstrap을 이용한 퍼블리싱이 아닐 경우 안 될 수 있음
== 다국어 관련 날짜 포맷
SDL에서는 다국어 포맷을 Server로 부터 message properties를 통해 받아서 사용한다.
.message.properties
[source, json]
----
{
"ko_KR":{
"data-format.time.hm":"HH:mm",
"data-format.datetime.ymdhms":"YYYY-MM-DD HH:mm:ss",
"data-format.time.hms":"HH:mm:ss",
"data-format.date.ym":"YYYY-MM",
"data-format.date.yw":"YYYY-W",
"data-format.date.ymw":"YYYY-MM(W)",
"data-format.date.ymd":"YYYY-MM-DD"
},
"en_US":{
"data-format.time.hm":"HH:mm",
"data-format.datetime.ymdhms":"YYYY-MM-DD HH:mm:ss",
"data-format.time.hms":"HH:mm:ss",
"data-format.date.ym":"YYYY-MM",
"data-format.date.yw":"YYYY-W",
"data-format.date.ymw":"YYYY-MM(W)",
"data-format.date.ymd":"MM/DD/YYYY"
}
}
----
.moment() 를 이용한 현재 날짜의 언어별 포맷(SDLUtil.getMsgProp) 표기법
[source, javascript]
----
firstRegDatetime: moment().format(SDLUtil.getMsgProp('data-format.date.ymd')),
----
.filter를 통해 template에서 사용가능
[source, html]
----
<!-- Vue2 -->
<!-- default 'YYYY-MM-DD' -->
<small class="float-right">{{ row.regDate || dateFormat }}</small>
<!-- Vue3 -->
<small class="float-right">{{ $filters.dateFormat(row.regDate) }}</small>
<!-- Vue2 -->
<!-- 포맷을 임의로 지정 -->
<td class="text-center">{{ mail.sendDateTime || dateFormat($t('data-format.date.ymd')) }}</td>
<!-- Vue3 -->
<td class="text-center">{{ $filters.dateFormat(mail.sendDateTime, $t('data-format.date.ymd')) }}</td>
----
== 화면별 권한처리
SDL에서는 역할관리에서 정의해놓은 역할별로 4개의 권한을 지정할 수 있다.
그리고 지정한 권한을 화면에서 버튼에 directive로 지정함으로써 show/hide 처리를 자동으로 해준다.
image::front_01_03.png[]
* vue 내에서 authorization directive를 통해 버튼 별 권한을 정의한다.(배열로 정의할 경우 여러개 중에 하나만 매칭되도 show처리 됨)
** 여러개의 권한을 둘 경우
+
[source, html]
----
<button
type="button"
class="btn btn-primary btn-sm"
v-authorization="['UPDATE', 'EXECUTE']"
@click="onApprWrite"
>
{{ $t('sdl.approval.label.APPROVE') }}
</button>
----
** 하나의 권한을 둘 경우
+
[source, javascript]
----
<button type="button"
class="btn btn-primary btn-sm"
v-authorization="'UPDATE'"
@click="onApprWrite"
>
{{ $t('sdl.approval.label.APPROVE') }}
</button>
----
* 관리자일 경우는 directive 지정 상관 없이 무조건 show 처리된다.
== 목록 페이지와 상세 페이지 검색조건
=== 목록 페이지
mixins 에 StoreParams 추가
[source, javascript]
----
// 상단
import StoreParams from '@/mixin/StoreParams';
// script
export default {
mixins: [StoreParams],
/*
** 조회하는 method에 this.setStoreParameter(params); 호출하여 파라미터 저장
*/
methods: {
getList(pageIndex = 1) {
const params = {
pageIndex,
pageSize: this.pageSize,
searchCondition: this.searchCondition,
searchKeyword: this.searchKeyword,
};
// 해당코드 추가
this.setStoreParameter(params);
// Loading bar 실행
SDLUtil.showLoadingBar(true);
// axios api 호출 로직 생략
}
}
----
created() 항목에 파라미터 복원 로직 추가
[source, javascript]
----
created() {
const storeParams = this.getStoreParameter();
// 저장된 파라미터가 있으면 복원
if (storeParams) {
this.searchCondition = storeParams.searchCondition;
this.searchKeyword = storeParams.searchKeyword;
this.pageIndex = storeParams.pageIndex;
this.pageSize = storeParams.pageSize;
this.getList(this.pageIndex);
} else {
// 저장된 파라미터가 없이 들어왔을때 로직
this.getList();
}
},
----
=== 상세 페이지
mixins에 StoreParams 추가 후 목록버튼에 goBackToList() 호출하여 목록으로 이동
[source, javascript]
----
// 상단
import StoreParams from '@/mixin/StoreParams';
// script
export default {
mixins: [StoreParams],
// ... 생략 ...
methods: {
// template 내에서는 goBackToList 바로 호출
// 로직상 필요한 경우도 호출
deleteDetail() {
// 해당페이지 상세 삭제후 목록이동
// 목록페이지로 돌아가기
this.goBackToList();
}
}
----
== 기타 유용한 filter
=== cutString
원하는 길이만큼 문자열 컷 + '...'
[source, html]
----
<!-- vue2 -->
<td class="text-left">{{ grid.docTitle | cutString(100) }}</td>
<!-- vue3 -->
<td class="text-left">{{ $filters.cutString(grid.docTitle, 100) }}</td>
----
=== dateFormat
timestamp 형태의 값을 지정된 날짜 포맷으로 변경(default : 'YYYY-MM-DD')
[source, html]
----
<!-- vue2 -->
<!-- default 'YYYY-MM-DD' -->
<small class="float-right">{{ row.regDate | dateFormat }}</small>
<!-- vue3 -->
<small class="float-right">{{ $filters.dateFormat(row.regDate) }}</small>
<!-- 포맷 임의 지정 -->
<!-- vue2 -->
<td class="text-center">{{ mail.sendDateTime | dateFormat($t('data-format.date.ymd')) }}</td>
<!-- vue3 -->
<td class="text-center">{{ $filters.dateFormat(mail.sendDateTime, $t('data-format.date.ymd')) }}</td>
----
=== numberFormat
숫자를 금액 단위로 표시(999,999,999)
[source, html]
----
<!-- vue2 -->
<td class="text-right">{{ log.hitCount | numberFormat }}</td>
<!-- vue3 -->
<td class="text-right">{{ $filters.numberFormat(log.hitCount) }}</td>
----
=== nl2Br
\n 을 <br/> 로 변경(v-text 인 경우는 tag가 안 되므로 v-html 사용)
[source, html]
----
<!-- vue2 -->
<div
v-else
v-html="$options.filters.nl2br(post.postDetail)"
ref="postDetail"
class="form-control"
style="overflow:scroll; height:250px;max-height:250px"
contenteditable="true"
></div>
<!-- vue3 -->
<div
v-else
v-html="$filters.nl2br(post.postDetail)"
ref="postDetail"
class="form-control"
style="overflow:scroll; height:250px;max-height:250px"
contenteditable="true"
></div>
----