Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#815][3.0] Grid 기능 추가 #816

Merged
merged 9 commits into from
Jun 1, 2021
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 26 additions & 6 deletions docs/views/grid/api/grid.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,20 @@
@click-row="onClickRow"
@dblclick-row="onDoubleClickRow"
>
<!-- Cell Renderer -->
<template v-slot:db-icon>
kdeun1 marked this conversation as resolved.
Show resolved Hide resolved
<div class="db-icon"></div>
</template>
<!-- Toolbar -->
<template v-slot:toolbar="{ item }">
<ev-text-field
v-model="searchVm"
class="search"
type="search"
placeholder="Search"
@input="item.onSearch"
/>
</template>
</ev-grid>
```

Expand All @@ -38,16 +52,25 @@
| | columnWidth | 40 | 기본 컬럼 너비를 설정한다. | `min-width: 40px` |
| | useFilter | false | 필터 기능 사용 여부, 컨텍스트 메뉴에서 'Filter On' 메뉴를 클릭하여 설정한다. | |
| | useCheckbox | {} | 각 row별 체크박스 사용 여부 및 단일 선택이나 다중 선택을 설정한다. | |
| | | use | 체크박스 사용 여부 | boolean |
| | | use | 체크박스 사용 여부 | Boolean |
| | | mode | 단일 및 다중 선택 설정 | 'multi', 'single' |
| | | headerCheck | 헤더 체크박스 사용 여부 | boolean |
| | | headerCheck | 헤더 체크박스 사용 여부 | Boolean |
| | style | {} | 그리드의 스타일을 설정한다. | |
| | | stripe | row의 배경색을 Stripe 스타일로 설정한다. | boolean |
| | | stripe | row의 배경색을 Stripe 스타일로 설정한다. | Boolean |
| | | border | 그리드의 Border 여부를 설정한다. | 'none', 'rows' |
| | | highlight | 지정한 row에 Highlight 효과를 설정한다. | `rowIndex` |
| | customContextMenu | [] | 우클릭시 보여지는 컨텍스트 메뉴를 설정한다. | |
| | | menuItems | 컨텍스트 메뉴 | |

### Columns
| 이름 | 타입 | 설명 | 종류 | 필수 |
| --- | ---- | ----- | ---- | --- |
| caption | String | 컬럼명 | ex) '인스턴스명' | Y |
| field | String | 필드명 | ex) 'instance_name' | Y |
| type | String | 데이터 타입 | 'string', 'number', 'float', 'boolean' | Y |
| width | Number | 컬럼 넓이 | ex) 150 | N |
| searchable | Boolean | 검색 대상 여부 | `true`, `false` | N |

### Event
| 이름 | 파라미터 | 설명 |
| ---- | ------- | ---- |
Expand All @@ -56,6 +79,3 @@
| click-row | newValue | row가 클릭 되었을 때 호출된다. |
| dblclick-row | newValue | row가 더블 클릭 되었을 때 호출된다. |

>### 참고
- <그리드> 셀 내부에 타 컴포넌트를 Rendering 할 수 있다.
- `ev-button`, `ev-checkbox`, `ev-input-number`, `ev-select` 외 컴포넌트 추가 예정
313 changes: 313 additions & 0 deletions docs/views/grid/example/CellRenderer.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,313 @@
<template>
<div class="case">
<ev-grid
v-model:selected="selected"
v-model:checked="checked"
:columns="columns"
:rows="tableData"
:width="widthMV"
:height="heightMV"
:option="{
adjust: adjustMV,
showHeader: showHeaderMV,
rowHeight: rowHeightMV,
columnWidth: columnWidthMV,
useFilter: useFilterMV,
useCheckbox: {
use: useCheckboxMV,
mode: checkboxModeMV,
headerCheck: headerCheckMV,
},
customContextMenu: menuItems,
style: {
stripe: stripeMV,
border: borderMV,
},
}"
@check-row="onCheckedRow"
@check-all="onCheckedRow"
@click-row="onClickRow"
@dblclick-row="onDoubleClickRow"
>
<!-- renderer start -->
<template v-slot:gridButton="{ item }">
<ev-button
type="ghost"
size="small"
@click="item.onRowDelete(item.row[0])"
>
Delete
</ev-button>
<ev-button
size="small"
@click="item.onRowEdit(item.row)"
>
Edit
</ev-button>
</template>
<template v-slot:check="{ item }">
<ev-checkbox
v-model="item.row[2][item.column.index]"
label="check"
@click.stop=""
@dblclick.stop=""
/>
</template>
<template v-slot:select="{ item }">
<ev-select
v-model="item.row[2][item.column.index]"
:items="[
{
name: 'a',
value: 'a',
}, {
name: 'b',
value: 'b',
}, {
name: 'c',
value: 'c',
},
]"
placeholder="Please select value."
@click.stop=""
@dblclick.stop=""
/>
</template>
<template v-slot:slide="{ item }">
<ev-slider
v-model="item.row[2][item.column.index]"
range
readonly
:mark="{
33.33: 'W',
66.66: 'C',
}"
:color="['#3C81F6', '#FADE4C', '#FF470E']"
:show-tooltip="false"
/>
</template>
<template v-slot:custom="{ item }">
<span
:class="getStateClass(item.row[2][item.column.index])"
>
<span class="v-chip__content"> {{ item.row[2][item.column.index] }} </span>
</span>
</template>
<template v-slot:inputNumber="{ item }">
<ev-input-number
v-model="item.row[2][item.column.index]"
:max="100"
:min="0"
@click.stop="onInputNumberClick"
@dblclick.stop=""
/>
</template>
</ev-grid>
</div>
</template>

<script>
import { ref } from 'vue';

export default {
setup() {
const tableData = ref([]);
const selected = ref([]);
const checked = ref([]);
const widthMV = ref('100%');
const heightMV = ref(300);
const adjustMV = ref(true);
const showHeaderMV = ref(true);
const stripeMV = ref(false);
const rowHeightMV = ref(35);
const columnWidthMV = ref(80);
const useFilterMV = ref(true);
const useCheckboxMV = ref(true);
const checkboxModeMV = ref('multi');
const headerCheckMV = ref(true);
const checkedRowsMV = ref();
const clickedRowMV = ref();
const DbClickedRowsMV = ref();
const menuItems = ref([
{
text: 'Menu1',
click: () => console.log(`[Menu1] Selected Row Data: ${selected.value}`),
}, {
text: 'Menu2',
click: () => console.log('[Menu2]'),
},
]);
const borderMV = ref('');
const columns = ref([
{
caption: 'Check',
field: 'check',
type: 'boolean',
},
{
caption: 'Select',
field: 'select',
type: 'string',
},
{
caption: 'Slide',
field: 'slide',
type: 'string',
},
{
caption: 'InputNumber',
field: 'inputNumber',
type: 'number',
width: 140,
},
{
caption: 'Custom',
field: 'custom',
type: 'string',
},
{
caption: '',
field: 'gridButton',
type: 'boolean',
width: 120,
},
]);
const onCheckedRow = () => {
let checkedRow = '';
for (let i = 0; i < checked.value.length; i++) {
checkedRow += JSON.stringify(checked.value[i]);
}
checkedRowsMV.value = checkedRow;
};
const onDoubleClickRow = (e) => {
DbClickedRowsMV.value = `${e.rowData}`;
};
const onClickRow = (e) => {
clickedRowMV.value = `${e.rowData}`;
};
const getData = (count, startIndex) => {
const state = ['a', 'b', 'c'];
const temp = [];
for (let ix = startIndex; ix < startIndex + count; ix++) {
temp.push([
true, // check
state[ix % 3], // select
[33.33, 66.66], // slide
10, // inputNumber
Math.floor(Math.random() * (99 - 10 + 1)) + 10, // custom
'',
]);
}
tableData.value = temp;
};
const onInputNumberClick = () => {
console.log('On click InputNumber');
};
const getStateClass = (value) => {
let stateColor = 'green';
if (value >= 70) {
stateColor = 'yellow';
} else if (value >= 50) {
stateColor = 'red';
}
return {
'v-chip': true,
'v-size--default': true,
[stateColor]: true,
};
};

getData(7, 0);
return {
columns,
tableData,
selected,
checked,
widthMV,
heightMV,
adjustMV,
showHeaderMV,
stripeMV,
rowHeightMV,
columnWidthMV,
useFilterMV,
useCheckboxMV,
checkboxModeMV,
headerCheckMV,
checkedRowsMV,
clickedRowMV,
DbClickedRowsMV,
menuItems,
borderMV,
onCheckedRow,
onDoubleClickRow,
onClickRow,
onInputNumberClick,
getStateClass,
};
},
};
</script>

<style lang="scss" scoped>
.description {
min-width: 200px;
}
.form-rows {
display: flex;
margin-bottom: 5px;
}
.form-row {
width: 50%;
}
.ev-text-field, .ev-input-number, .ev-select {
width: 80%;
}
.badge {
margin-bottom: 2px;
margin-right: 5px !important;
}
.ev-toggle {
margin-right: 10px;
}
.v-chip {
display: inline-flex;
position: relative;
height: 32px;
padding: 0 12px;
align-items: center;
cursor: default;
color: #FFFFFF;
line-height: 20px;
max-width: 100%;
outline: none;
overflow: hidden;
text-decoration: none;
transition-duration: .28s;
transition-property: box-shadow, opacity;
transition-timing-function: cubic-bezier(.4,0,.2,1);
vertical-align: middle;
white-space: nowrap;
border-radius: 16px;
font-size: 14px;

&.green {
background-color: #4CAF50;
border-color: #4CAF50;
}
&.yellow {
background-color: #F7DF6A;
border-color: #F7DF6A;
}
&.red {
background-color: #FF4949;
border-color: #FF4949;
}
}
.v-chip .v-chip__content {
display: inline-flex;
height: 100%;
align-items: center;
max-width: 100%;
}
</style>
Loading