优化管理端代码结构

This commit is contained in:
paulGao
2022-09-02 17:51:33 +08:00
parent 36c4584970
commit 55aa57d812
147 changed files with 1759 additions and 114 deletions

View File

@@ -0,0 +1,117 @@
// text
@prefixCls: zk-checkbox;
// color
@border: #dddee1;
@hoverBorder: #bcbcbc;
@blue: #2d8cf0;
.@{prefixCls}-wrapper {
display: flex;
justify-content: center;
}
.@{prefixCls} {
display: inline-block;
position: relative;
line-height: 1;
white-space: nowrap;
vertical-align: middle;
cursor: pointer;
outline: none;
&:hover {
.@{prefixCls}__inner {
border-color: @hoverBorder;
}
}
}
.@{prefixCls}__inner {
display: inline-block;
width: 14px;
height: 14px;
position: relative;
top: 0;
left: 0;
border: 1px solid @border;
border-radius: 2px;
background-color: #ffffff;
transition: border-color .2s ease-in-out,background-color .2s ease-in-out;
&::after {
content: "";
display: table;
width: 4px;
height: 8px;
position: absolute;
top: 1px;
left: 4px;
border: 2px solid #fff;
border-top: 0;
border-left: 0;
transform: rotate(45deg) scale(0);
transition: all .2s ease-in-out;
}
}
.@{prefixCls}--indeterminate {
.@{prefixCls}__inner {
background-color: @blue;
border-color: @blue;
&::after {
content: "";
width: 8px;
height: 1px;
transform: scale(1);
position: absolute;
left: 2px;
top: 5px;
}
}
&:hover {
.@{prefixCls}__inner {
border-color: @blue;
}
}
}
.@{prefixCls}--checked {
.@{prefixCls}__inner {
border-color: @blue;
background-color: @blue;
&::after {
content: "";
display: table;
width: 4px;
height: 8px;
position: absolute;
top: 1px;
left: 4px;
border: 2px solid #ffffff;
border-top: 0;
border-left: 0;
transform: rotate(45deg) scale(1);
transition: all .2s ease-in-out;
}
}
&:hover {
.@{prefixCls}__inner {
border-color: @blue;
}
}
}
.@{prefixCls}--disabled {
cursor: not-allowed;
.@{prefixCls}__inner {
background-color: #f3f3f3;
border-color: @border;
&::after {
animation-name: none;
border-color: #ccc;
}
}
&:hover {
.@{prefixCls}__inner {
border-color: @border;
}
}
}

View File

@@ -0,0 +1,58 @@
<template lang="html">
<label :class="`${prefixCls}-wrapper`">
<span :class="checkboxClass">
<span
:class="`${prefixCls}__inner`"
@click="toggle"></span>
</span>
</label>
</template>
<script>
export default {
name: 'zk-checkbox',
props: {
value: {
type: Boolean,
default: false,
},
disabled: {
type: Boolean,
default: false,
},
indeterminate: {
type: Boolean,
default: false,
},
},
data() {
return {
prefixCls: 'zk-checkbox',
};
},
computed: {
checkboxClass() {
return [
`${this.prefixCls}`,
{
[`${this.prefixCls}--disabled`]: this.disabled,
[`${this.prefixCls}--checked`]: this.value,
[`${this.prefixCls}--indeterminate`]: this.indeterminate,
},
];
},
},
methods: {
toggle() {
if (this.disabled) {
return false;
}
const value = !this.value;
this.$emit('input', value);
return this.$emit('on-change', value);
},
},
};
</script>
<style lang="less" scoped src="./Checkbox.less"></style>

View File

@@ -0,0 +1,170 @@
@import "./font/iconfont";
// text
@prefixCls: zk-table;
// color
@black: #515a6e;
@white: #ffffff;
@border: #e9eaec;
@hoverRow: #ebf7ff;
@backgroundRow: #f8f8f9;
.@{prefixCls} {
position: relative;
width: 100%;
box-sizing: border-box;
background-color: @white;
border: 1px solid @border;
font-size: 14px;
line-height: 26px;
color: @black;
overflow: hidden;
}
.@{prefixCls}__header-cell {
font-weight: bold;
}
.@{prefixCls}__cell-inner {
padding: 0px 18px;
}
.@{prefixCls}-default {
font-size: 14px;
.@{prefixCls}__header-row {
height: 40px !important;
}
.@{prefixCls}__body-row {
height: 48px !important;
}
}
.@{prefixCls}-small {
font-size: 12px;
.@{prefixCls}__header-row {
height: 36px !important;
}
.@{prefixCls}__body-row {
height: 40px !important;
}
}
.@{prefixCls}-large {
font-size: 16px;
.@{prefixCls}__header-row {
height: 43px !important;
}
.@{prefixCls}__body-row {
height: 60px !important;
}
}
.@{prefixCls}__header-wrapper,
.@{prefixCls}__footer-wrapper {
overflow: hidden;
}
.@{prefixCls}__body-wrapper {
overflow: auto;
}
.@{prefixCls}__header,
.@{prefixCls}__body,
.@{prefixCls}__footer {
width: 100%;
table-layout: fixed;
border-collapse: collapse;
border-spacing: 0;
}
.@{prefixCls}__header-row {
height: 40px;
box-sizing: border-box;
background-color: @backgroundRow;
border-bottom: 1px solid @border;
}
.@{prefixCls}__footer-row {
height: 40px;
box-sizing: border-box;
background-color: @white;
border-top: 1px solid @border;
}
.@{prefixCls}__body-row {
height: 48px;
box-sizing: border-box;
&:not(:first-of-type) {
border-top: 1px solid @border;
}
}
.@{prefixCls}__header-cell,
.@{prefixCls}__body-cell,
.@{prefixCls}__footer-cell {
box-sizing: border-box;
text-align: left;
vertical-align: middle;
word-break: break-all;
overflow: hidden;
}
.@{prefixCls}--firstProp-header-inner {
padding-left: 32px;
}
.@{prefixCls}--empty-row {
height: 80px;
}
.@{prefixCls}--empty-content {
text-align: center;
}
.@{prefixCls}--center-cell {
text-align: center;
}
.@{prefixCls}--right-cell {
text-align: right;
}
.@{prefixCls}--stripe-row {
background-color: @backgroundRow;
}
.@{prefixCls}--row-hover {
background-color: @hoverRow;
}
.@{prefixCls}--border-cell {
&:not(:last-of-type) {
border-right: 1px solid @border;
}
}
.@{prefixCls}--tree-icon {
margin-right: 6px;
cursor: pointer;
}
.@{prefixCls}--expand-inner {
text-align: center;
cursor: pointer;
transition: transform .2s ease-in-out;
}
.@{prefixCls}--expanded-inner {
transform: rotate(90deg);
}
.@{prefixCls}--expand-content {
padding: 20px;
}

View File

@@ -0,0 +1,396 @@
<template lang="html">
<div
v-if="columns.length > 0"
ref="table"
:class="[prefixCls, `${prefixCls}-${size}`, tableClass]">
<Spin fix v-if="loading"></Spin>
<div
v-show="showHeader"
ref="header-wrapper"
:class="`${prefixCls}__header-wrapper`"
@mousewheel="handleEvent('header', $event)">
<table-header
ref="table-header">
</table-header>
</div>
<div
ref="body-wrapper"
:style="bodyWrapperStyle"
:class="`${prefixCls}__body-wrapper`"
@scroll="handleEvent('body', $event)">
<table-body
ref="table-body"
:class="bodyClass">
</table-body>
</div>
<div
v-show="showSummary && data.length > 0"
ref="footer-wrapper"
:class="`${prefixCls}__footer-wrapper`"
@mousewheel="handleEvent('footer', $event)">
<table-footer
ref="table-footer">
</table-footer>
</div>
</div>
</template>
<script>
import TableHeader from "./TableHeader";
import TableBody from "./TableBody";
import TableFooter from "./TableFooter";
import { mixins, scrollBarWidth as getSbw } from "./utils";
/* eslint-disable no-underscore-dangle */
/* eslint-disable no-param-reassign */
// function getBodyData(data, isTreeType, childrenProp, isFold, level = 1) {
function getBodyData(
primaryKey,
oldBodyData,
data,
isTreeType,
childrenProp,
isFold,
parentFold,
level = 1
) {
let bodyData = [];
data.forEach((row, index) => {
const children = row[childrenProp];
const childrenLen =
Object.prototype.toString.call(children).slice(8, -1) === "Array"
? children.length
: 0;
let curIsFold = isFold;
if (
isFold &&
typeof primaryKey === "string" &&
Array.isArray(oldBodyData)
) {
for (let i = 0; i < oldBodyData.length; i++) {
const oldRow = oldBodyData[i];
if (oldRow[primaryKey] === row[primaryKey]) {
if ("_isFold" in oldRow) {
curIsFold = oldRow._isFold;
}
break;
}
}
}
bodyData.push({
_isHover: false,
_isExpanded: false,
_isChecked: false,
_level: level,
// _isHide: isFold ? level !== 1 : false,
// _isFold: isFold,
_isHide: level !== 1 ? isFold && parentFold : false,
_isFold: isFold && curIsFold,
_childrenLen: childrenLen,
_normalIndex: index + 1,
...row
});
if (isTreeType) {
if (childrenLen > 0) {
// bodyData = bodyData.concat(getBodyData(children, true, childrenProp, isFold, level + 1));
bodyData = bodyData.concat(
getBodyData(
primaryKey,
oldBodyData,
children,
true,
childrenProp,
isFold,
curIsFold,
level + 1
)
);
}
}
});
return bodyData;
}
function initialState(table, expandKey) {
return {
bodyHeight: "auto",
firstProp: expandKey || (table.columns[0] && table.columns[0].key),
// bodyData: getBodyData(table.data, table.treeType, table.childrenProp, table.isFold),
bodyData: getBodyData(
table.primaryKey,
table.bodyData,
table.data,
table.treeType,
table.childrenProp,
table.isFold,
false
)
};
}
function initialColumns(table, clientWidth) {
let columnsWidth = 0;
const minWidthColumns = [];
const otherColumns = [];
const columns = table.columns.concat();
if (table.expandType) {
columns.unshift({
width: "50"
});
}
if (table.selectable) {
columns.unshift({
width: "50"
});
}
if (table.showIndex) {
columns.unshift({
width: "50px",
key: "_normalIndex",
title: table.indexText
});
}
columns.forEach((column, index) => {
let width = "";
let minWidth = "";
if (!column.width) {
if (column.minWidth) {
minWidth =
typeof column.minWidth === "number"
? column.minWidth
: parseInt(column.minWidth, 10);
} else {
minWidth = 80;
}
minWidthColumns.push({
...column,
minWidth,
_index: index
});
} else {
width =
typeof column.width === "number"
? column.width
: parseInt(column.width, 10);
otherColumns.push({
...column,
width,
_index: index
});
}
columnsWidth += minWidth || width;
});
const scrollBarWidth = getSbw();
const totalWidth = columnsWidth + scrollBarWidth;
const isScrollX = totalWidth > clientWidth;
if (!isScrollX) {
const extraWidth = clientWidth - totalWidth;
const averageExtraWidth = Math.floor(extraWidth / minWidthColumns.length);
minWidthColumns.forEach(column => {
column.computedWidth = column.minWidth + averageExtraWidth;
});
}
const tableColumns = otherColumns.concat(minWidthColumns);
tableColumns.sort((a, b) => a._index - b._index);
return tableColumns;
}
export default {
name: "TreeTable",
mixins: [mixins],
components: {
TableHeader,
TableBody,
TableFooter
},
props: {
data: {
type: Array,
default: () => []
},
columns: {
type: Array,
default: () => []
},
size: {
default() {
return !this.$IVIEW || this.$IVIEW.size === ""
? "default"
: this.$IVIEW.size;
}
},
loading: {
type: Boolean,
default: false
},
maxHeight: {
type: [String, Number],
default: "auto"
},
stripe: {
type: Boolean,
default: false
},
border: {
type: Boolean,
default: false
},
treeType: {
type: Boolean,
default: true
},
childrenProp: {
type: String,
default: "children"
},
isFold: {
type: Boolean,
default: true
},
expandType: {
type: Boolean,
default: true
},
selectable: {
type: Boolean,
default: true
},
selectType: {
type: String,
default: "checkbox"
},
emptyText: {
type: String,
default: "暂无数据"
},
showHeader: {
type: Boolean,
default: true
},
showIndex: {
type: Boolean,
default: false
},
indexText: {
type: String,
default: "#"
},
showSummary: {
type: Boolean,
default: false
},
sumText: {
type: String,
default: "合计"
},
primaryKey: String,
summaryMethod: Function,
showRowHover: {
type: Boolean,
default: true
},
rowKey: Function,
rowClassName: [String, Function],
cellClassName: [String, Function],
rowStyle: [Object, Function],
cellStyle: [Object, Function],
expandKey: String
},
data() {
return {
computedWidth: "",
computedHeight: "",
tableColumns: [],
...initialState(this, this.expandKey)
};
},
computed: {
bodyWrapperStyle() {
return {
height: this.bodyHeight
};
},
tableClass() {
return {
[`${this.prefixCls}--border`]: this.border
};
},
bodyClass() {
return {
[`${this.prefixCls}--stripe`]: this.stripe
};
}
},
methods: {
handleEvent(type, $event) {
this.validateType(type, ["header", "body", "footer"], "handleEvent");
const eventType = $event.type;
if (eventType === "scroll") {
this.$refs["header-wrapper"].scrollLeft = $event.target.scrollLeft;
this.$refs["footer-wrapper"].scrollLeft = $event.target.scrollLeft;
}
if (eventType === "mousewheel") {
const deltaX = $event.deltaX;
const $body = this.$refs["body-wrapper"];
if (deltaX > 0) {
$body.scrollLeft += 10;
} else {
$body.scrollLeft -= 10;
}
}
return this.$emit(`${type}-${eventType}`, $event);
},
// computedWidth, computedHeight, tableColumns
measure() {
this.$nextTick(() => {
const { clientWidth, clientHeight } = this.$el;
this.computedWidth = clientWidth + 2;
this.computedHeight = clientHeight + 2;
const maxHeight = parseInt(this.maxHeight, 10);
if (this.maxHeight !== "auto" && this.computedHeight > maxHeight) {
this.bodyHeight = `${maxHeight - 83}px`;
}
this.tableColumns = initialColumns(this, clientWidth);
});
},
getCheckedProp(key = "index") {
if (!this.selectable) {
return [];
}
const checkedIndexs = [];
this.bodyData.forEach((item, index) => {
if (item._isChecked) {
if (key === "index") {
checkedIndexs.push(index);
} else {
checkedIndexs.push(item[key]);
}
}
});
return checkedIndexs;
}
},
watch: {
$props: {
deep: true,
handler() {
Object.assign(this.$data, initialState(this, this.expandKey));
}
}
},
updated() {
this.measure();
},
mounted() {
this.measure();
window.addEventListener("resize", this.measure);
},
beforeDestroy() {
window.removeEventListener("resize", this.measure);
}
};
</script>
<style lang="less" src="./Table.less"></style>

View File

@@ -0,0 +1,328 @@
import Checkbox from '../Checkbox/Checkbox'; // eslint-disable-line
// import Radio from '../Radio/Radio'; // eslint-disable-line
import { mixins } from './utils';
import { Radio } from 'view-design'; // eslint-disable-line
/* eslint-disable no-underscore-dangle */
export default {
name: 'TreeTable__body',
mixins: [mixins],
components: { Radio },
data() {
return {
radioSelectedIndex: -1,
};
},
computed: {
table() {
return this.$parent;
},
},
methods: {
toggleStatus(type, row, rowIndex, value) {
this.validateType(type, ['Expanded', 'Checked', 'Hide', 'Fold'], 'toggleStatus', false);
const target = this.table.bodyData[rowIndex];
this.table.bodyData.splice(rowIndex, 1, {
...target,
[`_is${type}`]: typeof value === 'undefined' ? !row[`_is${type}`] : value,
});
},
getChildrenIndex(parentLevel, parentIndex, careFold = true) {
const data = this.table.bodyData;
let childrenIndex = [];
for (let i = parentIndex + 1; i < data.length; i++) {
if (data[i]._level <= parentLevel) break;
if (data[i]._level - 1 === parentLevel) {
childrenIndex.push(i);
}
}
const len = childrenIndex.length; // important!!!
if (len > 0) {
for (let i = 0; i < len; i++) {
const childData = data[childrenIndex[i]];
if (
childData._childrenLen &&
(!careFold || (careFold && !childData._isFold))
) {
childrenIndex = childrenIndex.concat(
this.getChildrenIndex(childData._level, childrenIndex[i], careFold));
}
}
}
return childrenIndex;
},
handleEvent($event, type, data, others) {
const certainType = this.validateType(type, ['cell', 'row', 'checkbox', 'icon', 'radio'], 'handleEvent');
const eventType = $event ? $event.type : '';
const { row, rowIndex, column, columnIndex } = data;
const latestData = this.table.bodyData;
// Checkbox
if (certainType.checkbox) {
const { isChecked } = others;
this.toggleStatus('Checked', row, rowIndex, isChecked);
if (row._childrenLen > 0) {
const childrenIndex = this.getChildrenIndex(row._level, rowIndex, false);
for (let i = 0; i < childrenIndex.length; i++) {
this.toggleStatus('Checked', latestData[childrenIndex[i]], childrenIndex[i], isChecked);
}
}
return this.table.$emit('checkbox-click', latestData[rowIndex], column, columnIndex, $event);
}
// Radio
if (certainType.radio) {
this.radioSelectedIndex = rowIndex;
return this.table.$emit('radio-click', { row, rowIndex, column, columnIndex, $event });
}
// Tree's icon
if (certainType.icon) {
$event.stopPropagation();
this.toggleStatus('Fold', row, rowIndex);
const childrenIndex = this.getChildrenIndex(row._level, rowIndex);
for (let i = 0; i < childrenIndex.length; i++) {
this.toggleStatus('Hide', latestData[childrenIndex[i]], childrenIndex[i]);
}
return this.table.$emit('tree-icon-click', latestData[rowIndex], column, columnIndex, $event);
}
if (certainType.cell && eventType === 'click') {
// 点击扩展单元格
if (this.isExpandCell(this.table, columnIndex)) {
this.toggleStatus('Expanded', row, rowIndex);
return this.table.$emit('expand-cell-click', latestData[rowIndex], column, columnIndex, $event);
}
}
// 行Hover
if (certainType.row && (eventType === 'mouseenter' || eventType === 'mouseleave')) {
const { hover } = others;
const target = latestData[rowIndex];
latestData.splice(rowIndex, 1, {
...target,
_isHover: hover,
});
}
if (certainType.row && others && others.clickRow && certainType.radio) {
this.radioSelectedIndex = rowIndex;
return this.table.$emit('radio-click', { row, rowIndex, column, columnIndex, $event });
}
if (certainType.cell) {
return this.table.$emit(`${type}-${eventType}`, latestData[rowIndex], rowIndex, column, columnIndex, $event);
}
return this.table.$emit(`${type}-${eventType}`, latestData[rowIndex], rowIndex, $event);
},
},
render() {
// key
// function getKey(row, rowIndex) {
// const rowKey = this.table.rowKey;
// if (rowKey) {
// return rowKey.call(null, row, rowIndex);
// }
// return rowIndex;
// }
// style
function getStyle(type, row, rowIndex, column, columnIndex) {
const certainType = this.validateType(type, ['cell', 'row'], 'getStyle');
const style = this.table[`${type}Style`];
if (typeof style === 'function') {
if (certainType.row) {
return style.call(null, row, rowIndex);
}
if (certainType.cell) {
return style.call(null, row, rowIndex, column, columnIndex);
}
}
return style;
}
// className
function getClassName(type, row, rowIndex, column, columnIndex) {
const certainType = this.validateType(type, ['cell', 'row', 'inner'], 'getClassName');
const classList = [];
if (column && column.key == "_normalIndex") {
classList.push(`${this.prefixCls}--center-cell`);
}
// console.log(certainType.inner)
if (certainType.row || certainType.cell) {
const className = this.table[`${type}ClassName`];
if (typeof className === 'string') {
classList.push(className);
} else if (typeof className === 'function') {
if (certainType.row) {
classList.push(className.call(null, row, rowIndex) || '');
}
if (certainType.cell) {
classList.push(className.call(null, row, rowIndex, column, columnIndex) || '');
}
}
if (certainType.row) {
classList.push(`${this.prefixCls}__body-row`);
if (this.table.stripe && rowIndex % 2 !== 0) {
classList.push(`${this.prefixCls}--stripe-row`);
}
if (this.table.showRowHover && row._isHover) {
classList.push(`${this.prefixCls}--row-hover`);
}
}
if (certainType.cell) {
classList.push(`${this.prefixCls}__body-cell`);
if (this.table.border) {
classList.push(`${this.prefixCls}--border-cell`);
}
const align = column.align;
if (['center', 'right'].indexOf(align) > -1) {
classList.push(`${this.prefixCls}--${align}-cell`);
}
}
}
if (certainType.inner) {
classList.push(`${this.prefixCls}__cell-inner`);
if (this.isExpandCell(this.table, columnIndex)) {
classList.push(`${this.prefixCls}--expand-inner`);
if (row._isExpanded) {
classList.push(`${this.prefixCls}--expanded-inner`);
}
}
}
return classList.join(' ');
}
// 根据type渲染单元格Cell
function renderCell(row, rowIndex, column, columnIndex) {
// ExpandType
if (this.isExpandCell(this.table, columnIndex)) {
return <i class='zk-icon zk-icon-angle-right'></i>;
}
// SelectionType's Checkbox
if (this.isSelectionCell(this.table, columnIndex)) {
let res = null;
if (this.table.selectType === 'checkbox') {
let allCheck;
let childrenIndex;
const hasChildren = row._childrenLen > 0;
if (hasChildren) {
childrenIndex = this.getChildrenIndex(row._level, rowIndex, false);
allCheck = true;
for (let i = 0; i < childrenIndex.length; i++) {
if (!this.table.bodyData[childrenIndex[i]]._isChecked) {
allCheck = false;
break;
}
}
} else {
allCheck = row._isChecked;
}
let indeterminate = false;
if (hasChildren && !allCheck) {
for (let i = 0; i < childrenIndex.length; i++) {
if (this.table.bodyData[childrenIndex[i]]._isChecked) {
indeterminate = true;
break;
}
}
}
// res = <Checkbox
// indeterminate={indeterminate}
// value={allCheck}
// onOn-change={isChecked => this.handleEvent(null, 'checkbox', { row, rowIndex, column, columnIndex }, { isChecked })}>
// </Checkbox>;
} else {
res = <Radio value={this.radioSelectedIndex === rowIndex} on-on-change={() => this.handleEvent(null, 'radio', { row, rowIndex, column, columnIndex })}></Radio>;
}
return res;
}
// Tree's firstProp
if (this.table.treeType && this.table.firstProp === column.key) {
return <span
class={`${this.prefixCls}--level-${row._level}-cell`}
style={{
marginLeft: `${(row._level - 1) * 24}px`,
paddingLeft: row._childrenLen === 0 ? '20px' : '',
}}>
{row._childrenLen > 0 &&
<i
class={`${this.prefixCls}--tree-icon zk-icon zk-icon-${row._isFold ? 'plus' : 'minus'}-square-o`}
on-click={$event => this.handleEvent($event, 'icon', { row, rowIndex, column, columnIndex }, { isFold: row._isFold })}></i>
}
{row[column.key] ? row[column.key] : ''}
</span>;
}
// TreeType children's index
if (this.table.showIndex && this.table.treeType && column.key === '_normalIndex' && row._level > 1) {
return '';
}
if (column.type === undefined || column.type === 'custom') {
return row[column.key];
} else if (column.type === 'template') {
return this.table.$scopedSlots[column.template]
? this.table.$scopedSlots[column.template]({ row, rowIndex, column, columnIndex })
: '';
}
return '';
}
// Template
return (
<table cellspacing="0" cellpadding="0" border="0" class={`${this.prefixCls}__body`}>
{/* <colgroup>
{this.table.tableColumns.map(column =>
<col width={column.computedWidth || column.minWidth || column.width}></col>)
}
</colgroup> */}
<tbody>
{ this.table.bodyData.length > 0
? this.table.bodyData.map((row, rowIndex) =>
[
<tr
v-show={!row._isHide}
key={`table_row_${rowIndex}`}
style={getStyle.call(this, 'row', row, rowIndex)}
class={getClassName.call(this, 'row', row, rowIndex)}
on-click={$event => this.handleEvent($event, 'row', { row, rowIndex }, { clickRow: true })}
on-dblclick={$event => this.handleEvent($event, 'row', { row, rowIndex })}
on-contextmenu={$event => this.handleEvent($event, 'row', { row, rowIndex })}
on-mouseenter={$event => this.handleEvent($event, 'row', { row, rowIndex }, { hover: true })}
on-mouseleave={$event => this.handleEvent($event, 'row', { row, rowIndex }, { hover: false })}>
{ this.table.tableColumns.map((column, columnIndex) =>
column.key ? <td
style={getStyle.call(this, 'cell', row, rowIndex, column, columnIndex)}
class={getClassName.call(this, 'cell', row, rowIndex, column, columnIndex)}
on-click={$event => this.handleEvent($event, 'cell', { row, rowIndex, column, columnIndex })}
on-dblclick={$event => this.handleEvent($event, 'cell', { row, rowIndex, column, columnIndex })}
on-contextmenu={$event => this.handleEvent($event, 'cell', { row, rowIndex, column, columnIndex })}
on-mouseenter={$event => this.handleEvent($event, 'cell', { row, rowIndex, column, columnIndex })}
on-mouseleave={$event => this.handleEvent($event, 'cell', { row, rowIndex, column, columnIndex })}>
<div class={getClassName.call(this, 'inner', row, rowIndex, column, columnIndex)}>
{renderCell.call(this, row, rowIndex, column, columnIndex)}
</div>
</td>:"")
}
</tr>,
this.table.expandType && row._isExpanded &&
<tr
key={rowIndex}
class={`${this.prefixCls}__body-row ${this.prefixCls}--expand-row`}>
<td
class={`${this.prefixCls}--expand-content`}
colspan={this.table.tableColumns.length}>
{this.table.$scopedSlots.expand
? this.table.$scopedSlots.expand({ row, rowIndex })
: ''
}
</td>
</tr>,
])
: <tr
class={`${this.prefixCls}--empty-row`}>
<td
class={`${this.prefixCls}__body-cell ${this.prefixCls}--empty-content`}
colspan={this.table.tableColumns.length}>
{this.table.emptyText}
</td>
</tr>
}
</tbody>
</table>
);
},
};

View File

@@ -0,0 +1,84 @@
import { mixins } from './utils';
/* eslint-disable no-underscore-dangle */
export default {
name: 'TreeTable__footer',
mixins: [mixins],
data() {
return {
};
},
computed: {
table() {
return this.$parent;
},
},
methods: {
},
render() {
// 计算各列总和
function renderCell({ key }, columnIndex) {
if (columnIndex === 0) {
return this.table.sumText;
}
const rows = this.table.bodyData;
const values = rows.map(row => Number(row[key]));
const precisions = [];
let notNumber = true;
values.forEach((value) => {
if (!isNaN(value)) {
notNumber = false;
const decimal = value.toString().split('.')[1];
precisions.push(decimal ? decimal.length : 0);
}
});
const precision = Math.max.apply(null, precisions);
if (!notNumber) {
return values.reduce((prev, curr) => {
const value = Number(curr);
if (!isNaN(value)) {
return parseFloat((prev + curr).toFixed(precision));
}
return prev;
}, 0);
}
return '';
}
// className
function getClassName() {
const classList = [];
classList.push(`${this.prefixCls}__footer-cell`);
if (this.table.border) {
classList.push(`${this.prefixCls}--border-cell`);
}
return classList.join(' ');
}
// Template
return (
<table cellspacing="0" cellpadding="0" border="0" class={ `${this.prefixCls}__footer` }>
<colgroup>
{ this.table.tableColumns.map(column =>
<col width={ column.computedWidth || column.minWidth || column.width }></col>)
}
</colgroup>
<tfoot>
<tr class={ `${this.prefixCls}__footer-row` }>
{ this.table.tableColumns.map((column, columnIndex) =>
<td class={ getClassName.call(this) }>
<div class={ `${this.prefixCls}__cell-inner` }>
{ this.table.summaryMethod
? this.table.summaryMethod(this.table.bodyData, column, columnIndex)
: renderCell.call(this, column, columnIndex) }
</div>
</td>)
}
</tr>
</tfoot>
</table>
);
},
};

View File

@@ -0,0 +1,108 @@
import Checkbox from "../Checkbox/Checkbox"; // eslint-disable-line
import { mixins } from "./utils";
/* eslint-disable no-underscore-dangle */
export default {
name: "TreeTable__header",
mixins: [mixins],
data() {
return {};
},
computed: {
table() {
return this.$parent;
}
},
methods: {
toggleAllChecked(checked) {
this.table.bodyData = this.table.bodyData.map(row => ({
...row,
_isChecked: checked
}));
}
},
render() {
// className
function getClassName(type, { headerAlign, key }) {
const certainType = this.validateType(
type,
["cell", "inner"],
"getClassName"
);
const classList = [];
if (key == "_normalIndex") {
classList.push(`${this.prefixCls}--center-cell`);
}
if (certainType.cell) {
classList.push(`${this.prefixCls}__header-cell`);
if (this.table.border) {
classList.push(`${this.prefixCls}--border-cell`);
}
if (["center", "right"].indexOf(headerAlign) > -1) {
classList.push(`${this.prefixCls}--${headerAlign}-cell`);
}
}
if (certainType.inner) {
classList.push(`${this.prefixCls}__cell-inner`);
if (this.table.treeType && this.table.firstProp === key) {
classList.push(`${this.prefixCls}--firstProp-header-inner`);
}
}
return classList.join(" ");
}
// 根据type渲染单元格Label
function renderLabel(column, columnIndex) {
if (
this.isSelectionCell(this.table, columnIndex) &&
this.selectType === "checkbox"
) {
const allCheck = this.table.bodyData.every(row => row._isChecked);
const indeterminate =
!allCheck && this.table.bodyData.some(row => row._isChecked);
return (
<Checkbox
indeterminate={indeterminate}
value={allCheck}
onOn-change={checked => this.toggleAllChecked(checked)}
></Checkbox>
);
}
return column.title ? column.title : "";
}
// Template
return (
<table
cellspacing="0"
cellpadding="0"
border="0"
class={`${this.prefixCls}__header`}
>
{/* <colgroup>
{this.table.tableColumns.map(column => (
<col
width={column.computedWidth || column.minWidth || column.width}
></col>
))}
</colgroup> */}
<thead>
<tr class={`${this.prefixCls}__header-row`}>
{
this.table.tableColumns.map((column, columnIndex) =>
column.key ? (
<th class={getClassName.call(this, "cell", column)}>
<div class={getClassName.call(this, "inner", column)}>
{renderLabel.call(this, column, columnIndex)}
</div>
</th>
) : (
""
)
)}
</tr>
</thead>
</table>
);
}
};

View File

@@ -0,0 +1,22 @@
// icon
@font-face {font-family: "iconfont";
src: url('iconfont.eot?t=1505310522875'); /* IE9*/
src: url('iconfont.eot?t=1505310522875#iefix') format('embedded-opentype'), /* IE6-IE8 */
url('data:application/x-font-woff;charset=utf-8;base64,d09GRgABAAAAAAW0AAsAAAAACOQAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABHU1VCAAABCAAAADMAAABCsP6z7U9TLzIAAAE8AAAARAAAAFZW7kggY21hcAAAAYAAAABuAAABojLtBtFnbHlmAAAB8AAAAa8AAAKA73SzT2hlYWQAAAOgAAAALwAAADYO3fRqaGhlYQAAA9AAAAAcAAAAJAfeA4ZobXR4AAAD7AAAABMAAAAUE+kAAGxvY2EAAAQAAAAADAAAAAwBbAHYbWF4cAAABAwAAAAeAAAAIAEUAF1uYW1lAAAELAAAAUUAAAJtPlT+fXBvc3QAAAV0AAAAQAAAAFryy5h0eJxjYGRgYOBikGPQYWB0cfMJYeBgYGGAAJAMY05meiJQDMoDyrGAaQ4gZoOIAgCKIwNPAHicY2Bk/s04gYGVgYOpk+kMAwNDP4RmfM1gxMjBwMDEwMrMgBUEpLmmMDgwVDwzZm7438AQw9zA0AAUZgTJAQAoHgyieJzFkcENwyAUQ98HyqHKKDmEZoEOklOnYOK/RmI+uXSCWDLG/pZAALyALK5iAfthDBxKLfLMO/LCJl+lRqL7fp7y3VuoKprV0KxO0qbyGOy5o/+xxPq9nV6YflNX9DY5fsA/k6Pj+yTpAn3jEO8AAHiclVDNitNQFD7n3slNE9vE5N7kpOn0J0mbKB3DGDMZRGw3bhQXA2LB5TyAbmfjohvBhQvfYEAEoc8wr+EDiK4KPkITU0EcXDmHw3fOgfN9fHygATTf+BUPQMIduA9P4AwAxRxjiw0xysqczdGLNI+UxbMki/QkzvljpFgov6jKlIQubLRwhA+iospyluFJuWCPsPCHiP1B+MKdHbr8I5pBNnpXP2Of0Bsnh/biXv30aKmKiexcdF2377ofOkLTOowd2Ba+Jt/QDFPUnzU79K7Gd9kYu/0sfP6qNxm45+/LN8MZGYjrNcrBxPqydEKn7behL92+frvXCcJeMlV48eNWILvD9Du0hXtgl+wSHIBZnJZLzNKyKgh9paPAdVca260hAxPBMBowz9t1uzUDuT8CswEDDtq8Gr7mADaM4QgetrKRhbozQooWeOrkKJVIojg9ccqqjcT3uBJ6lGNZnUYjnBU+ORbGaeYskM93m+kx4vGUrX5PQXK3kUSSrSS9JFWvFJHCjaIGJCFSugcOLeM6c7f6wyFZf/37+PO6AgD/x/vNnN/A7H8bhF86tmcbAHicY2BkYGAAYl/p/jnx/DZfGbhZGEDg6v0IKwT9/yELA7MEkMvBwAQSBQAZYgnZAHicY2BkYGBu+N/AEMPCAAJAkpEBFbACAEcLAm54nGNhYGBgfsnAwMKAwAAOmwD9AAAAAAAAdgCYAPYBQHicY2BkYGBgZQgEYhBgAmIuIGRg+A/mMwAAES0BcgAAeJxlj01OwzAQhV/6B6QSqqhgh+QFYgEo/RGrblhUavdddN+mTpsqiSPHrdQDcB6OwAk4AtyAO/BIJ5s2lsffvHljTwDc4Acejt8t95E9XDI7cg0XuBeuU38QbpBfhJto41W4Rf1N2MczpsJtdGF5g9e4YvaEd2EPHXwI13CNT+E69S/hBvlbuIk7/Aq30PHqwj7mXle4jUcv9sdWL5xeqeVBxaHJIpM5v4KZXu+Sha3S6pxrW8QmU4OgX0lTnWlb3VPs10PnIhVZk6oJqzpJjMqt2erQBRvn8lGvF4kehCblWGP+tsYCjnEFhSUOjDFCGGSIyujoO1Vm9K+xQ8Jee1Y9zed0WxTU/3OFAQL0z1xTurLSeTpPgT1fG1J1dCtuy56UNJFezUkSskJe1rZUQuoBNmVXjhF6XNGJPyhnSP8ACVpuyAAAAHicY2BigAAuBuyAlZGJkZmRhZGVkY2BsYI7MS89J1W3KDM9o4S3IKe0WLe4sDSxKFU3ny83Mw+Jy8AAAHSWD8A=') format('woff'),
url('iconfont.ttf?t=1505310522875') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/
url('iconfont.svg?t=1505310522875#iconfont') format('svg'); /* iOS 4.1- */
}
.zk-icon {
font-family: "iconfont" !important;
font-size: 14px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.zk-icon-plus-square-o:before { content: "\e631"; }
.zk-icon-minus-square-o:before { content: "\e632"; }
.zk-icon-angle-right:before { content: "\e633"; }

View File

@@ -0,0 +1,42 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
<!--
2013-9-30: Created.
-->
<svg>
<metadata>
Created by iconfont
</metadata>
<defs>
<font id="iconfont" horiz-adv-x="1024" >
<font-face
font-family="iconfont"
font-weight="500"
font-stretch="normal"
units-per-em="1024"
ascent="896"
descent="-128"
/>
<missing-glyph />
<glyph glyph-name="x" unicode="x" horiz-adv-x="1001"
d="M281 543q-27 -1 -53 -1h-83q-18 0 -36.5 -6t-32.5 -18.5t-23 -32t-9 -45.5v-76h912v41q0 16 -0.5 30t-0.5 18q0 13 -5 29t-17 29.5t-31.5 22.5t-49.5 9h-133v-97h-438v97zM955 310v-52q0 -23 0.5 -52t0.5 -58t-10.5 -47.5t-26 -30t-33 -16t-31.5 -4.5q-14 -1 -29.5 -0.5
t-29.5 0.5h-32l-45 128h-439l-44 -128h-29h-34q-20 0 -45 1q-25 0 -41 9.5t-25.5 23t-13.5 29.5t-4 30v167h911zM163 247q-12 0 -21 -8.5t-9 -21.5t9 -21.5t21 -8.5q13 0 22 8.5t9 21.5t-9 21.5t-22 8.5zM316 123q-8 -26 -14 -48q-5 -19 -10.5 -37t-7.5 -25t-3 -15t1 -14.5
t9.5 -10.5t21.5 -4h37h67h81h80h64h36q23 0 34 12t2 38q-5 13 -9.5 30.5t-9.5 34.5q-5 19 -11 39h-368zM336 498v228q0 11 2.5 23t10 21.5t20.5 15.5t34 6h188q31 0 51.5 -14.5t20.5 -52.5v-227h-327z" />
<glyph glyph-name="angle-right" unicode="&#58931;" d="M384.087 97.474c-7.857 0-15.713 2.997-21.707 8.992-11.989 11.989-11.989 31.426 0 43.415l234.118 234.12-234.118 234.118c-11.988 11.989-11.988 31.427 0 43.416 11.989 11.988 31.426 11.988 43.416 0l255.826-255.827c11.989-11.989 11.989-31.427 0-43.416l-255.826-255.827c-5.995-5.995-13.851-8.992-21.708-8.992z" horiz-adv-x="1024" />
<glyph glyph-name="plus-square-o" unicode="&#58929;" d="M810.666667 768H213.333333c-46.933333 0-85.333333-38.4-85.333333-85.333333v-597.333334c0-46.933333 38.4-85.333333 85.333333-85.333333h597.333334c46.933333 0 85.333333 38.4 85.333333 85.333333V682.666667c0 46.933333-38.4 85.333333-85.333333 85.333333z m42.666666-682.666667c0-25.6-17.066667-42.666667-42.666666-42.666666H213.333333c-25.6 0-42.666667 17.066667-42.666666 42.666666V682.666667c0 25.6 17.066667 42.666667 42.666666 42.666666h597.333334c25.6 0 42.666667-17.066667 42.666666-42.666666v-597.333334zM768 384c0-25.6-17.066667-42.666667-42.666667-42.666667H298.666667c-25.6 0-42.666667 17.066667-42.666667 42.666667s17.066667 42.666667 42.666667 42.666667h426.666666c25.6 0 42.666667-17.066667 42.666667-42.666667zM512 640c25.6 0 42.666667-17.066667 42.666667-42.666667v-426.666666c0-25.6-17.066667-42.666667-42.666667-42.666667s-42.666667 17.066667-42.666667 42.666667V597.333333c0 25.6 17.066667 42.666667 42.666667 42.666667z" horiz-adv-x="1024" />
<glyph glyph-name="minus-square-o" unicode="&#58930;" d="M810.666667 768H213.333333c-46.933333 0-85.333333-38.4-85.333333-85.333333v-597.333334c0-46.933333 38.4-85.333333 85.333333-85.333333h597.333334c46.933333 0 85.333333 38.4 85.333333 85.333333V682.666667c0 46.933333-38.4 85.333333-85.333333 85.333333z m42.666666-682.666667c0-25.6-17.066667-42.666667-42.666666-42.666666H213.333333c-25.6 0-42.666667 17.066667-42.666666 42.666666V682.666667c0 25.6 17.066667 42.666667 42.666666 42.666666h597.333334c25.6 0 42.666667-17.066667 42.666666-42.666666v-597.333334zM768 384c0-25.6-17.066667-42.666667-42.666667-42.666667H298.666667c-25.6 0-42.666667 17.066667-42.666667 42.666667s17.066667 42.666667 42.666667 42.666667h426.666666c25.6 0 42.666667-17.066667 42.666667-42.666667z" horiz-adv-x="1024" />
</font>
</defs></svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@@ -0,0 +1,6 @@
import mixins from './mixins';
import scrollBarWidth from './scrollBarWidth';
export {
mixins,
scrollBarWidth
}

View File

@@ -0,0 +1,34 @@
export default {
data() {
return {
prefixCls: 'zk-table',
};
},
methods: {
validateType(type, validTypes, funcName, isReturn = true) {
if (validTypes.indexOf(type) < 0) throw new Error(`${funcName}'s type must is ${validTypes.join(' or ')}.`);
if (isReturn) {
const certainType = {};
validTypes.forEach((item) => {
certainType[item] = item === type;
});
return certainType;
}
return true;
},
isExpandCell(table, columnIndex) {
return table.expandType && (
(table.showIndex && columnIndex === 1) ||
(!table.showIndex && columnIndex === 0)
);
},
isSelectionCell(table, columnIndex) {
return table.selectable && (
(table.showIndex && table.expandType && columnIndex === 2) ||
(!table.showIndex && table.expandType && columnIndex === 1) ||
(table.showIndex && !table.expandType && columnIndex === 1) ||
(!table.showIndex && !table.expandType && columnIndex === 0)
);
},
},
};

View File

@@ -0,0 +1,28 @@
import Vue from 'vue';
let scrollBarWidth;
export default function () {
if (Vue.prototype.$isServer) return 0;
if (scrollBarWidth !== undefined) return scrollBarWidth;
const outer = document.createElement('div');
outer.style.visibility = 'hidden';
outer.style.width = '100px';
outer.style.position = 'absolute';
outer.style.top = '-9999px';
document.body.appendChild(outer);
const widthNoScroll = outer.offsetWidth;
outer.style.overflow = 'scroll';
const inner = document.createElement('div');
inner.style.width = '100%';
outer.appendChild(inner);
const widthWithScroll = inner.offsetWidth;
outer.parentNode.removeChild(outer);
scrollBarWidth = widthNoScroll - widthWithScroll;
return scrollBarWidth;
}