샘플 메뉴 추가
This commit is contained in:
195
front/bo/client/components/sample-menu/code-crud/input-form.vue
Normal file
195
front/bo/client/components/sample-menu/code-crud/input-form.vue
Normal file
@@ -0,0 +1,195 @@
|
||||
<template>
|
||||
<div>
|
||||
<u-field-set ref="fieldSet">
|
||||
<u-field-row>
|
||||
<u-field label="코드">
|
||||
<dx-text-box ref="codeInput" v-model="inputData.dtlCd" :disabled="inputMode === 'update'">
|
||||
<dx-validator>
|
||||
<dx-required-rule />
|
||||
<dx-async-rule message="이미 사용 중인 코드입니다." :validation-callback="validateCode" />
|
||||
</dx-validator>
|
||||
</dx-text-box>
|
||||
</u-field>
|
||||
</u-field-row>
|
||||
|
||||
<u-field-row>
|
||||
<u-field label="코드명">
|
||||
<dx-text-box v-model="inputData.cdNm">
|
||||
<dx-validator>
|
||||
<dx-required-rule />
|
||||
</dx-validator>
|
||||
</dx-text-box>
|
||||
</u-field>
|
||||
</u-field-row>
|
||||
|
||||
<u-field-row>
|
||||
<u-field label="설명">
|
||||
<dx-text-area v-model="inputData.cdDesc"></dx-text-area>
|
||||
</u-field>
|
||||
</u-field-row>
|
||||
|
||||
<u-field-row>
|
||||
<u-field label="사용여부">
|
||||
<dx-radio-group v-model="inputData.useYn" :items="useYnList" display-expr="name" value-expr="code"></dx-radio-group>
|
||||
</u-field>
|
||||
</u-field-row>
|
||||
</u-field-set>
|
||||
<u-button-bar position="bottom">
|
||||
<dx-button text="신규" icon="plus" :disabled="inputMode === 'new'" @click="newForm"></dx-button>
|
||||
|
||||
<dx-button text="저장" class="right" icon="floppy" type="default" @click="save" />
|
||||
<dx-button text="삭제" icon="close" :disabled="inputMode === 'new'" @click="remove" />
|
||||
</u-button-bar>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { Component, Ref, Emit } from 'vue-property-decorator'
|
||||
import { UstraBoComponent } from '@ustra/nuxt-mng-bo/src/components/ustra-bo-component'
|
||||
import { Validatable } from '@ustra/nuxt-dx/src/components/dx/dx-validation-group'
|
||||
import { DxTextBox } from '@ustra/nuxt-dx/src/components/dx/dx-text-box'
|
||||
import { CodeInfo } from '@ustra/nuxt-mng/src/system/models/ustra-code-model'
|
||||
import { UseYnDataList } from '@ustra/nuxt-mng/src/data'
|
||||
import { FormMode } from '@ustra/data/src/models/base-models'
|
||||
import { OnError } from '@ustra/nuxt/src/vue/decorators'
|
||||
import { REMOVE_QUESTION } from '@ustra/data/src/data/common-messages'
|
||||
import { SampleCrudModel, sampleCrudService } from '~/services/sample-crud-service'
|
||||
|
||||
type InputType = 'groupCode' | 'detailCode'
|
||||
|
||||
@Component
|
||||
/**
|
||||
* @vuese
|
||||
* @group component group
|
||||
* component description
|
||||
*/
|
||||
export default class extends UstraBoComponent {
|
||||
// #region variables
|
||||
inputData: SampleCrudModel = null
|
||||
inputMode: FormMode = null
|
||||
inputType: InputType = null
|
||||
groupCode: SampleCrudModel = {
|
||||
useYn: 'Y',
|
||||
}
|
||||
|
||||
useYnList = UseYnDataList
|
||||
|
||||
@Ref() readonly fieldSet: Validatable
|
||||
@Ref() readonly codeInput: DxTextBox
|
||||
// #endregion
|
||||
// #region hooks
|
||||
created() {
|
||||
this.init('groupCode')
|
||||
}
|
||||
|
||||
// #endregion
|
||||
// #region methods
|
||||
async init(inputType: InputType = 'detailCode', groupCode?: CodeInfo) {
|
||||
if (this.fieldSet) {
|
||||
await this.fieldSet.reset()
|
||||
}
|
||||
|
||||
this.inputData = {
|
||||
grpCd: null,
|
||||
dtlCd: null,
|
||||
cdNm: null,
|
||||
cdDesc: null,
|
||||
useYn: 'Y',
|
||||
}
|
||||
|
||||
this.inputType = inputType
|
||||
this.groupCode = null
|
||||
this.inputMode = 'new'
|
||||
|
||||
if (inputType === 'detailCode' && !groupCode) {
|
||||
throw new Error('groupCode 값이 없음.')
|
||||
}
|
||||
|
||||
this.groupCode = groupCode
|
||||
this.focus()
|
||||
}
|
||||
|
||||
async detail(code?: CodeInfo) {
|
||||
const detail = await sampleCrudService.getCode(code.grpCd, code.dtlCd)
|
||||
|
||||
if (detail === null) {
|
||||
throw new Error('코드 정보가 없습니다.')
|
||||
}
|
||||
|
||||
if (detail.dtlCd === '*') {
|
||||
detail.dtlCd = detail.grpCd
|
||||
}
|
||||
|
||||
await this.fieldSet.reset()
|
||||
this.inputData = detail
|
||||
this.inputMode = 'update'
|
||||
|
||||
this.focus()
|
||||
}
|
||||
|
||||
@OnError()
|
||||
async save() {
|
||||
const saveData = this.$ustra.utils.core.deepMerge({}, this.inputData)
|
||||
|
||||
if (this.inputType === 'groupCode') {
|
||||
saveData.grpCd = saveData.dtlCd
|
||||
saveData.dtlCd = '*'
|
||||
} else {
|
||||
saveData.grpCd = this.groupCode.grpCd
|
||||
}
|
||||
|
||||
const validateResult = await this.fieldSet.validate(true)
|
||||
if (!validateResult || !validateResult.isValid) {
|
||||
// alert('입력 값을 확인해주세요.')
|
||||
return
|
||||
}
|
||||
|
||||
if (this.inputMode === 'new') {
|
||||
await sampleCrudService.add(saveData)
|
||||
} else {
|
||||
await sampleCrudService.edit(saveData)
|
||||
}
|
||||
this.saved(this.groupCode)
|
||||
}
|
||||
|
||||
@OnError()
|
||||
async remove() {
|
||||
if (await confirm(REMOVE_QUESTION)) {
|
||||
await sampleCrudService.remove(this.inputData.grpCd, this.inputData.dtlCd)
|
||||
this.saved(this.groupCode)
|
||||
}
|
||||
}
|
||||
|
||||
newForm() {
|
||||
this.init('detailCode', this.groupCode)
|
||||
this.reset()
|
||||
}
|
||||
|
||||
focus() {
|
||||
try {
|
||||
this.codeInput.instance.focus()
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
// #region validation
|
||||
async validateCode(e) {
|
||||
const code = await sampleCrudService.getCode(e.value, '*')
|
||||
return code === null
|
||||
}
|
||||
// #endregion
|
||||
|
||||
// #region event method
|
||||
@Emit()
|
||||
saved(groupCode: CodeInfo) {
|
||||
return groupCode
|
||||
}
|
||||
|
||||
@Emit()
|
||||
reset() {}
|
||||
// #endregion
|
||||
|
||||
// #endregion
|
||||
// #region watches
|
||||
// #endregion
|
||||
}
|
||||
</script>
|
||||
<style lang="scss"></style>
|
||||
121
front/bo/client/components/sample-menu/code-crud/master-grid.vue
Normal file
121
front/bo/client/components/sample-menu/code-crud/master-grid.vue
Normal file
@@ -0,0 +1,121 @@
|
||||
<template>
|
||||
<dx-box direction="col">
|
||||
<dx-item :ratio="1">
|
||||
<template #default>
|
||||
<dx-box direction="col">
|
||||
<dx-item :ratio="1">
|
||||
<template #default>
|
||||
<dx-data-grid ref="grid" :data-source="codes" @selection-changed="rowSelected">
|
||||
<dx-column data-field="grpCd" caption="코드" />
|
||||
<dx-column data-field="cdNm" caption="코드명" />
|
||||
<dx-column />
|
||||
</dx-data-grid>
|
||||
</template>
|
||||
</dx-item>
|
||||
<dx-item base-size="auto">
|
||||
<template #default>
|
||||
<div>
|
||||
<u-help-box :is-grid-total="false" :show-icon="false">
|
||||
검색 건수 : <span class="emphasis-text">{{ codes.length }}</span> 건
|
||||
</u-help-box>
|
||||
</div>
|
||||
</template>
|
||||
</dx-item>
|
||||
</dx-box>
|
||||
</template>
|
||||
</dx-item>
|
||||
<dx-item :ratio="0" base-size="auto">
|
||||
<template #default>
|
||||
<u-button-bar>
|
||||
<dx-button text="신규" class="right" icon="plus" @click="newGroupCode"></dx-button>
|
||||
<dx-button text="수정" icon="edit" :visible="hasSelectedRow" @click="editGroupCode"></dx-button>
|
||||
|
||||
<dx-popup :width="500" :height="400" :visible.sync="isOpenedInputForm" title="마스터 코드 등록" @shown="inputForm.focus()">
|
||||
<dx-box direction="col" height="100%">
|
||||
<dx-item :ratio="1">
|
||||
<template #default>
|
||||
<input-form ref="inputForm" @saved="onSaved" />
|
||||
</template>
|
||||
</dx-item>
|
||||
</dx-box>
|
||||
</dx-popup>
|
||||
</u-button-bar>
|
||||
</template>
|
||||
</dx-item>
|
||||
</dx-box>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { Component, Ref, Emit } from 'vue-property-decorator'
|
||||
import { DxDataGrid } from '@ustra/nuxt-dx/src/components'
|
||||
import { UstraBoComponent } from '@ustra/nuxt-mng-bo/src/components/ustra-bo-component'
|
||||
import InputForm from './input-form.vue'
|
||||
import { SampleCrudModel, sampleCrudService } from '~/services/sample-crud-service'
|
||||
|
||||
@Component({
|
||||
components: { InputForm },
|
||||
})
|
||||
/**
|
||||
* @vuese
|
||||
* @group component group
|
||||
* component description
|
||||
*/
|
||||
export default class extends UstraBoComponent {
|
||||
// #region variables
|
||||
|
||||
codes: SampleCrudModel[] = []
|
||||
isOpenedInputForm: boolean = false
|
||||
hasSelectedRow: boolean = false
|
||||
|
||||
@Ref() readonly inputForm: InputForm
|
||||
@Ref() readonly grid: DxDataGrid
|
||||
// #endregion
|
||||
// #region hooks
|
||||
created() {
|
||||
this.loadCode()
|
||||
}
|
||||
|
||||
// #endregion
|
||||
// #region methods
|
||||
@Emit()
|
||||
codeSelected(code: SampleCrudModel) {
|
||||
return code
|
||||
}
|
||||
|
||||
@Emit()
|
||||
codeLoaded() {}
|
||||
|
||||
newGroupCode() {
|
||||
this.isOpenedInputForm = true
|
||||
this.inputForm.init('groupCode')
|
||||
}
|
||||
|
||||
editGroupCode() {
|
||||
this.newGroupCode()
|
||||
this.inputForm.detail(this.grid.instance.getSelectedRowsData()[0])
|
||||
}
|
||||
|
||||
async loadCode() {
|
||||
this.codes = await sampleCrudService.getGroups()
|
||||
this.codeLoaded()
|
||||
}
|
||||
|
||||
rowSelected(e) {
|
||||
this.hasSelectedRow = e.selectedRowsData.length > 0
|
||||
|
||||
if (e.selectedRowsData.length < 1) {
|
||||
return
|
||||
}
|
||||
this.codeSelected(e.selectedRowsData[0] as SampleCrudModel)
|
||||
}
|
||||
|
||||
onSaved() {
|
||||
this.isOpenedInputForm = false
|
||||
this.loadCode()
|
||||
}
|
||||
|
||||
// #endregion
|
||||
// #region watches
|
||||
// #endregion
|
||||
}
|
||||
</script>
|
||||
<style lang="scss"></style>
|
||||
@@ -0,0 +1,58 @@
|
||||
<template>
|
||||
<dx-data-grid ref="grid" height="100%" :data-source="codes" @selection-changed="rowSelected">
|
||||
<dx-column data-field="dtlCd" caption="코드" />
|
||||
<dx-column data-field="cdNm" caption="코드명" />
|
||||
</dx-data-grid>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { Component, Ref, Emit } from 'vue-property-decorator'
|
||||
import { UstraBoComponent } from '@ustra/nuxt-mng-bo/src/components/ustra-bo-component'
|
||||
import { OnError } from '@ustra/nuxt/src/vue/decorators'
|
||||
import { DxDataGrid } from '@ustra/nuxt-dx/src/components/dx/dx-data-grid'
|
||||
import { SampleCrudModel, sampleCrudService } from '~/services/sample-crud-service'
|
||||
|
||||
@Component
|
||||
/**
|
||||
* @vuese
|
||||
* @group component group
|
||||
* component description
|
||||
*/
|
||||
export default class extends UstraBoComponent {
|
||||
// #region variables
|
||||
codes: SampleCrudModel[] = null
|
||||
@Ref() readonly grid: DxDataGrid
|
||||
// #endregion
|
||||
// #region hooks
|
||||
// #endregion
|
||||
// #region methods
|
||||
@OnError({ message: '코드 목록 조회 중 오류가 발생하였습니다.' })
|
||||
async loadData(groupCode: SampleCrudModel) {
|
||||
this.codes = (await sampleCrudService.getCodes(null, groupCode.grpCd)).body.filter(code => code.dtlCd !== '*')
|
||||
}
|
||||
|
||||
@Emit()
|
||||
codeSelected(code: SampleCrudModel) {
|
||||
return code
|
||||
}
|
||||
|
||||
rowSelected(e) {
|
||||
if (e.selectedRowsData.length < 1) {
|
||||
return
|
||||
}
|
||||
|
||||
this.codeSelected(e.selectedRowsData[0] as SampleCrudModel)
|
||||
}
|
||||
|
||||
clearSelection() {
|
||||
this.grid.instance.clearSelection()
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.codes = []
|
||||
}
|
||||
// #endregion
|
||||
// #region watches
|
||||
// #endregion
|
||||
}
|
||||
</script>
|
||||
<style lang="scss"></style>
|
||||
@@ -1,15 +0,0 @@
|
||||
<template>
|
||||
<div style="display: flex; align-items: stretch; flex: 1; flex-grow: 1; flex-direction: column"></div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { Component } from 'vue-property-decorator'
|
||||
import { UstraBoComponent } from '@ustra/nuxt-mng-bo/src/components/ustra-bo-component'
|
||||
|
||||
@Component({})
|
||||
/**
|
||||
* @vuese
|
||||
* @group component group
|
||||
* component description
|
||||
*/
|
||||
export default class extends UstraBoComponent {}
|
||||
</script>
|
||||
81
front/bo/client/pages/samples/code-crud.vue
Normal file
81
front/bo/client/pages/samples/code-crud.vue
Normal file
@@ -0,0 +1,81 @@
|
||||
<template>
|
||||
<dx-box direction="row" height="100%" width="100%">
|
||||
<template #default>
|
||||
<dx-item :ratio="1">
|
||||
<template #default>
|
||||
<master-grid ref="masterGrid" @code-selected="masterCodeSelected" @code-loaded="onMasterCodeLoaded" />
|
||||
</template>
|
||||
</dx-item>
|
||||
<dx-item :ratio="1" :disabled="subFormDisabled">
|
||||
<template #default>
|
||||
<dx-box direction="col" width="100%">
|
||||
<template #default>
|
||||
<dx-item :ratio="1">
|
||||
<template #default>
|
||||
<sub-grid ref="subGrid" @code-selected="subCodeSelected" />
|
||||
</template>
|
||||
</dx-item>
|
||||
<dx-item :ratio="0" :base-size="250">
|
||||
<template #default>
|
||||
<input-form ref="inputForm" @saved="onSaved" @reset="onReset" />
|
||||
</template>
|
||||
</dx-item>
|
||||
</template>
|
||||
</dx-box>
|
||||
</template>
|
||||
</dx-item>
|
||||
</template>
|
||||
</dx-box>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { Component, Ref } from 'vue-property-decorator'
|
||||
import { UstraBoComponent } from '@ustra/nuxt-mng-bo/src/components/ustra-bo-component'
|
||||
import MasterGrid from '~/components/sample-menu/code-crud/master-grid.vue'
|
||||
import SubGrid from '~/components/sample-menu/code-crud/sub-grid.vue'
|
||||
import InputForm from '~/components/sample-menu/code-crud/input-form.vue'
|
||||
import { SampleCrudModel } from '~/services/sample-crud-service'
|
||||
|
||||
@Component({
|
||||
components: { MasterGrid, SubGrid, InputForm },
|
||||
})
|
||||
export default class extends UstraBoComponent {
|
||||
// #region variables
|
||||
@Ref() readonly masterGrid: MasterGrid
|
||||
@Ref() readonly subGrid: SubGrid
|
||||
@Ref() readonly inputForm: InputForm
|
||||
|
||||
subFormDisabled: boolean = true
|
||||
masterCodes: SampleCrudModel[]
|
||||
|
||||
// #endregion
|
||||
// #region hooks
|
||||
// #endregion
|
||||
// #region methods
|
||||
async masterCodeSelected(code: SampleCrudModel) {
|
||||
await this.subGrid.loadData(code)
|
||||
await this.inputForm.init('detailCode', code)
|
||||
this.subFormDisabled = false
|
||||
}
|
||||
|
||||
subCodeSelected(code: SampleCrudModel) {
|
||||
this.inputForm.detail(code)
|
||||
}
|
||||
|
||||
onMasterCodeLoaded() {
|
||||
this.subGrid.clear()
|
||||
this.subFormDisabled = true
|
||||
}
|
||||
|
||||
onSaved(code: SampleCrudModel) {
|
||||
this.masterCodeSelected(code)
|
||||
}
|
||||
|
||||
onReset() {
|
||||
this.subGrid.clearSelection()
|
||||
}
|
||||
// #endregion
|
||||
// #region watches
|
||||
// #endregion
|
||||
}
|
||||
</script>
|
||||
<style lang="scss"></style>
|
||||
139
front/bo/client/services/sample-crud-service.ts
Normal file
139
front/bo/client/services/sample-crud-service.ts
Normal file
@@ -0,0 +1,139 @@
|
||||
import { BaseModel } from '@ustra/data/src/models/base-models'
|
||||
import { ApiResponse } from '@ustra/data/src/models/api-model'
|
||||
import { PaginationRequest } from '@ustra/data/src/models/pagination-model'
|
||||
import { UtraService } from '@ustra/nuxt/src/services/ustra-service'
|
||||
import { HttpMethod } from '@ustra/core/src/server/http/const'
|
||||
|
||||
/**
|
||||
* crud sample 모델
|
||||
*/
|
||||
export interface SampleCrudModel extends BaseModel {
|
||||
/**
|
||||
* 그룹 코드
|
||||
*/
|
||||
grpCd?: string
|
||||
|
||||
/**
|
||||
* 상세 코드
|
||||
*/
|
||||
dtlCd?: string
|
||||
|
||||
/**
|
||||
* 코드 명
|
||||
*/
|
||||
cdNm?: string
|
||||
|
||||
/**
|
||||
* 코드 상세
|
||||
*/
|
||||
cdDesc?: string
|
||||
|
||||
/**
|
||||
* 사용 여부
|
||||
*/
|
||||
useYn?: string
|
||||
|
||||
/**
|
||||
* 비고
|
||||
*/
|
||||
rmk?: string
|
||||
}
|
||||
|
||||
export class SampleCrudService extends UtraService {
|
||||
/**
|
||||
* 코드 그룹 목록 조회
|
||||
*/
|
||||
async getGroups() {
|
||||
return (
|
||||
await this.$ustra.api.call<ApiResponse<SampleCrudModel[]>>({
|
||||
url: '/api/sample/crud-code/groups',
|
||||
method: HttpMethod.GET,
|
||||
})
|
||||
).data.body
|
||||
}
|
||||
|
||||
/**
|
||||
* 코드 목록 조회
|
||||
* @param pagination 페이징 요청 정보
|
||||
* @param grpCd 그룹 코드
|
||||
*/
|
||||
async getCodes(pagination: PaginationRequest, grpCd: string = null) {
|
||||
const url = this.$ustra.api
|
||||
.urlBuilder('/api/sample/crud-code')
|
||||
.add('criteria', {
|
||||
paginationRequest: pagination,
|
||||
grpCd,
|
||||
})
|
||||
.build()
|
||||
|
||||
return (
|
||||
await this.$ustra.api.call<ApiResponse<SampleCrudModel[]>>({
|
||||
url,
|
||||
method: HttpMethod.GET,
|
||||
})
|
||||
).data
|
||||
}
|
||||
|
||||
/**
|
||||
* 코드 상세 정보 조회
|
||||
* @param grpCd 그룹 코드
|
||||
* @param dtlCd 상세 코드
|
||||
*/
|
||||
async getCode(grpCd: string, dtlCd: string) {
|
||||
return (
|
||||
await this.$ustra.api.call<ApiResponse<SampleCrudModel>>({
|
||||
url: `/api/sample/crud-code/${grpCd}/${dtlCd}`,
|
||||
method: HttpMethod.GET,
|
||||
})
|
||||
).data.body
|
||||
}
|
||||
|
||||
/**
|
||||
* 코드 추가
|
||||
* @param data 입력 데이터
|
||||
*/
|
||||
async add(data: SampleCrudModel) {
|
||||
return (
|
||||
await this.$ustra.api.call<ApiResponse<SampleCrudModel>>({
|
||||
url: '/api/sample/crud-code',
|
||||
method: HttpMethod.POST,
|
||||
data,
|
||||
})
|
||||
).data.body
|
||||
}
|
||||
|
||||
/**
|
||||
* 코드 수정
|
||||
* @param data 수정 데이터
|
||||
*/
|
||||
async edit(data: SampleCrudModel) {
|
||||
return (
|
||||
await this.$ustra.api.call<ApiResponse<SampleCrudModel>>({
|
||||
url: '/api/sample/crud-code',
|
||||
method: HttpMethod.PUT,
|
||||
data,
|
||||
})
|
||||
).data.body
|
||||
}
|
||||
|
||||
/**
|
||||
* 코드 삭제
|
||||
* @param grpCd 그룹 코드
|
||||
* @param dtlCd 상세 코드
|
||||
*/
|
||||
async remove(grpCd: string, dtlCd: string) {
|
||||
return (
|
||||
await this.$ustra.api.call<ApiResponse<SampleCrudModel>>({
|
||||
url: '/api/sample/crud-code',
|
||||
method: HttpMethod.DELETE,
|
||||
data: {
|
||||
grpCd,
|
||||
dtlCd,
|
||||
},
|
||||
})
|
||||
).data.body
|
||||
}
|
||||
}
|
||||
|
||||
export const sampleCrudService = new SampleCrudService()
|
||||
export default sampleCrudService
|
||||
Reference in New Issue
Block a user