update the master branch to the latest

This commit is contained in:
梁灏 2019-08-27 09:42:40 +08:00
parent 67d534df27
commit 23a0ba9831
611 changed files with 122648 additions and 0 deletions

View file

@ -0,0 +1,124 @@
<template>
<div :class="classes" ref="cell">
<template v-if="renderType === 'index'"><span>{{ column.indexMethod ? column.indexMethod(row) : (naturalIndex + 1) }}</span></template>
<template v-if="renderType === 'selection'">
<Checkbox :value="checked" @click.native.stop="handleClick" @on-change="toggleSelect" :disabled="disabled"></Checkbox>
</template>
<template v-if="renderType === 'html'"><span v-html="row[column.key]"></span></template>
<template v-if="renderType === 'normal'">
<template v-if="column.tooltip">
<Tooltip transfer :content="row[column.key]" :theme="tableRoot.tooltipTheme" :disabled="!showTooltip" :max-width="300" class="ivu-table-cell-tooltip">
<span ref="content" @mouseenter="handleTooltipIn" @mouseleave="handleTooltipOut" class="ivu-table-cell-tooltip-content">{{ row[column.key] }}</span>
</Tooltip>
</template>
<span v-else>{{row[column.key]}}</span>
</template>
<template v-if="renderType === 'expand' && !row._disableExpand">
<div :class="expandCls" @click="toggleExpand">
<Icon type="ios-arrow-forward"></Icon>
</div>
</template>
<table-expand
v-if="renderType === 'render'"
:row="row"
:column="column"
:index="index"
:render="column.render"></table-expand>
<table-slot
v-if="renderType === 'slot'"
:row="row"
:column="column"
:index="index"></table-slot>
</div>
</template>
<script>
import TableExpand from './expand';
import TableSlot from './slot';
import Icon from '../icon/icon.vue';
import Checkbox from '../checkbox/checkbox.vue';
import Tooltip from '../tooltip/tooltip.vue';
export default {
name: 'TableCell',
components: { Icon, Checkbox, TableExpand, TableSlot, Tooltip },
inject: ['tableRoot'],
props: {
prefixCls: String,
row: Object,
column: Object,
naturalIndex: Number, // index of rebuildData
index: Number, // _index of data
checked: Boolean,
disabled: Boolean,
expanded: Boolean,
fixed: {
type: [Boolean, String],
default: false
}
},
data () {
return {
renderType: '',
uid: -1,
context: this.$parent.$parent.$parent.currentContext,
showTooltip: false, // overflow
};
},
computed: {
classes () {
return [
`${this.prefixCls}-cell`,
{
[`${this.prefixCls}-hidden`]: !this.fixed && this.column.fixed && (this.column.fixed === 'left' || this.column.fixed === 'right'),
[`${this.prefixCls}-cell-ellipsis`]: this.column.ellipsis || false,
[`${this.prefixCls}-cell-with-expand`]: this.renderType === 'expand',
[`${this.prefixCls}-cell-with-selection`]: this.renderType === 'selection'
}
];
},
expandCls () {
return [
`${this.prefixCls}-cell-expand`,
{
[`${this.prefixCls}-cell-expand-expanded`]: this.expanded
}
];
}
},
methods: {
toggleSelect () {
this.$parent.$parent.$parent.toggleSelect(this.index);
},
toggleExpand () {
this.$parent.$parent.$parent.toggleExpand(this.index);
},
handleClick () {
// Checkbox
},
handleTooltipIn () {
const $content = this.$refs.content;
this.showTooltip = $content.scrollWidth > $content.offsetWidth;
},
handleTooltipOut () {
this.showTooltip = false;
}
},
created () {
if (this.column.type === 'index') {
this.renderType = 'index';
} else if (this.column.type === 'selection') {
this.renderType = 'selection';
} else if (this.column.type === 'html') {
this.renderType = 'html';
} else if (this.column.type === 'expand') {
this.renderType = 'expand';
} else if (this.column.render) {
this.renderType = 'render';
} else if (this.column.slot) {
this.renderType = 'slot';
} else {
this.renderType = 'normal';
}
}
};
</script>

View file

@ -0,0 +1,21 @@
export default {
name: 'TableExpand',
functional: true,
props: {
row: Object,
render: Function,
index: Number,
column: {
type: Object,
default: null
}
},
render: (h, ctx) => {
const params = {
row: ctx.props.row,
index: ctx.props.index
};
if (ctx.props.column) params.column = ctx.props.column;
return ctx.props.render(h, params);
}
};

View file

@ -0,0 +1,76 @@
function has (browser) {
const ua = navigator.userAgent;
if (browser === 'ie') {
const isIE = ua.indexOf('compatible') > -1 && ua.indexOf('MSIE') > -1;
if (isIE) {
const reIE = new RegExp('MSIE (\\d+\\.\\d+);');
reIE.test(ua);
return parseFloat(RegExp['$1']);
} else {
return false;
}
} else {
return ua.indexOf(browser) > -1;
}
}
const csv = {
_isIE11 () {
let iev = 0;
const ieold = (/MSIE (\d+\.\d+);/.test(navigator.userAgent));
const trident = !!navigator.userAgent.match(/Trident\/7.0/);
const rv = navigator.userAgent.indexOf('rv:11.0');
if (ieold) {
iev = Number(RegExp.$1);
}
if (navigator.appVersion.indexOf('MSIE 10') !== -1) {
iev = 10;
}
if (trident && rv !== -1) {
iev = 11;
}
return iev === 11;
},
_isEdge () {
return /Edge/.test(navigator.userAgent);
},
_getDownloadUrl (text) {
const BOM = '\uFEFF';
// Add BOM to text for open in excel correctly
if (window.Blob && window.URL && window.URL.createObjectURL) {
const csvData = new Blob([BOM + text], { type: 'text/csv' });
return URL.createObjectURL(csvData);
} else {
return 'data:attachment/csv;charset=utf-8,' + BOM + encodeURIComponent(text);
}
},
download (filename, text) {
if (has('ie') && has('ie') < 10) {
// has module unable identify ie11 and Edge
const oWin = window.top.open('about:blank', '_blank');
oWin.document.charset = 'utf-8';
oWin.document.write(text);
oWin.document.close();
oWin.document.execCommand('SaveAs', filename);
oWin.close();
} else if (has('ie') === 10 || this._isIE11() || this._isEdge()) {
const BOM = '\uFEFF';
const csvData = new Blob([BOM + text], { type: 'text/csv' });
navigator.msSaveBlob(csvData, filename);
} else {
const link = document.createElement('a');
link.download = filename;
link.href = this._getDownloadUrl(text);
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
}
};
export default csv;

View file

@ -0,0 +1,16 @@
export default {
name: 'TableRenderHeader',
functional: true,
props: {
render: Function,
column: Object,
index: Number
},
render: (h, ctx) => {
const params = {
column: ctx.props.column,
index: ctx.props.index
};
return ctx.props.render(h, params);
}
};

View file

@ -0,0 +1,2 @@
import Table from './table.vue';
export default Table;

View file

@ -0,0 +1,31 @@
export default {
methods: {
alignCls (column, row = {}) {
let cellClassName = '';
if (row.cellClassName && column.key && row.cellClassName[column.key]) {
cellClassName = row.cellClassName[column.key];
}
return [
{
[`${cellClassName}`]: cellClassName, // cell className
[`${column.className}`]: column.className, // column className
[`${this.prefixCls}-column-${column.align}`]: column.align,
[`${this.prefixCls}-hidden`]: (this.fixed === 'left' && column.fixed !== 'left') || (this.fixed === 'right' && column.fixed !== 'right') || (!this.fixed && column.fixed && (column.fixed === 'left' || column.fixed === 'right'))
}
];
},
isPopperShow (column) {
return column.filters && ((!this.fixed && !column.fixed) || (this.fixed === 'left' && column.fixed === 'left') || (this.fixed === 'right' && column.fixed === 'right'));
},
setCellWidth (column) {
let width = '';
if (column.width) {
width = column.width;
} else if (this.columnsWidth[column._index]) {
width = this.columnsWidth[column._index].width;
}
if (width === '0') width = '';
return width;
}
}
};

View file

@ -0,0 +1,20 @@
export default {
name: 'TableSlot',
functional: true,
inject: ['tableRoot'],
props: {
row: Object,
index: Number,
column: {
type: Object,
default: null
}
},
render: (h, ctx) => {
return h('div', ctx.injections.tableRoot.$scopedSlots[ctx.props.column.slot]({
row: ctx.props.row,
column: ctx.props.column,
index: ctx.props.index
}));
}
};

View file

@ -0,0 +1,110 @@
<template>
<table cellspacing="0" cellpadding="0" border="0" :style="styleObject">
<colgroup>
<col v-for="(column, index) in columns" :width="setCellWidth(column)">
</colgroup>
<tbody :class="[prefixCls + '-tbody']">
<template v-for="(row, index) in data">
<table-tr
:draggable="draggable"
:row="row"
:key="rowKey ? row._rowKey : index"
:prefix-cls="prefixCls"
@mouseenter.native.stop="handleMouseIn(row._index)"
@mouseleave.native.stop="handleMouseOut(row._index)"
@click.native="clickCurrentRow(row._index)"
@dblclick.native.stop="dblclickCurrentRow(row._index)">
<td v-for="column in columns" :class="alignCls(column, row)">
<table-cell
:fixed="fixed"
:prefix-cls="prefixCls"
:row="row"
:key="column._columnKey"
:column="column"
:natural-index="index"
:index="row._index"
:checked="rowChecked(row._index)"
:disabled="rowDisabled(row._index)"
:expanded="rowExpanded(row._index)"
></table-cell>
</td>
</table-tr>
<tr v-if="rowExpanded(row._index)" :class="{[prefixCls + '-expanded-hidden']: fixed}">
<td :colspan="columns.length" :class="prefixCls + '-expanded-cell'">
<Expand :key="rowKey ? row._rowKey : index" :row="row" :render="expandRender" :index="row._index"></Expand>
</td>
</tr>
</template>
</tbody>
</table>
</template>
<script>
// todo :key="row"
import TableTr from './table-tr.vue';
import TableCell from './cell.vue';
import Expand from './expand.js';
import Mixin from './mixin';
export default {
name: 'TableBody',
mixins: [ Mixin ],
components: { TableCell, Expand, TableTr },
props: {
prefixCls: String,
styleObject: Object,
columns: Array,
data: Array, // rebuildData
objData: Object,
columnsWidth: Object,
fixed: {
type: [Boolean, String],
default: false
},
draggable: {
type: Boolean,
default: false
},
rowKey: {
type: Boolean,
default: false
}
},
computed: {
expandRender () {
let render = function () {
return '';
};
for (let i = 0; i < this.columns.length; i++) {
const column = this.columns[i];
if (column.type && column.type === 'expand') {
if (column.render) render = column.render;
}
}
return render;
}
},
methods: {
rowChecked (_index) {
return this.objData[_index] && this.objData[_index]._isChecked;
},
rowDisabled(_index){
return this.objData[_index] && this.objData[_index]._isDisabled;
},
rowExpanded(_index){
return this.objData[_index] && this.objData[_index]._isExpanded;
},
handleMouseIn (_index) {
this.$parent.handleMouseIn(_index);
},
handleMouseOut (_index) {
this.$parent.handleMouseOut(_index);
},
clickCurrentRow (_index) {
this.$parent.clickCurrentRow(_index);
},
dblclickCurrentRow (_index) {
this.$parent.dblclickCurrentRow(_index);
}
}
};
</script>

View file

@ -0,0 +1,228 @@
<template>
<table cellspacing="0" cellpadding="0" border="0" :style="styles">
<colgroup>
<col v-for="(column, index) in columns" :width="setCellWidth(column)">
<col v-if="$parent.showVerticalScrollBar" :width="$parent.scrollBarWidth"/>
</colgroup>
<thead>
<tr v-for="(cols, rowIndex) in headRows">
<th
v-for="(column, index) in cols"
:colspan="column.colSpan"
:rowspan="column.rowSpan"
:class="alignCls(column)">
<div :class="cellClasses(column)">
<template v-if="column.type === 'expand'">
<span v-if="!column.renderHeader">{{ column.title || '' }}</span>
<render-header v-else :render="column.renderHeader" :column="column" :index="index"></render-header>
</template>
<template v-else-if="column.type === 'selection'"><Checkbox :value="isSelectAll" :disabled="isSelectDisabled" @on-change="selectAll"></Checkbox></template>
<template v-else>
<span v-if="!column.renderHeader" :class="{[prefixCls + '-cell-sort']: column.sortable}" @click="handleSortByHead(getColumn(rowIndex, index)._index)">{{ column.title || '#' }}</span>
<render-header v-else :render="column.renderHeader" :column="column" :index="index"></render-header>
<span :class="[prefixCls + '-sort']" v-if="column.sortable">
<i class="ivu-icon ivu-icon-md-arrow-dropup" :class="{on: getColumn(rowIndex, index)._sortType === 'asc'}" @click="handleSort(getColumn(rowIndex, index)._index, 'asc')"></i>
<i class="ivu-icon ivu-icon-md-arrow-dropdown" :class="{on: getColumn(rowIndex, index)._sortType === 'desc'}" @click="handleSort(getColumn(rowIndex, index)._index, 'desc')"></i>
</span>
<Poptip
v-if="isPopperShow(column)"
v-model="getColumn(rowIndex, index)._filterVisible"
placement="bottom"
popper-class="ivu-table-popper"
transfer
@on-popper-hide="handleFilterHide(getColumn(rowIndex, index)._index)">
<span :class="[prefixCls + '-filter']">
<i class="ivu-icon ivu-icon-ios-funnel" :class="{on: getColumn(rowIndex, index)._isFiltered}"></i>
</span>
<div slot="content" :class="[prefixCls + '-filter-list']" v-if="getColumn(rowIndex, index)._filterMultiple">
<div :class="[prefixCls + '-filter-list-item']">
<checkbox-group v-model="getColumn(rowIndex, index)._filterChecked">
<checkbox v-for="(item, index) in column.filters" :key="index" :label="item.value">{{ item.label }}</checkbox>
</checkbox-group>
</div>
<div :class="[prefixCls + '-filter-footer']">
<i-button type="text" size="small" :disabled="!getColumn(rowIndex, index)._filterChecked.length" @click.native="handleFilter(getColumn(rowIndex, index)._index)">{{ t('i.table.confirmFilter') }}</i-button>
<i-button type="text" size="small" @click.native="handleReset(getColumn(rowIndex, index)._index)">{{ t('i.table.resetFilter') }}</i-button>
</div>
</div>
<div slot="content" :class="[prefixCls + '-filter-list']" v-else>
<ul :class="[prefixCls + '-filter-list-single']">
<li
:class="itemAllClasses(getColumn(rowIndex, index))"
@click="handleReset(getColumn(rowIndex, index)._index)">{{ t('i.table.clearFilter') }}</li>
<li
:class="itemClasses(getColumn(rowIndex, index), item)"
v-for="item in column.filters"
@click="handleSelect(getColumn(rowIndex, index)._index, item.value)">{{ item.label }}</li>
</ul>
</div>
</Poptip>
</template>
</div>
</th>
<th v-if="$parent.showVerticalScrollBar && rowIndex===0" :class='scrollBarCellClass()' :rowspan="headRows.length"></th>
</tr>
</thead>
</table>
</template>
<script>
import CheckboxGroup from '../checkbox/checkbox-group.vue';
import Checkbox from '../checkbox/checkbox.vue';
import Poptip from '../poptip/poptip.vue';
import iButton from '../button/button.vue';
import renderHeader from './header';
import Mixin from './mixin';
import Locale from '../../mixins/locale';
export default {
name: 'TableHead',
mixins: [ Mixin, Locale ],
components: { CheckboxGroup, Checkbox, Poptip, iButton, renderHeader },
props: {
prefixCls: String,
styleObject: Object,
columns: Array,
objData: Object,
data: Array, // rebuildData
columnsWidth: Object,
fixed: {
type: [Boolean, String],
default: false
},
columnRows: Array,
fixedColumnRows: Array
},
computed: {
styles () {
const style = Object.assign({}, this.styleObject);
const width = parseInt(this.styleObject.width) ;
style.width = `${width}px`;
return style;
},
isSelectAll () {
let isSelectAll = true;
if (!this.data.length) isSelectAll = false;
if (!this.data.find(item => !item._disabled)) isSelectAll = false; // #1751
for (let i = 0; i < this.data.length; i++) {
if (!this.objData[this.data[i]._index]._isChecked && !this.objData[this.data[i]._index]._isDisabled) {
isSelectAll = false;
break;
}
}
return isSelectAll;
},
headRows () {
const isGroup = this.columnRows.length > 1;
if (isGroup) {
return this.fixed ? this.fixedColumnRows : this.columnRows;
} else {
return [this.columns];
}
},
isSelectDisabled () {
let isSelectDisabled = false;
if (!this.data.length) isSelectDisabled = true;
if (!this.data.find(item => !item._disabled)) isSelectDisabled = true;
return isSelectDisabled;
}
},
methods: {
cellClasses (column) {
return [
`${this.prefixCls}-cell`,
{
[`${this.prefixCls}-hidden`]: !this.fixed && column.fixed && (column.fixed === 'left' || column.fixed === 'right'),
[`${this.prefixCls}-cell-with-selection`]: column.type === 'selection'
}
];
},
scrollBarCellClass(){
let hasRightFixed = false;
for(let i in this.headRows){
for(let j in this.headRows[i]){
if(this.headRows[i][j].fixed === 'right') {
hasRightFixed=true;
break;
}
if(hasRightFixed) break;
}
}
return [
{
[`${this.prefixCls}-hidden`]: hasRightFixed
}
];
},
itemClasses (column, item) {
return [
`${this.prefixCls}-filter-select-item`,
{
[`${this.prefixCls}-filter-select-item-selected`]: column._filterChecked[0] === item.value
}
];
},
itemAllClasses (column) {
return [
`${this.prefixCls}-filter-select-item`,
{
[`${this.prefixCls}-filter-select-item-selected`]: !column._filterChecked.length
}
];
},
selectAll () {
const status = !this.isSelectAll;
this.$parent.selectAll(status);
},
handleSort (index, type) {
// index #5580
const column = this.columns.find(item => item._index === index);
const _index = column._index;
if (column._sortType === type) {
type = 'normal';
}
this.$parent.handleSort(_index, type);
},
handleSortByHead (index) {
// index #5580
const column = this.columns.find(item => item._index === index);
if (column.sortable) {
const type = column._sortType;
if (type === 'normal') {
this.handleSort(index, 'asc');
} else if (type === 'asc') {
this.handleSort(index, 'desc');
} else {
this.handleSort(index, 'normal');
}
}
},
handleFilter (index) {
this.$parent.handleFilter(index);
},
handleSelect (index, value) {
this.$parent.handleFilterSelect(index, value);
},
handleReset (index) {
this.$parent.handleFilterReset(index);
},
handleFilterHide (index) {
this.$parent.handleFilterHide(index);
},
// _ isGroup
getColumn (rowIndex, index) {
const isGroup = this.columnRows.length > 1;
if (isGroup) {
const id = this.headRows[rowIndex][index].__id;
return this.columns.filter(item => item.__id === id)[0];
} else {
return this.headRows[rowIndex][index];
}
}
}
};
</script>

View file

@ -0,0 +1,44 @@
<template>
<tr :class="rowClasses(row._index)" :draggable="draggable" @dragstart="onDrag($event,row._index)" @drop="onDrop($event,row._index)" @dragover="allowDrop($event)" v-if="draggable"><slot></slot></tr>
<tr :class="rowClasses(row._index)" v-else><slot></slot></tr>
</template>
<script>
export default {
props: {
row: Object,
prefixCls: String,
draggable: Boolean
},
computed: {
objData () {
return this.$parent.objData;
}
},
methods: {
onDrag (e,index) {
e.dataTransfer.setData('index',index);
},
onDrop (e,index) {
const dragIndex = e.dataTransfer.getData('index');
this.$parent.$parent.dragAndDrop(dragIndex,index);
e.preventDefault();
},
allowDrop (e) {
e.preventDefault();
},
rowClasses (_index) {
return [
`${this.prefixCls}-row`,
this.rowClsName(_index),
{
[`${this.prefixCls}-row-highlight`]: this.objData[_index] && this.objData[_index]._isHighlight,
[`${this.prefixCls}-row-hover`]: this.objData[_index] && this.objData[_index]._isHover
}
];
},
rowClsName (_index) {
return this.$parent.$parent.rowClassName(this.objData[_index], _index);
},
}
};
</script>

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,93 @@
import { deepCopy } from '../../utils/assist';
const convertColumnOrder = (columns, fixedType) => {
let list = [];
let other = [];
columns.forEach((col) => {
if (col.fixed && col.fixed === fixedType) {
list.push(col);
} else {
other.push(col);
}
});
return list.concat(other);
};
export {convertColumnOrder};
// set forTableHead to true when convertToRows, false in normal cases like table.vue
const getAllColumns = (cols, forTableHead = false) => {
const columns = deepCopy(cols);
const result = [];
columns.forEach((column) => {
if (column.children) {
if (forTableHead) result.push(column);
result.push.apply(result, getAllColumns(column.children, forTableHead));
} else {
result.push(column);
}
});
return result;
};
export {getAllColumns};
const convertToRows = (columns, fixedType = false) => {
const originColumns = fixedType ? fixedType === 'left' ? deepCopy(convertColumnOrder(columns, 'left')) : deepCopy(convertColumnOrder(columns, 'right')) : deepCopy(columns);
let maxLevel = 1;
const traverse = (column, parent) => {
if (parent) {
column.level = parent.level + 1;
if (maxLevel < column.level) {
maxLevel = column.level;
}
}
if (column.children) {
let colSpan = 0;
column.children.forEach((subColumn) => {
traverse(subColumn, column);
colSpan += subColumn.colSpan;
});
column.colSpan = colSpan;
} else {
column.colSpan = 1;
}
};
originColumns.forEach((column) => {
column.level = 1;
traverse(column);
});
const rows = [];
for (let i = 0; i < maxLevel; i++) {
rows.push([]);
}
const allColumns = getAllColumns(originColumns, true);
allColumns.forEach((column) => {
if (!column.children) {
column.rowSpan = maxLevel - column.level + 1;
} else {
column.rowSpan = 1;
}
rows[column.level - 1].push(column);
});
return rows;
};
export {convertToRows};
const getRandomStr = function (len = 32) {
const $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
const maxPos = $chars.length;
let str = '';
for (let i = 0; i < len; i++) {
str += $chars.charAt(Math.floor(Math.random() * maxPos));
}
return str;
};
export {getRandomStr};