Commit d9af43cc authored by 周远喜's avatar 周远喜

ok

parent 3fee7396
<template>
<div class="treeTbale">
<div class="table-tools">
<div class="table-search">
<slot name="easySearch"></slot>
</div>
<div class="btns">
<slot name="buttons"></slot>
<!-- <Button @click="config=!config">
<Icon type="md-build" class="table-set" size="14" title="列设置" />
</Button>-->
</div>
</div>
<table>
<thead>
<tr>
<th v-for="(column, index) in cloneColumns" :key="index">
<label v-if="column.type === 'selection'">
<Checkbox v-model="all"></Checkbox>
</label>
<label v-else>
{{ renderHeader(column, index) }}
<span class="ivu-table-sort" v-if="column.sortable">
<Icon
type="arrow-up-b"
:class="{ on: column._sortType === 'asc' }"
@click.native="handleSort(index, 'asc')"
/>
<Icon
type="arrow-down-b"
:class="{ on: column._sortType === 'desc' }"
@click.native="handleSort(index, 'desc')"
/>
</span>
</label>
</th>
</tr>
</thead>
<tbody>
<tr
v-for="(item, index) in trs"
:key="item.id"
v-show="show(item)"
class="treetr"
:id="'tr' + index"
:draggable="drag"
@dragstart="dragstart($event, index, item)"
@drop="dragdrop($event, index, item)"
@dragenter="dragenter($event, index, item)"
@dragover="dragover($event, index, item)"
@dragleave="dragleave($event, index, item)"
>
<td
v-for="(column, snum) in columns"
:key="column.key"
:style="tdStyle(column)"
>
<!-- 多选 -->
<label
v-if="column.type === 'selection'"
@click="handleCheckClick(item, $event, index)"
>
<Checkbox v-model="item.checked"></Checkbox>
</label>
<!-- 图标 -->
<div v-if="column.type === 'icon'">
<i
class="icon-set"
size="small"
@click="RowClick(item, $event, index, action.text)"
v-for="action in column.actions"
:key="action.text"
>
<Icon
:type="action.type"
:title="action.text"
:style="action.style"
/>
</i>
</div>
<div v-if="column.type === 'icons'">
<Icon :type="item[column.key]" size="20" />
</div>
<state
v-if="column.code"
:code="column.code"
:value="item[column.key]"
/>
<!-- 树图标 -->
<span @click="toggle(index, item)" v-if="snum == iconRow()">
<span v-html="item.spaceHtml"></span>
<a v-if="item.children && item.children.length > 0">
<i
class="ivu-icon"
:class="{
'ivu-icon-ios-arrow-forward': !item.expanded,
'ivu-icon-ios-arrow-down': item.expanded,
}"
></i> </a
><i v-else class="ms-tree-space"></i>
</span>
<!-- 菜单名称、排序、请求地址 -->
<label
v-if="
!column.type && !column.code && !column.render && !column.slot
"
>
{{ renderBody(item, column) }}
</label>
<table-expand
v-if="column.render && !column.type && !column.solt"
:row="item"
:column="column"
:index="snum"
:render="column.render"
></table-expand>
<column-slot
v-if="column.slot"
:row="item"
:column="column"
:index="snum"
></column-slot>
</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
import TableExpand from "./expand";
import ColumnSlot from "./columnSolt";
export default {
name: "treeGrid",
components: { TableExpand, ColumnSlot },
props: {
mode: {
type: [String, Number],
default: 0,
validator: (v) => {
var modes = ["read", "column", "row"];
if (/^\d+/.test(v)) {
return v >= 0 && v < modes.length;
}
return modes.indexOf(v) > -1;
},
},
action: {
//接口地址
type: String,
default: null,
},
level: {
//展开层级
type: Number,
default: 0,
},
query: {
//参数
type: Object,
},
dataFormater: {
//数据处理函数
type: Function,
},
columns: Array,
items: {
//接收树形数据
type: Array,
default() {
return [];
},
},
data: {
//接收UpId型数据
type: Array,
default() {
return [];
},
},
rowKey: {
//默认行主键
type: [String],
default: "id",
},
root: {
// 根级UpId的值.
type: [String, Number],
default: 0,
},
parent: {
// 父级字段名称
type: String,
default: "upId",
},
iconName: false,
drag: {
//拖拽
type: Boolean,
default: false,
},
spaceWidth: {
//树形表格缩进距离
type: Number,
default: 20,
},
},
provide() {
return {
tableRoot: this.slots,
};
},
data() {
return {
color: "#19be6b",
all: true,
logs: [],
trs: [], // 处理后数据数组
cloneColumns: [], // 处理后的表头数据
checkGroup: [], // 复选框数组
checks: false, // 全选
tdsWidth: 0, // td总宽
timer: false, // 控制监听时长
dataLength: 0, // 树形数据长度
dragIndex: -1, //拖拽开始的序号
};
},
computed: {},
watch: {
items() {
if (this.items) {
this.trs = [];
this.dataLength = this.Length(this.items);
this.initData(this.deepCopy(this.items), 1, null);
this.checkGroup = this.renderCheck(this.items);
if (this.checkGroup.length == this.dataLength) {
this.checks = true;
} else {
this.checks = false;
}
}
},
columns: {
handler() {
this.cloneColumns = this.makeColumns();
},
deep: true,
},
checkGroup(data) {
this.checkAllGroupChange(data);
},
},
mounted() {
if (this.items && this.items.length > 0) {
this.dataLength = this.Length(this.items);
this.initData(this.deepCopy(this.items), 1, null);
this.cloneColumns = this.makeColumns();
this.checkGroup = this.renderCheck(this.items);
if (this.checkGroup.length == this.dataLength) {
this.checks = true;
} else {
this.checks = false;
}
}
//this.initData();
},
methods: {
initData() {
},
slots() {
return this.$scopedSlots;
},
//拖拽开始
dragstart(e, index, row) {
this.dragIndex = index;
console.log(index);
},
//进入
dragenter(e, index, row) {
var tr = document.getElementById("tr" + index);
tr.className += " move";
// console.warn("进入",e, e.clientY,tr.clientTop, tr.className);
},
// 悬浮
dragover(e, index, row) {
// console.warn("悬浮",e)
e.preventDefault();
// 鼠标Y
var my = e.clientY;
var ty = e.toElement.offsetTop;
var h = e.toElement.clientHeight;
var tr = document.getElementById("tr" + index);
if (tr.className.indexOf(" sort") == -1 && 2.5 * h < my - ty) {
tr.className = tr.className.replace(" move", " sort");
}
// console.warn("在上边",my,ty,my-ty,h, tr.className);
this.logs.push({ index, ty, my, h });
},
// 离开
dragleave(e, index, row) {
var tr = document.getElementById("tr" + index);
tr.className = tr.className.replace(" move", "").replace(" sort", "");
console.warn(
"离开",
e.clientY,
e.toElement.offsetTop,
e.toElement.clientHeight,
tr.className
);
},
//放下
dragdrop(e, index, row) {
event.preventDefault();
var tr = document.getElementById("tr" + index);
tr.className = tr.className.replace(" move", "").replace(" sort", "");
if (index != this.dragIndex) {
this.$emit("on-drag-drop", this.dragIndex, index, this.trs);
}
console.log(JSON.stringify(this.logs));
},
/**
* @dragover="dragover($event, index, item)"
@dragleave="dragleave($event,index,item)"
*/
// 有无多选框折叠位置优化
iconRow() {
var num = 0;
for (let i = 0, len = this.columns.length; i < len; i++) {
if (this.columns[i].tree) {
num = i;
}
}
return num;
},
// 设置td宽度,td的align
tdStyle(column) {
const style = {};
if (column.align) {
style["text-align"] = column.align;
}
if (column.width) {
style["width"] = `${column.width}px`;
}
return style;
},
// 排序事件
handleSort(index, type) {
this.cloneColumns.forEach((col) => (col._sortType = "normal"));
if (this.cloneColumns[index]._sortType === type) {
this.cloneColumns[index]._sortType = "normal";
} else {
this.cloneColumns[index]._sortType = type;
}
this.$emit(
"on-sort-change",
this.cloneColumns[index].key,
this.cloneColumns[index]._sortType
);
},
// 点击某一行事件
RowClick(data, event, index, text) {
// this.iconName = true;
const result = this.makeData(data);
this.$emit("on-row-click", result, event, index, text);
},
//点击图标
RowClickIcon(event, index, text) {
this.$emit("on-icon-click", event, index, text);
},
// 点击事件 返回数据处理
makeData(data) {
const t = this.type(data);
let o;
if (t === "array") {
o = [];
} else if (t === "object") {
o = {};
} else {
return data;
}
if (t === "array") {
for (let i = 0; i < data.length; i++) {
o.push(this.makeData(data[i]));
}
} else if (t === "object") {
for (const i in data) {
if (
i != "spaceHtml" &&
i != "parent" &&
i != "level" &&
i != "expanded" &&
i != "isShow" &&
i != "load"
) {
o[i] = this.makeData(data[i]);
}
}
}
return o;
},
// 处理表头数据
makeColumns() {
const columns = this.deepCopy(this.columns);
this.tdsWidth = 0;
columns.forEach((column, index) => {
column._index = index;
column._width = column.width ? column.width : "";
column._sortType = "normal";
this.tdsWidth += column.width ? parseFloat(column.width) : 0;
});
return columns;
},
// 数据处理 增加自定义属性监听
initData(items, level, parent) {
// this.trs = []
let spaceHtml = "";
for (let i = 1; i < level; i++) {
spaceHtml += "<i class='ms-tree-space'></i>";
}
items.forEach((item, index) => {
item = Object.assign({}, item, {
parent,
level,
spaceHtml,
});
if (typeof item.expanded === "undefined") {
item = Object.assign({}, item, {
expanded: true,
});
}
if (typeof item.show === "undefined") {
item = Object.assign({}, item, {
isShow: true,
});
}
if (typeof item.isChecked === "undefined") {
item = Object.assign({}, item, {
isChecked: false,
});
}
item = Object.assign({}, item, {
load: !!item.expanded,
});
this.trs.push(item);
if (item.children && item.expanded) {
this.initData(item.children, level + 1, item);
}
items.splice(index, 1, item);
});
},
// 隐藏显示
show(item) {
return (
item.level == 1 || (item.parent && item.parent.expanded && item.isShow)
);
},
toggle(index, item) {
const level = item.level + 1;
let spaceHtml = "";
for (let i = 1; i < level; i++) {
spaceHtml += "<i class='ms-tree-space'></i>";
}
if (item.children) {
if (item.expanded) {
item.expanded = !item.expanded;
this.close(index, item);
} else {
item.expanded = !item.expanded;
if (item.load) {
this.open(index, item);
} else {
item.load = true;
item.children.forEach((child, childIndex) => {
this.trs.splice(index + childIndex + 1, 0, child);
// 设置监听属性
this.$set(this.trs[index + childIndex + 1], "parent", item);
this.$set(this.trs[index + childIndex + 1], "level", level);
this.$set(
this.trs[index + childIndex + 1],
"spaceHtml",
spaceHtml
);
this.$set(this.trs[index + childIndex + 1], "isShow", true);
this.$set(this.trs[index + childIndex + 1], "expanded", false);
});
}
}
}
},
open(index, item) {
if (item.children) {
item.children.forEach((child, childIndex) => {
child.isShow = true;
if (child.children && child.expanded) {
this.open(index + childIndex + 1, child);
}
});
}
},
close(index, item) {
if (item.children) {
item.children.forEach((child, childIndex) => {
child.isShow = false;
child.expanded = false;
if (child.children) {
this.close(index + childIndex + 1, child);
}
});
}
},
// 点击check勾选框,判断是否有children节点 如果有就一并勾选
handleCheckClick(data, event, index) {
data.isChecked = !data.isChecked;
const arr = data.children;
if (arr) {
if (data.isChecked) {
this.checkGroup.push(data.id);
for (let i = 0; i < arr.length; i++) {
this.checkGroup.push(arr[i].id);
}
} else {
for (let i = 0; i < this.checkGroup.length; i++) {
if (this.checkGroup[i] == data.id) {
this.checkGroup.splice(i, 1);
}
for (let j = 0; j < arr.length; j++) {
if (this.checkGroup[i] == arr[j].id) {
this.checkGroup.splice(i, 1);
}
}
}
}
}
},
// checkbox 全选 选择事件
handleCheckAll() {
this.checks = !this.checks;
if (this.checks) {
this.checkGroup = this.getArray(
this.checkGroup.concat(this.All(this.items))
);
} else {
this.checkGroup = [];
}
// this.$emit('on-selection-change', this.checkGroup)
},
// 数组去重
getArray(a) {
const hash = {};
const len = a.length;
const result = [];
for (let i = 0; i < len; i++) {
if (!hash[a[i]]) {
hash[a[i]] = true;
result.push(a[i]);
}
}
return result;
},
checkAllGroupChange(data) {
if (this.dataLength > 0 && data.length === this.dataLength) {
this.checks = true;
} else {
this.checks = false;
}
this.$emit("on-selection-change", this.checkGroup);
},
All(data) {
let arr = [];
data.forEach((item) => {
arr.push(item.id);
if (item.children && item.children.length > 0) {
arr = arr.concat(this.All(item.children));
}
});
return arr;
},
// 返回树形数据长度
Length(data) {
let { length } = data;
data.forEach((child) => {
if (child.children) {
length += this.Length(child.children);
}
});
return length;
},
// 返回表头
renderHeader(column, $index) {
if ("renderHeader" in this.columns[$index]) {
return this.columns[$index].renderHeader(column, $index);
}
return column.title || "#";
},
// 返回内容
renderBody(row, column, index) {
return row[column.key];
},
// 默认选中
renderCheck(data) {
let arr = [];
data.forEach((item) => {
if (item._checked) {
arr.push(item.id);
}
if (item.children && item.children.length > 0) {
arr = arr.concat(this.renderCheck(item.children));
}
});
return arr;
},
// 深度拷贝函数
deepCopy(data) {
const t = this.type(data);
let o;
let i;
let ni;
if (t === "array") {
o = [];
} else if (t === "object") {
o = {};
} else {
return data;
}
if (t === "array") {
for (i = 0, ni = data.length; i < ni; i++) {
o.push(this.deepCopy(data[i]));
}
return o;
}
if (t === "object") {
for (i in data) {
o[i] = this.deepCopy(data[i]);
}
return o;
}
},
type(obj) {
const { toString } = Object.prototype;
const map = {
"[object Boolean]": "boolean",
"[object Number]": "number",
"[object String]": "string",
"[object Function]": "function",
"[object Array]": "array",
"[object Date]": "date",
"[object RegExp]": "regExp",
"[object Undefined]": "undefined",
"[object Null]": "null",
"[object Object]": "object",
};
return map[toString.call(obj)];
},
},
beforeDestroy() {
window.onresize = null;
},
};
</script>
<style lang="less">
@import "../../../assets/css/custom.less";
.treeTbale {
overflow: 0 auto;
width: 100% !important;
.table-tools {
line-height: 40px;
background: @right-header-bg;
.table-search {
float: left;
line-height: 40px;
min-width: 300px;
}
.btns {
float: right;
line-height: 40px;
}
tr:hover {
background: #f7f7f7;
}
}
.icon-set {
font-size: 17px;
margin-left: 5px;
display: inline-block;
}
.icon-set .ivu-icon {
cursor: pointer;
}
table {
border-spacing: 0;
border-collapse: collapse;
margin: 0 auto;
width: 100%;
th {
background: #f8f8f9;
}
td,
th {
border: #dcdee2 solid 1px;
line-height: 40px;
padding: 0 5px;
}
tr.treetr:hover td {
background: #f7f7f7;
}
tr.move {
td {
background-color: blue;
}
}
tr.sort {
td {
border-top: 2px solid blue;
}
}
.ms-tree-space {
position: relative;
top: 1px;
display: inline-block;
font-style: normal;
font-weight: 400;
line-height: 1;
width: 14px;
height: 14px;
}
}
}
</style>
<template>
<div class="tree">
<TreeGrid :columns="columns" :items="treeData" :drag="true">
<EditGrid :columns="columns" :items="treeData" :drag="true">
<template slot-scope="{row,column,index}" slot="name">
<Icon type="md-folder" /> {{row.name}}
</template>
<template slot-scope="{row,column,index}" slot="action">
<strong>{{row.action}}</strong>
</template>
</TreeGrid>
</EditGrid>
<!-- <Input v-model="data" type="textarea" rows="20" placeholder=""></Input> -->
</div>
</template>
......
......@@ -53,6 +53,7 @@ import files from '@/components/page/files.vue'
import FilesList from '@/components/page/filesList.vue'
import DataGrid from '@/components/page/dataGrid.vue'
import TreeGrid from '@/components/page/treeGrid/index.vue'
import EditGrid from '@/components/page/treeGrid/editGrid.vue'
import Filed from '@/components/page/filed.vue'
import User from '@/components/page/user.vue'
import op from '@/components/page/opration.vue'
......@@ -114,6 +115,7 @@ Vue.component("files", files)
Vue.component("FilesList", FilesList)
Vue.component("DataGrid", DataGrid)
Vue.component("TreeGrid", TreeGrid)
Vue.component("EditGrid", EditGrid)
Vue.component("Filed", Filed)
Vue.component("UserSelect", UserSelect)
Vue.component("Materiel", Materiel)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment