|
|
@@ -0,0 +1,1478 @@
|
|
|
+<template>
|
|
|
+ <div class="wl-gantt" id="wl-gantt">
|
|
|
+ <!-- 甘特图区 -->
|
|
|
+ <el-table
|
|
|
+ ref="wl-gantt"
|
|
|
+ class="wl-gantt-table"
|
|
|
+ :fit="fit"
|
|
|
+ :size="size"
|
|
|
+ :load="load"
|
|
|
+ :lazy="lazy"
|
|
|
+ :border="border"
|
|
|
+ :data="selfData"
|
|
|
+ :stripe="stripe"
|
|
|
+ :height="height"
|
|
|
+ :row-key="rowKey"
|
|
|
+ :row-style="rowStyle"
|
|
|
+ :class="dateTypeClass"
|
|
|
+ :cell-style="cellStyle"
|
|
|
+ :max-height="maxHeight"
|
|
|
+ :tree-props="selfProps"
|
|
|
+ :current-row-key="rowKey"
|
|
|
+ :row-class-name="rowClassName"
|
|
|
+ :cell-class-name="cellClassName"
|
|
|
+ :expand-row-keys="expandRowKeys"
|
|
|
+ :header-row-style="headerRowStyle"
|
|
|
+ :header-cell-style="headerCellStyle"
|
|
|
+ :default-expand-all="defaultExpandAll"
|
|
|
+ :header-row-class-name="headerRowClassName"
|
|
|
+ :highlight-current-row="highlightCurrentRow"
|
|
|
+ :header-cell-class-name="headerCellClassName"
|
|
|
+ @header-contextmenu="handleHeaderContextMenu"
|
|
|
+ @selection-change="handleSelectionChange"
|
|
|
+ @row-contextmenu="handleRowContextMenu"
|
|
|
+ @contextmenu.native="handleContextmenu"
|
|
|
+ @current-change="handleCurrentChange"
|
|
|
+ @cell-mouse-enter="handleMouseEnter"
|
|
|
+ @cell-mouse-leave="handleMouseLeave"
|
|
|
+ @expand-change="handleExpandChange"
|
|
|
+ @filter-change="handleFilterChange"
|
|
|
+ @cell-dblclick="handleCellDbClick"
|
|
|
+ @header-click="handleHeaderClick"
|
|
|
+ @row-dblclick="handleRowDbClick"
|
|
|
+ @sort-change="handleSortChange"
|
|
|
+ @cell-click="handleCellClick"
|
|
|
+ @select-all="handleSelectAll"
|
|
|
+ @row-click="handleRowClick"
|
|
|
+ @select="handleSelect"
|
|
|
+ >
|
|
|
+ <template v-if="!ganttOnly">
|
|
|
+ <slot name="prv"></slot>
|
|
|
+ <el-table-column
|
|
|
+ v-if="useCheckColumn"
|
|
|
+ fixed
|
|
|
+ type="selection"
|
|
|
+ width="55"
|
|
|
+ align="center"
|
|
|
+ ></el-table-column>
|
|
|
+ <el-table-column v-if="useIndexColumn" fixed type="index" width="50" label="序号"></el-table-column>
|
|
|
+ <slot></slot>
|
|
|
+ </template>
|
|
|
+ <!-- year and mouth gantt -->
|
|
|
+ <template v-if="self_date_type === 'yearAndMonth'">
|
|
|
+ <el-table-column :resizable="false" v-for="year in ganttTitleDate" :label="year.name" :key="year.id">
|
|
|
+ <el-table-column
|
|
|
+ class-name="wl-gantt-item"
|
|
|
+ v-for="month in year.children"
|
|
|
+ :resizable="false"
|
|
|
+ :key="month.id"
|
|
|
+ :label="month.name"
|
|
|
+ >
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <div :class="dayGanttType(scope.row, month.full_date, 'months')"></div>
|
|
|
+ <div
|
|
|
+ v-if="useRealTime"
|
|
|
+ :class="realDayGanttType(scope.row, month.full_date, 'months')"
|
|
|
+ ></div>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table-column>
|
|
|
+ </template>
|
|
|
+ <!-- year and week gantt -->
|
|
|
+ <template v-else-if="self_date_type === 'yearAndWeek'">
|
|
|
+ <el-table-column :resizable="false" v-for="i in ganttTitleDate" :label="i.full_date" :key="i.id">
|
|
|
+ <el-table-column
|
|
|
+ class-name="wl-gantt-item"
|
|
|
+ v-for="t in i.children"
|
|
|
+ :resizable="false"
|
|
|
+ :key="t.id"
|
|
|
+ :label="t.name"
|
|
|
+ >
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <div :class="dayGanttType(scope.row, t.full_date, 'week')"></div>
|
|
|
+ <div v-if="useRealTime" :class="realDayGanttType(scope.row, t.full_date, 'week')"></div>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table-column>
|
|
|
+ </template>
|
|
|
+ <!-- mouth and day gantt -->
|
|
|
+ <template v-else>
|
|
|
+ <el-table-column :resizable="false" v-for="i in ganttTitleDate" :label="i.full_date" :key="i.id">
|
|
|
+ <el-table-column
|
|
|
+ class-name="wl-gantt-item"
|
|
|
+ v-for="t in i.children"
|
|
|
+ :resizable="false"
|
|
|
+ :key="t.id"
|
|
|
+ :label="t.name"
|
|
|
+ width="50"
|
|
|
+ >
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <div :class="dayGanttType(scope.row, t.full_date)"></div>
|
|
|
+ <div v-if="useRealTime" :class="realDayGanttType(scope.row, t.full_date)"></div>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table-column>
|
|
|
+ </template>
|
|
|
+ </el-table>
|
|
|
+ <!-- 组件区 -->
|
|
|
+ <!-- 右键菜单 -->
|
|
|
+ <context-menu
|
|
|
+ :visible.sync="contextMenu.show"
|
|
|
+ :x="contextMenu.x"
|
|
|
+ :y="contextMenu.y"
|
|
|
+ :menuList="contextMenu.data"
|
|
|
+ ></context-menu>
|
|
|
+ <!-- hover 看板 -->
|
|
|
+ <div v-show="infoCard.show" class="wl-info-card" :style="infoCardStyle">
|
|
|
+ <slot
|
|
|
+ name="info-card"
|
|
|
+ :row="infoCard.row"
|
|
|
+ :column="infoCard.column"
|
|
|
+ :cell="infoCard.cell"
|
|
|
+ :event="infoCard.event"
|
|
|
+ ></slot>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import dayjs from 'dayjs'; // 导入日期js
|
|
|
+const uuidv4 = require('uuid/v4'); // 导入uuid生成插件
|
|
|
+import isBetween from 'dayjs/plugin/isBetween';
|
|
|
+dayjs.extend(isBetween);
|
|
|
+import { flattenDeep, getMax, flattenDeepParents, regDeepParents } from 'wl-core'; // 导入数组操作函数
|
|
|
+import ContextMenu from './components/wl-contextmenu';
|
|
|
+
|
|
|
+export default {
|
|
|
+ name: 'WlGantt',
|
|
|
+ components: { ContextMenu },
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ self_start_date: '', // 项目开始时间
|
|
|
+ self_end_date: '', // 项目结束时间
|
|
|
+ self_data_list: [], // 一维化后的gantt数据
|
|
|
+ self_date_type: '', // 自身日期类型
|
|
|
+ self_id: 1, // 自增id
|
|
|
+ self_cell_edit: null, // 正在编辑的单元格
|
|
|
+ self_dependent_store: [], // 自身依赖库
|
|
|
+ multipleSelection: [], // 多选数据
|
|
|
+ currentRow: null, // 单选数据
|
|
|
+ pre_options: [], // 可选前置节点
|
|
|
+ name_show_tooltip: true, // 名称列是否开启超出隐藏
|
|
|
+ update: true, // 更新视图
|
|
|
+ selectionList: [], // 多选选中数据
|
|
|
+ contextMenu: {
|
|
|
+ show: false, // 显示
|
|
|
+ x: 0, // 坐标点
|
|
|
+ y: 0, // 坐标点
|
|
|
+ data: [] // 整理后要显示的数据
|
|
|
+ }, // 右键菜单配置项
|
|
|
+ infoCard: {
|
|
|
+ show: false,
|
|
|
+ x: 0,
|
|
|
+ y: 0,
|
|
|
+ row: {},
|
|
|
+ column: {},
|
|
|
+ cell: null,
|
|
|
+ event: {},
|
|
|
+ timer: null
|
|
|
+ } // 看板信息
|
|
|
+ };
|
|
|
+ },
|
|
|
+ props: {
|
|
|
+ useCard: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false
|
|
|
+ }, // 是否使用hover看板
|
|
|
+ /**
|
|
|
+ * @name 右键扩展菜单
|
|
|
+ * @param {String} label 展示名称
|
|
|
+ * @param {String} prop 绑定的字段
|
|
|
+ * @param {String} icon 可选 字体图标class
|
|
|
+ */
|
|
|
+ contextMenuOptions: Array,
|
|
|
+ // gantt数据
|
|
|
+ data: {
|
|
|
+ type: Array,
|
|
|
+ default: () => {
|
|
|
+ return [];
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 日期类型
|
|
|
+ dateType: {
|
|
|
+ type: String,
|
|
|
+ default: 'yearAndMonth' // monthAndDay,yearAndMonth,yearAndWeek
|
|
|
+ },
|
|
|
+ // 树表配置项
|
|
|
+ props: Object,
|
|
|
+ // 开始日期
|
|
|
+ startDate: {
|
|
|
+ type: [String, Object],
|
|
|
+ required: true
|
|
|
+ },
|
|
|
+ // 结束时间
|
|
|
+ endDate: {
|
|
|
+ type: [String, Object],
|
|
|
+ required: true
|
|
|
+ },
|
|
|
+ // 是否使用实际开始时间、实际结束时间
|
|
|
+ useRealTime: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false
|
|
|
+ },
|
|
|
+ // 是否检查源数据符合规则,默认开启,如果源数据已遵循project规则,可设置为false以提高性能
|
|
|
+ checkSource: {
|
|
|
+ type: Boolean,
|
|
|
+ default: true
|
|
|
+ },
|
|
|
+ // 废弃:反而会因为频繁的判断而影响性能
|
|
|
+ // 是否生成自增id并组成parents来满足树链的查询条件,如果数据本身已有自增id,可设置为false以提高性能
|
|
|
+ // 如果设置为false,则数据内必须包含自增id字段:identityId,parents字段必须以`,`分割。
|
|
|
+ // 字段名可通过props配置,自增id必须唯一并尽可能的短,如1,2,3...,parents应为祖先自增id通过`,`拼接直至父级
|
|
|
+ recordParents: {
|
|
|
+ type: Boolean,
|
|
|
+ default: true
|
|
|
+ },
|
|
|
+ // 是否使用id来作为自增id,如果是请保证id本来就简短的数字型而不是较长的字符串或guid
|
|
|
+ treatIdAsIdentityId: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false
|
|
|
+ },
|
|
|
+ // 自动变化gantt标题日期模式
|
|
|
+ autoGanttDateType: {
|
|
|
+ type: Boolean,
|
|
|
+ default: true
|
|
|
+ },
|
|
|
+ nameFormatter: Function, // 名称列的格式化内容函数
|
|
|
+ // 是否使用内置前置任务列
|
|
|
+ usePreColumn: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false
|
|
|
+ },
|
|
|
+ // 是否使用复选框列
|
|
|
+ useCheckColumn: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false
|
|
|
+ },
|
|
|
+ // 是否使用序号列
|
|
|
+ useIndexColumn: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false
|
|
|
+ },
|
|
|
+ // 是否可编辑
|
|
|
+ edit: {
|
|
|
+ type: Boolean,
|
|
|
+ default: true
|
|
|
+ },
|
|
|
+ // 复选框是否父子关联
|
|
|
+ parentChild: {
|
|
|
+ type: Boolean,
|
|
|
+ default: true
|
|
|
+ },
|
|
|
+ // 是否开启前置任务多选 如果开启多选则pre字段必须是Array,否则可以是Number\String
|
|
|
+ preMultiple: {
|
|
|
+ type: Boolean,
|
|
|
+ default: true
|
|
|
+ },
|
|
|
+ preFormatter: Function, // 前置任务列的格式化内容函数
|
|
|
+ // 空单元格占位符
|
|
|
+ emptyCellText: {
|
|
|
+ type: String,
|
|
|
+ default: '-'
|
|
|
+ },
|
|
|
+ // 多选时,是否可以点击行快速选中复选框
|
|
|
+ /* quickCheck: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false
|
|
|
+ }, */
|
|
|
+ ganttOnly: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false
|
|
|
+ }, // 是否只显示图形
|
|
|
+ // ---------------------------------------------以下为el-table Attributes--------------------------------------------
|
|
|
+ defaultExpandAll: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false
|
|
|
+ }, // 是否全部展开
|
|
|
+ rowKey: {
|
|
|
+ type: String,
|
|
|
+ default: 'id'
|
|
|
+ }, // 必须指定key来渲染树形数据
|
|
|
+ height: [String, Number], // 列表高度
|
|
|
+ maxHeight: [String, Number], // 列表最大高度
|
|
|
+ stripe: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false
|
|
|
+ }, // 是否为斑马纹
|
|
|
+ highlightCurrentRow: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false
|
|
|
+ }, // 是否要高亮当前行
|
|
|
+ border: {
|
|
|
+ type: Boolean,
|
|
|
+ default: true
|
|
|
+ }, // 是否带有纵向边框
|
|
|
+ fit: {
|
|
|
+ type: Boolean,
|
|
|
+ default: true
|
|
|
+ }, // 列的宽度是否自撑开
|
|
|
+ size: String, // Table 的尺寸
|
|
|
+ rowClassName: Function, // 行的 className 的回调方法
|
|
|
+ rowStyle: Function, // 行的 style 的回调方法
|
|
|
+ cellClassName: Function, // 单元格的 className 的回调方法
|
|
|
+ cellStyle: Function, // 单元格的 style 的回调方法
|
|
|
+ headerRowClassName: {
|
|
|
+ type: [Function, String],
|
|
|
+ default: 'wl-gantt-header'
|
|
|
+ }, // 表头行的 className 的回调方法
|
|
|
+ headerRowStyle: [Function, Object], // 表头行的 style 的回调方法
|
|
|
+ headerCellClassName: [Function, String], // 表头单元格的 className 的回调方法
|
|
|
+ headerCellStyle: [Function, Object], // 表头单元格的 style 的回调方法
|
|
|
+ expandRowKeys: Array, // 可以通过该属性设置 Table 目前的展开行
|
|
|
+ lazy: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false
|
|
|
+ }, // 是否懒加载子节点数据
|
|
|
+ load: Function // 加载子节点数据的函数,lazy 为 true 时生效
|
|
|
+ // 是否使用一维数据组成树
|
|
|
+ /* arrayToTree: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false
|
|
|
+ } */
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ // 甘特图标题日期分配
|
|
|
+ ganttTitleDate() {
|
|
|
+ // 分解开始和结束日期
|
|
|
+ let start_date_spilt = dayjs(this.self_start_date)
|
|
|
+ .format('YYYY-M-D')
|
|
|
+ .split('-');
|
|
|
+ let end_date_spilt = dayjs(this.self_end_date)
|
|
|
+ .format('YYYY-M-D')
|
|
|
+ .split('-');
|
|
|
+ let start_year = Number(start_date_spilt[0]);
|
|
|
+ let start_mouth = Number(start_date_spilt[1]);
|
|
|
+ let end_year = Number(end_date_spilt[0]);
|
|
|
+ let end_mouth = Number(end_date_spilt[1]);
|
|
|
+ // 自动更新日期类型以适应任务时间范围跨度
|
|
|
+ if (this.autoGanttDateType) {
|
|
|
+ // 计算日期跨度
|
|
|
+ let mouth_diff = this.timeDiffTime(this.self_start_date, this.self_end_date, 'months');
|
|
|
+ if (mouth_diff > 12) {
|
|
|
+ // 12个月以上的分到yearAndMouth
|
|
|
+ this.setDataType('yearAndMonth');
|
|
|
+ } else if (mouth_diff > 2) {
|
|
|
+ // 2个月以上的分到yearAndWeek
|
|
|
+ this.setDataType('yearAndWeek');
|
|
|
+ } else {
|
|
|
+ this.setDataType('monthAndDay');
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 不自动更新日期类型,以dateType固定展示
|
|
|
+ if (this.self_date_type === 'yearAndWeek') {
|
|
|
+ return this.yearAndWeekTitleDate(start_year, start_mouth, end_year, end_mouth);
|
|
|
+ } else if (this.self_date_type === 'monthAndDay') {
|
|
|
+ return this.mouthAndDayTitleDate(start_year, start_mouth, end_year, end_mouth);
|
|
|
+ } else {
|
|
|
+ return this.yearAndMouthTitleDate(start_year, start_mouth, end_year, end_mouth);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 数据
|
|
|
+ selfData() {
|
|
|
+ let _data = this.data || [];
|
|
|
+ // 生成一维数据
|
|
|
+ this.setListData();
|
|
|
+ // 处理源数据合法性
|
|
|
+ this.handleData(_data);
|
|
|
+ // 处理前置依赖
|
|
|
+ this.handleDependentStore();
|
|
|
+ return _data;
|
|
|
+ },
|
|
|
+ // 树表配置项
|
|
|
+ selfProps() {
|
|
|
+ return {
|
|
|
+ hasChildren: 'hasChildren', // 字段来指定哪些行是包含子节点
|
|
|
+ children: 'children', // children字段来表示有子节点
|
|
|
+ name: 'name', // 任务名称字段
|
|
|
+ id: 'id', // id字段
|
|
|
+ pid: 'pid', // pid字段
|
|
|
+ startDate: 'startDate', // 开始时间字段
|
|
|
+ realStartDate: 'realStartDate', // 实际开始时间字段
|
|
|
+ endDate: 'endDate', // 结束时间字段
|
|
|
+ realEndDate: 'realEndDate', // 实际结束时间字段
|
|
|
+ identityId: 'identityId',
|
|
|
+ parents: 'parents',
|
|
|
+ pre: 'pre', // 前置任务字段【注意:如果使用recordParents,则pre值应是目标对象的identityId字段(可配置)】
|
|
|
+ ...this.props
|
|
|
+ };
|
|
|
+ },
|
|
|
+ // 根据日期类型改样式
|
|
|
+ dateTypeClass() {
|
|
|
+ if (this.self_date_type === 'yearAndMonth') {
|
|
|
+ return 'year-and-month';
|
|
|
+ } else if (this.self_date_type === 'monthAndDay') {
|
|
|
+ return 'month-and-day';
|
|
|
+ } else if (this.self_date_type === 'yearAndWeek') {
|
|
|
+ return 'year-and-week';
|
|
|
+ }
|
|
|
+ return '';
|
|
|
+ },
|
|
|
+ // 看板样式
|
|
|
+ infoCardStyle() {
|
|
|
+ return {
|
|
|
+ left: this.infoCard.x + 'px',
|
|
|
+ top: this.infoCard.y + 'px'
|
|
|
+ };
|
|
|
+ }
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ // 设置dateType
|
|
|
+ setDataType(type) {
|
|
|
+ this.self_date_type = type;
|
|
|
+ },
|
|
|
+ // 生成一维数据
|
|
|
+ setListData() {
|
|
|
+ this.self_data_list = flattenDeep(this.data, this.selfProps.children);
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 开始时间改变
|
|
|
+ * row: object 当前行数据
|
|
|
+ */
|
|
|
+ startDateChange(row) {
|
|
|
+ // 如果将开始时间后移,结束时间也应后移
|
|
|
+ let _delay = this.timeIsBefore(row._oldStartDate, row[this.selfProps.startDate]);
|
|
|
+ if (_delay) {
|
|
|
+ row[this.selfProps.endDate] = this.timeAdd(row[this.selfProps.endDate], row._cycle);
|
|
|
+ }
|
|
|
+ // 如果开始早于项目开始,则把项目开始提前
|
|
|
+ let _early_project_start = this.timeIsBefore(row[this.selfProps.startDate], this.self_start_date);
|
|
|
+ if (_early_project_start) {
|
|
|
+ this.self_start_date = row[this.selfProps.startDate];
|
|
|
+ }
|
|
|
+ this.emitTimeChange(row);
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 结束时间改变
|
|
|
+ * row: object 当前行数据
|
|
|
+ */
|
|
|
+ endDateChange(row) {
|
|
|
+ this.emitTimeChange(row);
|
|
|
+ // 如果开始晚于结束,提示
|
|
|
+ /* if (
|
|
|
+ this.timeIsBefore(
|
|
|
+ row[this.selfProps.endDate],
|
|
|
+ row[this.selfProps.startDate]
|
|
|
+ )
|
|
|
+ ) {
|
|
|
+ row[this.selfProps.startDate] = row._oldStartDate;
|
|
|
+ this.$message({
|
|
|
+ showClose: true,
|
|
|
+ message: "开始时间不可以晚于结束时间",
|
|
|
+ type: "error"
|
|
|
+ });
|
|
|
+ return;
|
|
|
+ } */
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 前置任务改变
|
|
|
+ * row: object 当前行数据
|
|
|
+ */
|
|
|
+ preChange(row) {
|
|
|
+ this.emitTimeChange(row);
|
|
|
+ this.self_cell_edit = null;
|
|
|
+ // 如果开始晚于结束,提示
|
|
|
+ /* if (
|
|
|
+ this.timeIsBefore(
|
|
|
+ row[this.selfProps.endDate],
|
|
|
+ row[this.selfProps.startDate]
|
|
|
+ )
|
|
|
+ ) {
|
|
|
+ row[this.selfProps.startDate] = row._oldStartDate;
|
|
|
+ this.$message({
|
|
|
+ showClose: true,
|
|
|
+ message: "开始时间不可以晚于结束时间",
|
|
|
+ type: "error"
|
|
|
+ });
|
|
|
+ return;
|
|
|
+ } */
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 前置任务内容格式化函数
|
|
|
+ * data:[String, Array] 前置任务
|
|
|
+ */
|
|
|
+ preFormat(row) {
|
|
|
+ // 自定义格式化前置任务列函数
|
|
|
+ if (this.preFormatter) {
|
|
|
+ return this.preFormatter(row);
|
|
|
+ }
|
|
|
+ let data = row[this.selfProps.pre];
|
|
|
+ if (!data) return this.emptyCellText;
|
|
|
+ if (Array.isArray(data)) {
|
|
|
+ if (data.length === 0) return this.emptyCellText;
|
|
|
+ let _pre_text = '';
|
|
|
+ data.forEach(i => {
|
|
|
+ let _act = this.self_data_list.find(t => t[this.selfProps.id] === i);
|
|
|
+ if (_act) _pre_text += `${_act[this.selfProps.name]},`;
|
|
|
+ });
|
|
|
+ return _pre_text;
|
|
|
+ }
|
|
|
+ let _act = this.self_data_list.find(t => t[this.selfProps.id] === data);
|
|
|
+ return _act ? _act[this.selfProps.name] : this.emptyCellText;
|
|
|
+ },
|
|
|
+ // 前置下拉框失去焦点事件,change会触发blur,如果不延时则chang失效,如果延时则也只是延迟触发,会造成选一次就关闭无法多选
|
|
|
+ /* preEditBlur(){
|
|
|
+ setTimeout(()=>{
|
|
|
+ this.self_cell_edit = null
|
|
|
+ },500)
|
|
|
+ }, */
|
|
|
+ /**
|
|
|
+ * 前置任务编辑
|
|
|
+ */
|
|
|
+ preCellEdit(row, key, ref) {
|
|
|
+ /* let _parents = row._parents.split(","); // 父祖节点不可选
|
|
|
+ let _children = row._all_children.map(i => i._identityId); // 子孙节点不可选
|
|
|
+ let _self = row[this.selfProps.id]; // 自己不可选
|
|
|
+ let _parents_and_children = _children.concat(_parents, [_self]);
|
|
|
+ let filter_options = this.self_data_list.filter(
|
|
|
+ i => !_parents_and_children.some(t => t == i._identityId)
|
|
|
+ );
|
|
|
+ this.pre_options = filter_options; */
|
|
|
+ if (!this.edit) return;
|
|
|
+ this.pre_options = [];
|
|
|
+ this.self_data_list.forEach(i => {
|
|
|
+ if (i[this.selfProps.id] !== row[this.selfProps.id]) {
|
|
|
+ this.pre_options.push({ ...i, [this.selfProps.children]: null });
|
|
|
+ }
|
|
|
+ });
|
|
|
+ // 再剔除所有前置链涉及到的节点
|
|
|
+ this.deepFindToSelf(row);
|
|
|
+ // 调用单元格编辑
|
|
|
+ this.cellEdit(key, ref);
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 找出to为当前元素的form,并将form作为to继续查找
|
|
|
+ * item: Object 当前元素
|
|
|
+ * targets: Array 需要过滤的数据(废弃)
|
|
|
+ */
|
|
|
+ deepFindToSelf(item) {
|
|
|
+ let _parents = item._parents.split(','); // 父祖节点不可选
|
|
|
+ let _children = item._all_children.map(i => i._identityId); // 子孙节点不可选
|
|
|
+ let _parents_and_children = _children.concat(_parents);
|
|
|
+ this.pre_options = this.pre_options.filter(i => !_parents_and_children.some(t => t == i._identityId));
|
|
|
+ this.self_dependent_store.forEach(i => {
|
|
|
+ let _tag = this.preMultiple
|
|
|
+ ? i.to.some(t => t[this.selfProps.id] === item[this.selfProps.id])
|
|
|
+ : i.to[this.selfProps.id] === item[this.selfProps.id];
|
|
|
+ if (_tag) {
|
|
|
+ this.pre_options = this.pre_options.filter(t => t[this.selfProps.id] !== i.form[this.selfProps.id]);
|
|
|
+ this.deepFindToSelf(i.form);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 单元格编辑
|
|
|
+ * key: string 需要操作的单元格key
|
|
|
+ * ref:object 需要获取焦点的dom
|
|
|
+ */
|
|
|
+ cellEdit(key, ref) {
|
|
|
+ if (!this.edit) return;
|
|
|
+ if (ref === 'wl-name') {
|
|
|
+ this.name_show_tooltip = false;
|
|
|
+ }
|
|
|
+ this.self_cell_edit = key;
|
|
|
+ this.$nextTick(() => {
|
|
|
+ this.$refs[ref].focus();
|
|
|
+ });
|
|
|
+ },
|
|
|
+ // 名称编辑事件
|
|
|
+ nameChange(row) {
|
|
|
+ this.self_cell_edit = null;
|
|
|
+ this.name_show_tooltip = true;
|
|
|
+ this.emitNameChange(row);
|
|
|
+ },
|
|
|
+ // 名称列编辑输入框blur事件
|
|
|
+ nameBlur() {
|
|
|
+ this.self_cell_edit = null;
|
|
|
+ this.name_show_tooltip = true;
|
|
|
+ },
|
|
|
+ // 以下是表格-日期-gantt生成函数----------------------------------------生成gantt表格-------------------------------------
|
|
|
+ /**
|
|
|
+ * 年-月模式gantt标题
|
|
|
+ * start_year: 起始年
|
|
|
+ * start_mouth:起始月
|
|
|
+ * end_year:结束年
|
|
|
+ * end_mouth:结束月
|
|
|
+ */
|
|
|
+ yearAndMouthTitleDate(start_year, start_mouth, end_year, end_mouth) {
|
|
|
+ // 日期数据盒子
|
|
|
+ let dates = [
|
|
|
+ {
|
|
|
+ name: `${start_year}年`,
|
|
|
+ date: start_year,
|
|
|
+ id: uuidv4(),
|
|
|
+ children: []
|
|
|
+ }
|
|
|
+ ];
|
|
|
+ // 处理年份
|
|
|
+ let year_diff = end_year - start_year;
|
|
|
+ // 年间隔小于一年
|
|
|
+ if (year_diff === 0) {
|
|
|
+ let isLeap = this.isLeap(start_year); // 是否闰年
|
|
|
+ let mouths = this.generationMonths(start_year, start_mouth, end_mouth + 1, isLeap, false); // 处理月份
|
|
|
+ dates[0].children = mouths;
|
|
|
+ return dates;
|
|
|
+ }
|
|
|
+ // 处理开始月份
|
|
|
+ let startIsLeap = this.isLeap(start_year);
|
|
|
+ let start_mouths = this.generationMonths(start_year, start_mouth, 13, startIsLeap, false);
|
|
|
+ // 处理结束月份
|
|
|
+ let endIsLeap = this.isLeap(end_year);
|
|
|
+ let end_mouths = this.generationMonths(end_year, 1, end_mouth + 1, endIsLeap, false);
|
|
|
+ // 年间隔等于一年
|
|
|
+ if (year_diff === 1) {
|
|
|
+ dates[0].children = start_mouths;
|
|
|
+ dates.push({
|
|
|
+ name: `${end_year}年`,
|
|
|
+ date: end_year,
|
|
|
+ children: end_mouths,
|
|
|
+ id: uuidv4()
|
|
|
+ });
|
|
|
+ return dates;
|
|
|
+ }
|
|
|
+ // 年间隔大于1年
|
|
|
+ if (year_diff > 1) {
|
|
|
+ dates[0].children = start_mouths;
|
|
|
+ for (let i = 1; i < year_diff; i++) {
|
|
|
+ let item_year = start_year + i;
|
|
|
+ let isLeap = this.isLeap(item_year);
|
|
|
+ let month_and_day = this.generationMonths(item_year, 1, 13, isLeap, false);
|
|
|
+ dates.push({
|
|
|
+ name: `${item_year}年`,
|
|
|
+ date: item_year,
|
|
|
+ id: uuidv4(),
|
|
|
+ children: month_and_day
|
|
|
+ });
|
|
|
+ }
|
|
|
+ dates.push({
|
|
|
+ name: `${end_year}年`,
|
|
|
+ date: end_year,
|
|
|
+ children: end_mouths,
|
|
|
+ id: uuidv4()
|
|
|
+ });
|
|
|
+ return dates;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 年-周模式gantt标题
|
|
|
+ * start_year: 起始年
|
|
|
+ * start_mouth:起始月
|
|
|
+ * end_year:结束年
|
|
|
+ * end_mouth:结束月
|
|
|
+ */
|
|
|
+ yearAndWeekTitleDate(start_year, start_mouth, end_year, end_mouth) {
|
|
|
+ // 处理年份
|
|
|
+ let year_diff = end_year - start_year;
|
|
|
+ // 只存在同年或前后年的情况
|
|
|
+ if (year_diff === 0) {
|
|
|
+ // 年间隔为同一年
|
|
|
+ let isLeap = this.isLeap(start_year); // 是否闰年
|
|
|
+ let mouths = this.generationMonths(start_year, start_mouth, end_mouth + 1, isLeap, true, true); // 处理月份
|
|
|
+ return mouths;
|
|
|
+ }
|
|
|
+ // 处理开始月份
|
|
|
+ let startIsLeap = this.isLeap(start_year);
|
|
|
+ let start_mouths = this.generationMonths(start_year, start_mouth, 13, startIsLeap, true, true);
|
|
|
+ // 处理结束月份
|
|
|
+ let endIsLeap = this.isLeap(end_year);
|
|
|
+ let end_mouths = this.generationMonths(end_year, 1, end_mouth + 1, endIsLeap, true, true);
|
|
|
+ return start_mouths.concat(end_mouths);
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 月-日模式gantt标题
|
|
|
+ * start_year: 起始年
|
|
|
+ * start_mouth:起始月
|
|
|
+ * end_year:结束年
|
|
|
+ * end_mouth:结束月
|
|
|
+ */
|
|
|
+ mouthAndDayTitleDate(start_year, start_mouth, end_year, end_mouth) {
|
|
|
+ // 处理年份
|
|
|
+ let year_diff = end_year - start_year;
|
|
|
+ // 只存在同年或前后年的情况
|
|
|
+ if (year_diff === 0) {
|
|
|
+ // 年间隔为同一年
|
|
|
+ let isLeap = this.isLeap(start_year); // 是否闰年
|
|
|
+ let mouths = this.generationMonths(start_year, start_mouth, end_mouth + 1, isLeap); // 处理月份
|
|
|
+ return mouths;
|
|
|
+ }
|
|
|
+ // 处理开始月份
|
|
|
+ let startIsLeap = this.isLeap(start_year);
|
|
|
+ let start_mouths = this.generationMonths(start_year, start_mouth, 13, startIsLeap);
|
|
|
+ // 处理结束月份
|
|
|
+ let endIsLeap = this.isLeap(end_year);
|
|
|
+ let end_mouths = this.generationMonths(end_year, 1, end_mouth + 1, endIsLeap);
|
|
|
+ return start_mouths.concat(end_mouths);
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 生成月份函数
|
|
|
+ * year: Number 当前年份
|
|
|
+ * start_num: Number 开始月分
|
|
|
+ * end_num:Number 结束月份
|
|
|
+ * isLeap: Boolean 是否闰年
|
|
|
+ * insert_days: Boolean 是否需要插入 日
|
|
|
+ * week: 是否以周的间隔
|
|
|
+ */
|
|
|
+ generationMonths(year, start_num = 1, end_num = 13, isLeap = false, insert_days = true, week = false) {
|
|
|
+ let months = [];
|
|
|
+ if (insert_days) {
|
|
|
+ // 无需 日 的模式
|
|
|
+ for (let i = start_num; i < end_num; i++) {
|
|
|
+ // 需要 日 的模式
|
|
|
+ let days = this.generationDays(year, i, isLeap, week);
|
|
|
+ months.push({
|
|
|
+ name: `${i}月`,
|
|
|
+ date: i,
|
|
|
+ full_date: `${year}-${i}`,
|
|
|
+ children: days,
|
|
|
+ id: uuidv4()
|
|
|
+ });
|
|
|
+ }
|
|
|
+ return months;
|
|
|
+ }
|
|
|
+ for (let i = start_num; i < end_num; i++) {
|
|
|
+ // 需要 日 的模式
|
|
|
+ months.push({
|
|
|
+ name: `${i}月`,
|
|
|
+ date: i,
|
|
|
+ full_date: `${year}-${i}`,
|
|
|
+ id: uuidv4()
|
|
|
+ });
|
|
|
+ }
|
|
|
+ return months;
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 生成日期函数
|
|
|
+ * year: Number 当前年份
|
|
|
+ * month: Number 当前月份
|
|
|
+ * isLeap: Boolean 是否闰年
|
|
|
+ * week: Boolean 是否间隔一周
|
|
|
+ */
|
|
|
+ generationDays(year, month, isLeap = false, week = false) {
|
|
|
+ let big_month = [1, 3, 5, 7, 8, 10, 12].includes(month);
|
|
|
+ let small_month = [4, 6, 9, 11].includes(month);
|
|
|
+ let dates_num = big_month ? 32 : small_month ? 31 : isLeap ? 30 : 29;
|
|
|
+ let days = [];
|
|
|
+ if (week) {
|
|
|
+ let _day = 1; // 从周日开始
|
|
|
+ let _start_day_inweek = this.timeInWeek(`${year}-${month}-1`);
|
|
|
+ if (_start_day_inweek !== 0) {
|
|
|
+ _day = 8 - _start_day_inweek;
|
|
|
+ }
|
|
|
+ for (let i = _day; i < dates_num; i += 7) {
|
|
|
+ days.push({
|
|
|
+ date: i,
|
|
|
+ name: `${i}日`,
|
|
|
+ id: uuidv4(),
|
|
|
+ full_date: `${year}-${month}-${i}`
|
|
|
+ });
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ for (let i = 1; i < dates_num; i++) {
|
|
|
+ days.push({
|
|
|
+ date: i,
|
|
|
+ name: `${i}日`,
|
|
|
+ id: uuidv4(),
|
|
|
+ full_date: `${year}-${month}-${i}`
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return days;
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 是否闰年函数
|
|
|
+ * year: Number 当前年份
|
|
|
+ */
|
|
|
+ isLeap(year) {
|
|
|
+ return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 当前日期gantt状态
|
|
|
+ * row: object 当前行信息
|
|
|
+ * date: string 当前格子日期
|
|
|
+ * unit: string 时间单位,以天、月、年计算
|
|
|
+ */
|
|
|
+ dayGanttType(row, date, unit = 'days') {
|
|
|
+ let start_date = row[this.selfProps.startDate];
|
|
|
+ let end_date = row[this.selfProps.endDate];
|
|
|
+ let between = dayjs(date).isBetween(start_date, end_date, unit);
|
|
|
+ if (between) {
|
|
|
+ return 'wl-item-on';
|
|
|
+ }
|
|
|
+ let start = dayjs(start_date).isSame(date, unit);
|
|
|
+ let end = dayjs(end_date).isSame(date, unit);
|
|
|
+ if (start && end) {
|
|
|
+ return 'wl-item-on wl-item-full';
|
|
|
+ }
|
|
|
+ if (start) {
|
|
|
+ return 'wl-item-on wl-item-start';
|
|
|
+ }
|
|
|
+ if (end) {
|
|
|
+ return 'wl-item-on wl-item-end';
|
|
|
+ }
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 实际日期gantt状态
|
|
|
+ * row: object 当前行信息
|
|
|
+ * date: string 当前格子日期
|
|
|
+ * unit: string 时间单位,以天、月、年计算
|
|
|
+ */
|
|
|
+ realDayGanttType(row, date, unit = 'days') {
|
|
|
+ let start_date = row[this.selfProps.realStartDate];
|
|
|
+ let end_date = row[this.selfProps.realEndDate];
|
|
|
+ if (!start_date || !end_date) {
|
|
|
+ return '';
|
|
|
+ }
|
|
|
+ let between = dayjs(date).isBetween(start_date, end_date, unit);
|
|
|
+ if (between) {
|
|
|
+ return 'wl-real-on';
|
|
|
+ }
|
|
|
+ let start = dayjs(start_date).isSame(date, unit);
|
|
|
+ let end = dayjs(end_date).isSame(date, unit);
|
|
|
+ if (start && end) {
|
|
|
+ return 'wl-real-on wl-real-full';
|
|
|
+ }
|
|
|
+ if (start) {
|
|
|
+ return 'wl-real-on wl-real-start';
|
|
|
+ }
|
|
|
+ if (end) {
|
|
|
+ return 'wl-real-on wl-real-end';
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 以下是时间计算类函数 ------------------------------------------------------时间计算---------------------------------------
|
|
|
+ /**
|
|
|
+ * 计算时差
|
|
|
+ * startDate:开始时间
|
|
|
+ * endDate:结束时间
|
|
|
+ * unit:单位 days、months、yesrs
|
|
|
+ */
|
|
|
+ timeDiffTime(startDate, endDate, unit = 'days') {
|
|
|
+ return dayjs(endDate).diff(startDate, unit);
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 比较时间,是否之前
|
|
|
+ * startDate:开始时间
|
|
|
+ * endDate:结束时间
|
|
|
+ * unit:单位 days、months、yesrs
|
|
|
+ */
|
|
|
+ timeIsBefore(startDate, endDate, unit = 'days') {
|
|
|
+ return dayjs(startDate).isBefore(endDate, unit);
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 时间加计算函数
|
|
|
+ * date:原时间
|
|
|
+ * num:需要增加的时间数量
|
|
|
+ * nuit:增加时间的单位 day year
|
|
|
+ */
|
|
|
+ timeAdd(date, num = 1, nuit = 'day', format = 'YYYY-MM-DD') {
|
|
|
+ return dayjs(date)
|
|
|
+ .add(num, nuit)
|
|
|
+ .format(format);
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 时间格式化函数
|
|
|
+ * date 需要格式化的数据
|
|
|
+ * format 格式化的格式
|
|
|
+ */
|
|
|
+ timeFormat(date, format = 'YYYY-MM-DD') {
|
|
|
+ return date ? dayjs(date).format(format) : this.emptyCellText;
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 查询时间是周几
|
|
|
+ */
|
|
|
+ timeInWeek(date) {
|
|
|
+ return dayjs(date).day();
|
|
|
+ },
|
|
|
+ // 以下为输出数据函数 --------------------------------------------------------------输出数据------------------------------------
|
|
|
+ // 删除任务
|
|
|
+ emitTaskRemove(item) {
|
|
|
+ this.$emit('taskRemove', item);
|
|
|
+ },
|
|
|
+ // 添加任务
|
|
|
+ emitTaskAdd(item) {
|
|
|
+ this.$emit('taskAdd', item);
|
|
|
+ },
|
|
|
+ // 任务名称更改
|
|
|
+ emitNameChange(item) {
|
|
|
+ this.$emit('nameChange', item);
|
|
|
+ },
|
|
|
+ // 任务时间更改
|
|
|
+ emitTimeChange(item) {
|
|
|
+ this.$emit('timeChange', item);
|
|
|
+ this.$nextTick(() => {
|
|
|
+ this.$set(item, '_oldStartDate', item[this.selfProps.startDate]);
|
|
|
+ this.$set(item, '_oldEndDate', item[this.selfProps.endDate]);
|
|
|
+ });
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 前置任务更改
|
|
|
+ * item: Object 发生更改的行数据
|
|
|
+ * oldval: [String, Array] 修改前数据
|
|
|
+ * handle: Boolean true为操作选择框修改 false为源数据不符合规范的修正更改
|
|
|
+ */
|
|
|
+ emitPreChange(item, oldval, handle = false) {
|
|
|
+ this.$emit('preChange', item, oldval, handle);
|
|
|
+ },
|
|
|
+ // 处理外部数据 ---------------------------------------------------------------原始数据处理-------------------------------------
|
|
|
+ handleData(data, parent = null, level = 0) {
|
|
|
+ level++;
|
|
|
+ data.forEach(i => {
|
|
|
+ this.$set(i, '_parent', parent); // 添加父级字段
|
|
|
+ this.$set(i, '_level', level); // 添加层级字段
|
|
|
+ if (!i._oldStartDate) {
|
|
|
+ this.$set(i, '_oldStartDate', i[this.selfProps.startDate]);
|
|
|
+ }
|
|
|
+ if (!i._oldEndDate) {
|
|
|
+ this.$set(i, '_oldEndDate', i[this.selfProps.endDate]);
|
|
|
+ }
|
|
|
+ // 当结束时间早于开始时间时,自动处理结束时间为开始时间延后一天
|
|
|
+ let _end_early_start = this.timeIsBefore(i[this.selfProps.endDate], i[this.selfProps.startDate]);
|
|
|
+ if (_end_early_start) {
|
|
|
+ this.$set(i, this.selfProps.endDate, i[this.selfProps.startDate]);
|
|
|
+ this.$set(i, '_cycle', 1); // 添加工期字段
|
|
|
+ this.emitTimeChange(i); // 将发生时间更新的数据输出
|
|
|
+ } else {
|
|
|
+ let _time_diff = this.timeDiffTime(i[this.selfProps.startDate], i[this.selfProps.endDate]);
|
|
|
+ this.$set(i, '_cycle', _time_diff + 1); // 添加工期字段
|
|
|
+ } // 添加工期字段
|
|
|
+ // 添加自增id字段及树链组成的parents字段
|
|
|
+ this.recordIdentityIdAndParents(i);
|
|
|
+ // 处理前置任务
|
|
|
+ // this.handlePreTask(i);
|
|
|
+ // 如果当前节点的开始时间早于父节点的开始时间,则将开始时间与父节点相同
|
|
|
+ this.parentStartDateToChild(i);
|
|
|
+ // 校验结束时间是否晚于子节点,如不则将节点结束时间改为最晚子节点
|
|
|
+ this.childEndDateToParent(i);
|
|
|
+ if (Array.isArray(i[this.selfProps.children])) {
|
|
|
+ this.$set(i, '_isLeaf', false); // 添加是否叶子节点字段
|
|
|
+ let _all_children = flattenDeep(i[this.selfProps.children], this.selfProps.children);
|
|
|
+ this.$set(i, '_all_children', _all_children); // 添加全部子节点字段
|
|
|
+ this.handleData(i[this.selfProps.children], i, level);
|
|
|
+ } else {
|
|
|
+ this.$set(i, '_isLeaf', true); // 添加是否叶子节点字段
|
|
|
+ this.$set(i, '_all_children', []); // 添加全部子节点字段
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+ // 取父节点开始时间给早于父节点开始时间的子节点
|
|
|
+ parentStartDateToChild(item) {
|
|
|
+ if (!item._parent) return;
|
|
|
+ // 如果子节点时间早于父节点,则将子节点开始时间后移至父节点开始时间,并将结束时间平移【即工期不变】
|
|
|
+ let _child_early_parent = this.timeIsBefore(
|
|
|
+ item[this.selfProps.startDate],
|
|
|
+ item._parent[this.selfProps.startDate]
|
|
|
+ );
|
|
|
+ if (_child_early_parent) {
|
|
|
+ // 修正子节点开始时间
|
|
|
+ this.$set(item, this.selfProps.startDate, item._parent[this.selfProps.startDate]);
|
|
|
+ // 修正子节点结束时间
|
|
|
+ let _to_endDate = this.timeAdd(item[this.selfProps.startDate], item._cycle);
|
|
|
+ this.$set(item, this.selfProps.endDate, _to_endDate);
|
|
|
+ this.emitTimeChange(item); // 将发生时间更新的数据输出
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 取数组结束时间最大值,如果最大值比父级结束时间大,更新父级结束时间
|
|
|
+ childEndDateToParent(item) {
|
|
|
+ if (!Array.isArray(item[this.selfProps.children])) return;
|
|
|
+ let _child_max = getMax(item[this.selfProps.children], this.selfProps.endDate, true); // 取子节点中最晚的结束时间
|
|
|
+ let _parent_end = dayjs(item[this.selfProps.endDate]).valueOf();
|
|
|
+ if (_child_max > _parent_end) {
|
|
|
+ // 如果子节点结束时间比父节点晚,则将父节点结束时间退后
|
|
|
+ this.$set(item, this.selfProps.endDate, this.timeFormat(_child_max));
|
|
|
+ this.emitTimeChange(item); // 将发生时间更新的数据输出
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 处理前置任务节点 /// ---- 此使前置任务校验处理还没开始,因此出错,前置处理后手动调用vue视图更新试试
|
|
|
+ handlePreTask(item) {
|
|
|
+ // 统一在一维化数据中处理前置任务
|
|
|
+ let _pre_target = this.self_dependent_store.find(
|
|
|
+ i => i.form[this.selfProps.id] === item[this.selfProps.id]
|
|
|
+ );
|
|
|
+ if (!_pre_target) return;
|
|
|
+ let _pre_end_date = this.preMultiple
|
|
|
+ ? getMax(_pre_target.to, this.selfProps.endDate, true) // 取前置点中最晚的结束时间
|
|
|
+ : _pre_target.to[this.selfProps.endDate];
|
|
|
+ /* 在数据循环中处理前置
|
|
|
+ let pres = item[this.selfProps.pre];
|
|
|
+ if(!pres) return;
|
|
|
+ let _pre_target = null, _pre_end_date = null;
|
|
|
+ if(this.preMultiple){
|
|
|
+ if(!Array.isArray(pres) || pres.length ===0) return;
|
|
|
+ _pre_target = this.self_data_list.filter(i => pres.includes(i[this.selfProps.id]));
|
|
|
+ _pre_end_date = getMax(_pre_target, this.selfProps.endDate, true);
|
|
|
+ }else{
|
|
|
+ _pre_target = this.self_data_list.find(i => i[this.selfProps.id] === pres);
|
|
|
+ if(!_pre_target) return;
|
|
|
+ _pre_end_date = _pre_target[this.selfProps.endDate]
|
|
|
+ } */
|
|
|
+ // 查看是否需要根据前置时间,如果不符合规则,更新后置时间
|
|
|
+ let _start_early_prvend = this.timeIsBefore(item[this.selfProps.startDate], _pre_end_date);
|
|
|
+ if (_start_early_prvend) {
|
|
|
+ let _cycle = item._cycle - 1;
|
|
|
+ let _to_startDate = this.timeAdd(_pre_end_date, 1);
|
|
|
+ let _to_endDate = this.timeAdd(_to_startDate, _cycle);
|
|
|
+ this.$set(item, this.selfProps.startDate, _to_startDate);
|
|
|
+ this.$set(item, this.selfProps.endDate, _to_endDate);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 检查前置任务合法性
|
|
|
+ * !!已废弃:改为从一维数据列收集form、to并校验,不再在递归中检查 -> handleDependentStore
|
|
|
+ */
|
|
|
+ checkPreTaskValidity(item) {
|
|
|
+ // 没有前置任务退出
|
|
|
+ if (!item[this.selfProps.pre]) return false;
|
|
|
+ // 多前置任务模式
|
|
|
+ if (this.preMultiple) {
|
|
|
+ let _pres = item[this.selfProps.pre];
|
|
|
+ // 不是数组退出
|
|
|
+ if (!Array.isArray(_pres)) {
|
|
|
+ this.emitPreChange(item, item[this.selfProps.pre]);
|
|
|
+ this.$set(item, this.selfProps.pre, []);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ // 数组为空退出
|
|
|
+ if (_pres.length === 0) return false;
|
|
|
+ // 前置任务有自己时,剔除自己
|
|
|
+ let _net_self_pres = _pres.filter(i => i !== item[this.selfProps.id]);
|
|
|
+ if (_net_self_pres.length !== _pres.length) {
|
|
|
+ this.emitPreChange(item, item[this.selfProps.pre]);
|
|
|
+ this.$set(item, this.selfProps.pre, _net_self_pres);
|
|
|
+ }
|
|
|
+ // 剔除前置任务找不到目标数据的元素
|
|
|
+ let _pre_exist = _net_self_pres.filter(i => this.targetInAllData(i));
|
|
|
+ if (_pre_exist.length !== _net_self_pres.length) {
|
|
|
+ this.emitPreChange(item, item[this.selfProps.pre]);
|
|
|
+ this.$set(item, this.selfProps.pre, _pre_exist);
|
|
|
+ }
|
|
|
+ let _no_par_chi = []; // 声明非父、祖、子、孙节点的盒子
|
|
|
+ for (let i of _pre_exist) {
|
|
|
+ let _pre_target = this.self_data_list.find(t => t[this.selfProps.id] === i);
|
|
|
+ if (!_pre_target) continue;
|
|
|
+ let _pre_par_chi = this.targetInParentsOrChildren(item, _pre_target);
|
|
|
+ _pre_par_chi || _no_par_chi.push(i);
|
|
|
+ }
|
|
|
+ // 前置任务是自己的父祖或子孙节点, 剔除此前置
|
|
|
+ if (_no_par_chi.length !== _pre_exist.length) {
|
|
|
+ this.emitPreChange(item, item[this.selfProps.pre]);
|
|
|
+ this.$set(item, this.selfProps.pre, _no_par_chi);
|
|
|
+ }
|
|
|
+ // 处理前置任务链链中产生了回环【A->B,B->C,C->D,D->B】即前置链中形成了相互前置的节点,剔除其错误前置数据
|
|
|
+ this.targetLinkLoopback(item);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ // 单前置任务模式
|
|
|
+ if (item[this.selfProps.pre] === item[this.selfProps.id]) {
|
|
|
+ this.$set(item, this.selfProps.pre, null);
|
|
|
+ return false;
|
|
|
+ } // 前置任务是自己退出
|
|
|
+ // 找到前置目标节点
|
|
|
+ let _pre_target = this.self_data_list.find(i => i[this.selfProps.id] == item[this.selfProps.pre]);
|
|
|
+ // 没找到前置任务节点数据退出
|
|
|
+ if (!_pre_target) {
|
|
|
+ this.$set(item, this.selfProps.pre, null);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ // 前置任务是自己的父祖或子孙节点退出
|
|
|
+ let is_pre_standard = this.targetInParentsOrChildren(item, _pre_target);
|
|
|
+ if (is_pre_standard) {
|
|
|
+ this.$set(item, this.selfProps.pre, null);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ // 处理前置任务链链中产生了回环【A->B,B->C,C->D,D->B】即前置链中形成了相互前置的节点,剔除其错误前置数据
|
|
|
+ this.targetLinkLoopback(item);
|
|
|
+ return true;
|
|
|
+ },
|
|
|
+ // 处理数据生成自增id和树链parents
|
|
|
+ recordIdentityIdAndParents(item) {
|
|
|
+ // if (!this.recordParents) return;
|
|
|
+ if (this.treatIdAsIdentityId) {
|
|
|
+ let _parents = item._parent ? item._parent._parents + ',' + item._parent[this.selfProps.id] : '';
|
|
|
+ this.$set(item, '_parents', _parents);
|
|
|
+ this.$set(item, '_identityId', item[this.selfProps.id]);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // 添加自增id
|
|
|
+ this.$set(item, '_identityId', this.self_id);
|
|
|
+ this.self_id++;
|
|
|
+ // 添加parents字段
|
|
|
+ let _parents = item._parent ? item._parent._parents + ',' + item._parent._identityId : '';
|
|
|
+ this.$set(item, '_parents', _parents);
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 查询目标是否在父级链或者全部子集中
|
|
|
+ * item 当前节点
|
|
|
+ * pre 前置节点
|
|
|
+ */
|
|
|
+ targetInParentsOrChildren(item, pre) {
|
|
|
+ let _parents = item._parents.split(',');
|
|
|
+ let _children = item._all_children.map(i => i._identityId);
|
|
|
+ return _children.concat(_parents).some(i => i == pre._identityId);
|
|
|
+ },
|
|
|
+ // 查询目标节点是否在数据中存在,并返回数据
|
|
|
+ targetInAllData(target_id) {
|
|
|
+ return this.self_data_list.find(i => i[this.selfProps.id] === target_id);
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 处理前置任务链链中产生了回环【A->B,B->C,C->D,D->B】即前置链中形成了相互前置的节点,剔除其错误前置数据
|
|
|
+ * item: Object 当前节点数据
|
|
|
+ * pre_tesk: Array 前置链上所有id
|
|
|
+ * !!已废弃:下方尝试改成form to结构收集起来处理,不再循环中反复循环处理 -> terseTargetLinkLoopback
|
|
|
+ */
|
|
|
+ targetLinkLoopback(item, pre_tesk = []) {
|
|
|
+ pre_tesk.push(item[this.selfProps.id]);
|
|
|
+ let _pres = item[this.selfProps.pre];
|
|
|
+ let _legal_pres = _pres.filter(i => !pre_tesk.includes(i));
|
|
|
+ if (this.preMultiple) {
|
|
|
+ if (_legal_pres.length !== _pres.length) {
|
|
|
+ this.emitPreChange(item, item[this.selfProps.pre]);
|
|
|
+ this.$set(item, this.selfProps.pre, _legal_pres);
|
|
|
+ }
|
|
|
+ _legal_pres.forEach(i => {
|
|
|
+ let _pre_target = this.self_data_list.find(t => t[this.selfProps.id] === i);
|
|
|
+ if (
|
|
|
+ _pre_target &&
|
|
|
+ Array.isArray(_pre_target[this.selfProps.pre]) &&
|
|
|
+ _pre_target[this.selfProps.pre].length > 0
|
|
|
+ ) {
|
|
|
+ this.targetLinkLoopback(_pre_target, pre_tesk);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ if (pre_tesk.includes(_pres)) {
|
|
|
+ this.emitPreChange(item, item[this.selfProps.pre]);
|
|
|
+ this.$set(item, this.selfProps.pre, _legal_pres);
|
|
|
+ }
|
|
|
+ let _pre_target = this.self_data_list.find(t => t[this.selfProps.id] === item[this.selfProps.id]);
|
|
|
+ if (_pre_target) {
|
|
|
+ this.targetLinkLoopback(_pre_target, pre_tesk);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 处理前置任务链链中产生了回环【A->B,B->C,C->D,D->B】即前置链中形成了相互前置的节点,剔除其错误前置数据
|
|
|
+ * item: Object 当前节点数据
|
|
|
+ * flow_pre_tesk: Array 前置链上所有id
|
|
|
+ */
|
|
|
+ terseTargetLinkLoopback(item, flow_pre_tesk = []) {
|
|
|
+ flow_pre_tesk.push(item.form[this.selfProps.id]);
|
|
|
+ if (this.preMultiple) {
|
|
|
+ let _legal_pre = [], // 收集合法数据
|
|
|
+ _next_form = []; // 收集所有前置的前置
|
|
|
+ for (let i of item.to) {
|
|
|
+ let _to_id = i[this.selfProps.id];
|
|
|
+ if (flow_pre_tesk.includes(_to_id)) continue;
|
|
|
+ _legal_pre.push(_to_id);
|
|
|
+ flow_pre_tesk.push(_to_id);
|
|
|
+ let _store_next_form = this.self_dependent_store.filter(t => t.form[this.selfProps.id] === _to_id);
|
|
|
+ _next_form = _next_form.concat(_store_next_form);
|
|
|
+ }
|
|
|
+ // 剔除不合法前置
|
|
|
+ if (_legal_pre.length !== item.to.length) {
|
|
|
+ this.emitPreChange(item.form, item.form[this.selfProps.pre]);
|
|
|
+ this.$set(item.form, this.selfProps.pre, _legal_pre);
|
|
|
+ }
|
|
|
+ // 向前置的前置递归
|
|
|
+ _next_form.forEach(t => {
|
|
|
+ this.terseTargetLinkLoopback(t, flow_pre_tesk);
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ let _to_id = item.to[this.selfProps.id];
|
|
|
+ if (flow_pre_tesk.includes(_to_id)) {
|
|
|
+ this.emitPreChange(item.form, item.form[this.selfProps.pre]);
|
|
|
+ this.$set(item.form, this.selfProps.pre, null);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ let _next_form = this.self_dependent_store.find(t => t.form[this.selfProps.id] === _to_id);
|
|
|
+ if (!_next_form) return;
|
|
|
+ this.terseTargetLinkLoopback(_next_form, flow_pre_tesk);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 简洁处理数据
|
|
|
+ terseHandleData(data, parent = null, level = 0) {
|
|
|
+ level++;
|
|
|
+ data.forEach(i => {
|
|
|
+ this.$set(i, '_parent', parent); // 添加父级字段
|
|
|
+ this.$set(i, '_level', level); // 添加层级字段
|
|
|
+ let _time_diff = this.timeDiffTime(i[this.selfProps.startDate], i[this.selfProps.endDate]);
|
|
|
+ i._cycle = _time_diff + 1;
|
|
|
+ if (!i._oldStartDate) {
|
|
|
+ // 添加开始时间字段
|
|
|
+ this.$set(i, '_oldStartDate', i[this.selfProps.startDate]);
|
|
|
+ }
|
|
|
+ if (!i._oldEndDate) {
|
|
|
+ // 添加结束字段时间
|
|
|
+ this.$set(i, '_oldEndDate', i[this.selfProps.endDate]);
|
|
|
+ }
|
|
|
+ // 添加自增id字段及树链组成的parents字段
|
|
|
+ this.recordIdentityIdAndParents(i);
|
|
|
+ if (Array.isArray(i[this.selfProps.children])) {
|
|
|
+ this.$set(i, '_isLeaf', false); // 添加是否叶子节点字段
|
|
|
+ let _all_children = flattenDeep(i[this.selfProps.children], this.selfProps.children);
|
|
|
+ this.$set(i, '_all_children', _all_children); // 添加全部子节点字段
|
|
|
+ this.terseHandleData(i[this.selfProps.children], i, level);
|
|
|
+ } else {
|
|
|
+ this.$set(i, '_isLeaf', true); // 添加是否叶子节点字段
|
|
|
+ }
|
|
|
+ // 处理前置任务
|
|
|
+ // this.handlePreTask(i);
|
|
|
+ });
|
|
|
+ },
|
|
|
+ // 生成前置依赖库, 校验前置合法性并剔除不合法数据
|
|
|
+ handleDependentStore() {
|
|
|
+ this.self_dependent_store = [];
|
|
|
+ // 多选前置模式
|
|
|
+ if (this.preMultiple) {
|
|
|
+ for (let i of this.self_data_list) {
|
|
|
+ let _pres = i[this.selfProps.pre];
|
|
|
+ if (!_pres) continue;
|
|
|
+ // 不是数组退出
|
|
|
+ if (!Array.isArray(_pres)) {
|
|
|
+ this.emitPreChange(i, i[this.selfProps.pre]);
|
|
|
+ this.$set(i, this.selfProps.pre, []);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ // 数组为空退出
|
|
|
+ if (_pres.length === 0) continue;
|
|
|
+ // 查询不到数据的不收集,是父、祖、子、孙节点的不收集
|
|
|
+ let _pre_exist_node = [],
|
|
|
+ _pre_exist_id = [];
|
|
|
+ for (let t of _pres) {
|
|
|
+ let target_node = this.targetInAllData(t);
|
|
|
+ if (!target_node) continue; // 查询不到数据的不收集
|
|
|
+ let in_per_chi = this.targetInParentsOrChildren(i, target_node);
|
|
|
+ if (in_per_chi) continue; // 是父、祖、子、孙节点的不收集
|
|
|
+ _pre_exist_node.push(target_node);
|
|
|
+ _pre_exist_id.push(target_node[this.selfProps.id]);
|
|
|
+ }
|
|
|
+ if (_pre_exist_node.length !== _pres.length) {
|
|
|
+ this.emitPreChange(i, i[this.selfProps.pre]);
|
|
|
+ this.$set(i, this.selfProps.pre, _pre_exist_id);
|
|
|
+ }
|
|
|
+ this.self_dependent_store.push({
|
|
|
+ form: i,
|
|
|
+ to: _pre_exist_node
|
|
|
+ });
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 单选前置模式
|
|
|
+ for (let i of this.self_data_list) {
|
|
|
+ if (!i[this.selfProps.pre]) continue;
|
|
|
+ let _pre_target = this.targetInAllData(i[this.selfProps.pre]);
|
|
|
+ // 处理前置任务找不到的情况
|
|
|
+ if (!_pre_target) {
|
|
|
+ this.emitPreChange(i, i[this.selfProps.pre]);
|
|
|
+ this.$set(i, this.selfProps.pre, null);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ // 处理前置任务是父祖子孙节点的情况
|
|
|
+ let in_per_chi = this.targetInParentsOrChildren(i, _pre_target);
|
|
|
+ if (in_per_chi) {
|
|
|
+ this.emitPreChange(i, i[this.selfProps.pre]);
|
|
|
+ this.$set(i, this.selfProps.pre, null);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ this.self_dependent_store.push({
|
|
|
+ form: i,
|
|
|
+ to: _pre_target
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 处理合格前置任务
|
|
|
+ this.self_dependent_store.forEach(i => {
|
|
|
+ this.terseTargetLinkLoopback(i);
|
|
|
+ });
|
|
|
+ // 处理前置依赖
|
|
|
+ this.self_data_list.forEach(i => {
|
|
|
+ this.handlePreTask(i);
|
|
|
+ });
|
|
|
+ // 暂时强制更新视图
|
|
|
+ if (this.update) {
|
|
|
+ this.update = false;
|
|
|
+ this.selfData.sort();
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 父子关联
|
|
|
+ tableSelect(val, row) {
|
|
|
+ if (!this.parentChild) return;
|
|
|
+ // 选中
|
|
|
+ if (val.some(item => item[this.selfProps.id] == row[this.selfProps.id])) {
|
|
|
+ // 父元素选中全选所有子孙元素
|
|
|
+ // for (let item of val) {
|
|
|
+ row._all_children.forEach(i => {
|
|
|
+ this.$refs['wl-gantt'].toggleRowSelection(i, true);
|
|
|
+ });
|
|
|
+ // }
|
|
|
+ // 子元素全选向上查找所有满足条件的祖先元素
|
|
|
+ regDeepParents(row, '_parent', parents => {
|
|
|
+ let reg =
|
|
|
+ parents &&
|
|
|
+ parents[this.selfProps.children].every(item => {
|
|
|
+ return val.some(it => it[this.selfProps.id] == item[this.selfProps.id]);
|
|
|
+ });
|
|
|
+ if (reg) this.$refs['wl-gantt'].toggleRowSelection(parents, true);
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ // 非选中将所有子孙元素及支线上祖先元素清除
|
|
|
+ let cancel_data = [...row._all_children, ...flattenDeepParents([row], '_parent')];
|
|
|
+ for (let item of cancel_data) {
|
|
|
+ this.$refs['wl-gantt'].toggleRowSelection(item, false);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // el-table事件----------------------------------------------以下为原el-table事件输出------------------------------------------------
|
|
|
+ handleSelectionChange(val) {
|
|
|
+ this.$emit('selection-change', val);
|
|
|
+ this.multipleSelection = val;
|
|
|
+ }, // 当选择项发生变化时会触发该事件
|
|
|
+ handleCurrentChange(val, oldVal) {
|
|
|
+ this.$emit('current-change', val, oldVal);
|
|
|
+ this.currentRow = val;
|
|
|
+ }, // 当表格的当前行发生变化的时候会触发该事件
|
|
|
+ handleSelectAll(val) {
|
|
|
+ let is_check = val.length > 0;
|
|
|
+ this.self_data_list.forEach(i => {
|
|
|
+ this.$refs['wl-gantt'].toggleRowSelection(i, is_check);
|
|
|
+ });
|
|
|
+ this.$emit('select-all', val);
|
|
|
+ }, // 当用户手动勾选全选 Checkbox 时触发的事件
|
|
|
+ handleSelect(selection, row) {
|
|
|
+ this.tableSelect(selection, row);
|
|
|
+ let _is_add = selection.some(i => i[this.rowKey] === row[this.rowKey]);
|
|
|
+ this.selectionList = selection;
|
|
|
+ this.$emit('select', selection, row, _is_add);
|
|
|
+ }, // 当用户手动勾选全选 Checkbox 时触发的事件
|
|
|
+ handleMouseEnter(row, column, cell, event) {
|
|
|
+ if (this.useCard) {
|
|
|
+ this.infoCard.show = true;
|
|
|
+ this.infoCard.x = event.screenX;
|
|
|
+ this.infoCard.y = event.screenY;
|
|
|
+ this.infoCard.row = { ...row };
|
|
|
+ this.infoCard.column = column;
|
|
|
+ this.infoCard.cell = cell;
|
|
|
+ this.infoCard.event = event;
|
|
|
+ this.infoCard.timer && clearTimeout(this.infoCard.timer);
|
|
|
+ }
|
|
|
+ this.$emit('cell-mouse-enter', row, column, cell, event);
|
|
|
+ }, // 当单元格 hover 进入时会触发该事件
|
|
|
+ handleMouseLeave(row, column, cell, event) {
|
|
|
+ if (this.useCard) {
|
|
|
+ this.infoCard.timer = setTimeout(() => {
|
|
|
+ this.infoCard.show = false;
|
|
|
+ clearTimeout(this.infoCard.timer);
|
|
|
+ this.infoCard.timer = null;
|
|
|
+ }, 500);
|
|
|
+ }
|
|
|
+ this.$emit('cell-mouse-leave', row, column, cell, event);
|
|
|
+ }, // 当单元格 hover 退出时会触发该事件
|
|
|
+ handleCellClick(row, column, cell, event) {
|
|
|
+ this.$emit('cell-click', row, column, cell, event);
|
|
|
+ }, // 当某个单元格被点击时会触发该事件
|
|
|
+ handleCellDbClick(row, column, cell, event) {
|
|
|
+ this.$emit('cell-dblclick', row, column, cell, event);
|
|
|
+ }, // 当某个单元格被双击击时会触发该事件
|
|
|
+ handleRowClick(row, column, event) {
|
|
|
+ /* if (this.useCheckColumn && this.quickCheck) {
|
|
|
+ let is_check = this.selectionList.some(
|
|
|
+ i => i[this.rowKey] == row[this.rowKey]
|
|
|
+ );
|
|
|
+ this.$refs["wl-gantt"].toggleRowSelection(row, !is_check);
|
|
|
+ this.$nextTick(() => {
|
|
|
+ this.handleSelect(this.selectionList, row, !is_check);
|
|
|
+ });
|
|
|
+ } */
|
|
|
+ this.$emit('row-click', row, column, event);
|
|
|
+ }, // 当某一行被点击时会触发该事件
|
|
|
+ handleRowContextMenu(row, column, event) {
|
|
|
+ this.$emit('row-contextmenu', row, column, event);
|
|
|
+ // 处理右键菜单浮窗
|
|
|
+ if (!Array.isArray(this.contextMenuOptions)) return;
|
|
|
+ this.contextMenu.data = [];
|
|
|
+ this.contextMenuOptions.forEach(i => {
|
|
|
+ let _item = {
|
|
|
+ label: i.label,
|
|
|
+ icon: i.icon,
|
|
|
+ value: row[i.prop]
|
|
|
+ };
|
|
|
+ this.contextMenu.data.push(_item);
|
|
|
+ });
|
|
|
+ this.contextMenu.x = event.x;
|
|
|
+ this.contextMenu.y = event.y;
|
|
|
+ this.contextMenu.show = true;
|
|
|
+ }, // 当某一行被鼠标右键点击时会触发该事件
|
|
|
+ handleContextmenu() {
|
|
|
+ event.preventDefault();
|
|
|
+ event.stopPropagation();
|
|
|
+ }, // 右键菜单事件
|
|
|
+ handleRowDbClick(row, column, event) {
|
|
|
+ this.$emit('row-dblclick', row, column, event);
|
|
|
+ }, // 当某一行被双击时会触发该事件
|
|
|
+ handleHeaderClick(column, event) {
|
|
|
+ this.$emit('header-click', column, event);
|
|
|
+ }, // 当某一列的表头被点击时会触发该事件
|
|
|
+ handleHeaderContextMenu(column, event) {
|
|
|
+ this.$emit('header-contextmenu', column, event);
|
|
|
+ }, // 当某一列的表头被鼠标右键点击时触发该事件
|
|
|
+ handleSortChange(e) {
|
|
|
+ this.$emit('sort-change', e);
|
|
|
+ }, // 当表格的排序条件发生变化的时候会触发该事件
|
|
|
+ handleFilterChange(filters) {
|
|
|
+ this.$emit('filter-change', filters);
|
|
|
+ }, // 当表格的筛选条件发生变化的时候会触发该事件
|
|
|
+ handleExpandChange(row, expanded) {
|
|
|
+ this.$emit('expand-change', row, expanded);
|
|
|
+ }, // 当表格的筛选条件发生变化的时候会触发该事件
|
|
|
+ // ------------------------------------------- 以下为提供方法 ------------------------------------
|
|
|
+ /**
|
|
|
+ * 手动调用树表懒加载
|
|
|
+ * row 要展开的行信息
|
|
|
+ */
|
|
|
+ loadTree(row) {
|
|
|
+ this.$refs['tableRef'].store.loadOrToggle(row);
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 更新树表懒加载后的子节点
|
|
|
+ * 要更新的节点id
|
|
|
+ * 要添加的节点list
|
|
|
+ */
|
|
|
+ loadTreeAdd(id, list) {
|
|
|
+ let _children = this.$refs['wl-gantt'].store.states.lazyTreeNodeMap[id] || [];
|
|
|
+ this.$set(this.$refs['wl-gantt'].store.states.lazyTreeNodeMap, id, list.concat(_children));
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 更新树表懒加载后的子节点
|
|
|
+ * 要更新的节点id
|
|
|
+ * 要删掉的字节的rowKey
|
|
|
+ */
|
|
|
+ loadTreeRemove(id, key) {
|
|
|
+ let _children = this.$refs['wl-gantt'].store.states.lazyTreeNodeMap[id];
|
|
|
+ let _new_children = _children.filter(i => i[this.rowKey] != key);
|
|
|
+ this.$set(this.$refs['wl-gantt'].store.states.lazyTreeNodeMap, id, _new_children);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ created() {
|
|
|
+ this.self_date_type = this.dateType;
|
|
|
+ this.self_start_date = this.startDate;
|
|
|
+ this.self_end_date = this.endDate;
|
|
|
+ },
|
|
|
+ beforeDestroy() {
|
|
|
+ if (this.infoCard.timer) {
|
|
|
+ clearTimeout(this.infoCard.timer);
|
|
|
+ this.infoCard.timer = null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+};
|
|
|
+</script>
|
|
|
+
|
|
|
+<!-- Add "scoped" attribute to limit CSS to this component only -->
|
|
|
+<style lang="less">
|
|
|
+@import './css/index.less';
|
|
|
+</style>
|