ag-grid-vue在排班组件中的使用

在很多医务系统中,会有医生护士排班的业务,比如下面这种:

 

 

 可是实现排班数据的上移,下移,并且能够通过右键菜单实现排班等操作;

直接上源码:

首先安装依赖:

npm install ag-grid-vue

npm install ag-grid-community

npm install vue-property-decorator
接下来组件封装:
目录结构如下:

 

 jhe-grid-table.vue内容如下:

   1 <template>
   2   <div class="JheGridTable">
   3     <div @contextmenu.prevent="onOpenContextMenu">
   4       <ag-grid-vue
   5         style="width: 100%; height: 100%"
   6         class="ag-theme-balham"
   7         :defaultColDef="defaultColDef"
   8         :columnDefs="columnDefs"
   9         :rowData="rowData"
  10         :enableColResize="true"
  11         :suppressCellFocus="false"
  12         :suppressMultiRangeSelection="false"
  13         :enableCellTextSelection="false"
  14         :enableRangeSelection="false"
  15         :rowMultiSelectWithClick="false"
  16         :suppressRowClickSelection="false"
  17         :floatingFilter="false"
  18         :suppressMenuHide="false"
  19         :suppressMovableColumns="true"
  20         :suppressDragLeaveHidesColumns="false"
  21         :suppressMovable="false"
  22         :context="ctx"
  23         :allowContextMenuWithControlKey="false"
  24         :headerHeight="headerHeight"
  25         :getRowHeight="getRowHeight"
  26         @grid-ready="onGridReady"
  27         @first-data-rendered="onFirstDataRendered"
  28         @rowDataChanged="onRowDataChanged"
  29         @cellClicked="onCellClicked"
  30         @sort-changed="onSortChanged"
  31         @cellMouseDown="onCellMouseDown"
  32         @mouseup.native="onCellMouseUp"
  33         @cellMouseOver="onCellMouseOver"
  34         @cellMouseOut="onCellMouseOut"
  35         @cellFocused="onCellFocused"
  36         @dragStarted="onDragStarted"
  37         @dragStopped="onDragStopped"
  38       ></ag-grid-vue>
  39     </div>
  40 
  41     <context-menu
  42       id="testingctx"
  43       ref="ctx"
  44       @ctx-open="onCtxOpened"
  45       @ctx-cancel="resetCtxMenu"
  46       @ctx-close="onCtxClosed"
  47     >
  48       <div class="ctx-menu-body" :style="ctxMenuBodyStyle">
  49         <div class="ctx-group" :style="{ width: ctxMenuBodyWidth }">
  50           <div
  51             class="ctx-item"
  52             :key="'ctxmi_' + index"
  53             v-for="(item, index) in ctxMenuItems"
  54             @click="onCtxMenuItemClick(item)"
  55             @mouseenter="onCtxMenuMouseEnter(item)"
  56             @mouseleave="onCtxMenuMouseLeave(item)"
  57           >
  58             <div>
  59               {{ item.title }}
  60             </div>
  61             <div v-if="item.children && item.children.length > 0">
  62               <i class="el-icon-arrow-right"></i>
  63             </div>
  64           </div>
  65         </div>
  66         <div
  67           v-if="showChildCtxMenu"
  68           class="ctx-group"
  69           style="border-left: 1px solid #ccc; overflow: auto"
  70         >
  71           <div
  72             class="ctx-item"
  73             :key="'sub_' + index"
  74             v-for="(item, index) in subMenuItems"
  75             @click="onCtxMenuItemClick(item)"
  76           >
  77             {{ item.title }}
  78           </div>
  79         </div>
  80       </div>
  81     </context-menu>
  82   </div>
  83 </template>
  84 <script>
  85 import { getOneWeekDate } from "../utils/tools";
  86 import $ from "jquery";
  87 import _ from "lodash";
  88 import SsCellRender from "../components/ss-cell-render";
  89 import SsHeaderRender from "../components/ss-header-render";
  90 import SsRowHeaderRender from "../components/ss-row-header-render";
  91 import contextMenu from "../components/ctx-menu";
  92 //引入样式文件
  93 import "ag-grid-community/dist/styles/ag-grid.css";
  94 import "ag-grid-community/dist/styles/ag-theme-balham.css";
  95 //引入ag-grid-vue
  96 import { AgGridVue } from "ag-grid-vue";
  97 import { Message } from "element-ui";
  98 
  99 export default {
 100   name: "JheGridTable",
 101   props: {
 102     startDate: {
 103       type: Date,
 104     },
 105     //列定义
 106     columns: {
 107       type: Array,
 108       default: () => {
 109         return [];
 110       },
 111     },
 112     //rowData数据
 113     rowData: {
 114       type: Array,
 115       default: () => {
 116         return [];
 117       },
 118     },
 119     headerHeight: {
 120       type: Number,
 121       default: 30,
 122     },
 123     ctxMenuItems: {
 124       type: Array,
 125       default: () => {
 126         return [];
 127       },
 128     },
 129   },
 130   data() {
 131     let self = this;
 132     return {
 133       gridCtrl: null,
 134       gridApi: null,
 135       columnApi: null,
 136       isDraging: false,
 137       selectedRanges: [],
 138       ctx: {
 139         isDragCopying: false,
 140       },
 141       ctxMenuBodyWidth: 0,
 142       ctxMenuBodyStyle: null,
 143       subMenuItems: [],
 144       showChildCtxMenu: false,
 145       mouseEnterCtxMenuItem: null,
 146       jheGridApi: {
 147         selectRow(rowId) {
 148           self.selectRow(rowId);
 149         },
 150         selectColumn(colId) {
 151           self.selectColumn(colId);
 152         },
 153         selectCells(range) {
 154           self.selectCells(range);
 155         },
 156         moveRowUp() {
 157           self.moveRowUp();
 158         },
 159         moveRowDown() {
 160           self.moveRowDown();
 161         },
 162         moveDaysUp() {
 163           self.moveDaysUp();
 164         },
 165         moveDaysDown() {
 166           self.moveDaysDown();
 167         },
 168         exchangeDays() {
 169           self.exchangeDays();
 170         },
 171         getCellData(rowId, colId) {
 172           return self.getCellData(rowId, colId);
 173         },
 174         setCellData(rowId, colId, value) {
 175           self.setCellData(rowId, colId, value);
 176         },
 177         getRowData(rowId) {
 178           return self.getRowData(rowId);
 179         },
 180         setRangeValue(range, data) {
 181           self.setRangeValue(range, data);
 182         },
 183       },
 184     };
 185   },
 186   computed: {
 187     defaultColDef() {
 188       return {
 189         cellStyle: {
 190           "text-align": "center",
 191         },
 192       };
 193     },
 194     columnDefs() {
 195       let oneWeekDate = getOneWeekDate(this.startDate);
 196       let colDefs = this.columns.map((c, index) => {
 197         let columnDef = _.cloneDeep(c);
 198         if (typeof columnDef.colId === "undefined") {
 199           columnDef.colId = index;
 200         }
 201         if (columnDef.selectable) {
 202           delete columnDef.selectable;
 203           columnDef.cellRenderer = "SsCellRender";
 204           columnDef.headerComponent = "SsHeaderRender";
 205           let date = oneWeekDate[columnDef.field];
 206 
 207           columnDef.headerComponentParams = {
 208             subtitle:
 209               date &&
 210               date.toLocaleDateString("cn", {
 211                 month: "numeric",
 212                 day: "numeric",
 213               }),
 214             onColumnClick: this.onSelectWholeColumn,
 215           };
 216         }
 217         return columnDef;
 218       });
 219       colDefs.unshift({
 220         headerName: "#",
 221         colId: "rowNum",
 222         valueGetter: "node.rowIndex",
 223         minWidth: 40,
 224         maxWidth: 40,
 225         pinned: "left",
 226         cellRenderer: "SsRowHeaderRender",
 227         cellStyle: {
 228           "text-align": "center",
 229           "background-color": "rgb(245, 247, 247)",
 230           "border-right": "1px solid #d9dcde",
 231         },
 232       });
 233       return colDefs;
 234     },
 235   },
 236   watch: {
 237     "ctx.isDragCopying": {
 238       handler(newVal, oldVal) {
 239         if (this.$el) {
 240           if (newVal) {
 241             this.$el.classList.add("drag-copying");
 242           } else {
 243             this.$el.classList.remove("drag-copying");
 244           }
 245         }
 246       },
 247     },
 248     columnDefs: {
 249       handler(newV) {
 250         //列定义改变后,表格需要重新渲染
 251         this.$nextTick(() => {
 252           this.gridApi.setColumnDefs(newV);
 253           this.gridApi.sizeColumnsToFit();
 254         });
 255       },
 256       deep: true,
 257     },
 258   },
 259   created() {
 260     this.iniGrid();
 261   },
 262   methods: {
 263     iniGrid() {
 264       this.ctxMenuBodyWidth = 160;
 265       this.ctxMenuBodyStyle = {
 266         width: this.ctxMenuBodyWidth + "px",
 267       };
 268     },
 269     getRowHeight(params) {
 270       return 35;
 271     },
 272     onGridReady(params) {
 273       this.gridCtrl = params;
 274       this.gridApi = params.api;
 275       this.columnApi = params.columnApi;
 276       this.gridApi.sizeColumnsToFit();
 277       this.$emit("init", this.jheGridApi);
 278     },
 279     onFirstDataRendered(params) {
 280       this.$emit("loaded", params);
 281     },
 282     onRowDataChanged(event) {
 283       this.$emit("changed", event);
 284     },
 285     //单元格点击事件
 286     onCellClicked(event) {
 287       let field = event.column.colDef.field;
 288       let cellRendererName = event.column.colDef.cellRenderer;
 289       let position = { rowId: event.node.id, colId: event.column.colId };
 290       if (cellRendererName === "SsCellRender") {
 291         this.gridCtrl.api.deselectAll();
 292         this.$emit("cellClicked", position, event.data[field]);
 293       }
 294 
 295       // const colIndex = this._getColumnIndex(event.column.colId);
 296       // if (colIndex == 1) {
 297       //   //行点击
 298       //   this._selectRow(event.node.id);
 299       // }
 300     },
 301     onSortChanged(params) {
 302       let { api } = params;
 303       api.refreshCells({
 304         columns: [this.columnDefs[0].colId],
 305       });
 306     },
 307 
 308     onCellMouseDown(event) {
 309       if (event.event.button != 0) {
 310         // 不是鼠标左键
 311         return;
 312       }
 313 
 314       this.isDraging = true;
 315       console.log("onCellMouseDown", arguments);
 316 
 317       if (!event.event.ctrlKey) {
 318         this.selectedRanges = [];
 319         this._clearSelectedCells();
 320       }
 321 
 322       this._clearDropCopyHolder();
 323 
 324       const start = this._getCellPos(event);
 325       this.selectedRanges.push([start]);
 326       this._showDropCopyHolder(start.rowId, start.colId);
 327     },
 328     onCellMouseUp(event) {
 329       this.isDraging = false;
 330 
 331       if (event.button != 0) {
 332         // 不是鼠标左键
 333         return;
 334       }
 335 
 336       console.log("onCellMouseUp", arguments, this.gridApi);
 337       const end = this._getCellPos(event.target);
 338       if (end == null) {
 339         // 不是单元格
 340         return;
 341       }
 342 
 343       const range = this.selectedRanges.pop();
 344       if (!range) {
 345         return;
 346       }
 347       range[1] = end;
 348 
 349       this.selectedRanges.push(range);
 350       this._selectRange(range);
 351       this.gridApi.clearFocusedCell();
 352 
 353       if (this.ctx.isDragCopying) {
 354         const data = this._getCellData(range[0].rowId, range[0].colId);
 355         this._setRangValue(range, data);
 356         console.log(
 357           "onCellMouseUp",
 358           this.rowData,
 359           this._getRowData(range[0].rowId)
 360         );
 361         // this.gridApi.refreshCells();
 362       }
 363 
 364       this.ctx.isDragCopying = false;
 365     },
 366     onCellMouseOver(event) {
 367       if (this.isDraging) {
 368         console.log("cellMouseOver", arguments);
 369         const end = this._getCellPos(event);
 370         const range = this.selectedRanges.pop();
 371         range[1] = end;
 372         this.selectedRanges.push(range);
 373 
 374         this._selectAllRanges(this.selectedRanges);
 375       }
 376     },
 377     onCellMouseOut() {
 378       if (this.isDraging) console.log("onCellMouseOut", arguments);
 379     },
 380     onCellFocused() {
 381       console.log("onCellFocused", arguments);
 382       // setTimeout(()=>{
 383       // this.gridApi.clearFocusedCell();
 384       // },1000);
 385     },
 386     onDragStarted() {
 387       console.log("onDragStarted", arguments);
 388     },
 389     onDragStopped() {
 390       console.log("onDragStopped", arguments);
 391     },
 392 
 393     _swapRanges(range1, range2) {
 394       if (range1 == null || range2 == null) {
 395         console.error("只能对两个尺寸相等的区域进行对换", arguments);
 396         return null;
 397       }
 398 
 399       const fX1 = Math.min(range1[0].colIndex, range1[1].colIndex) || 0;
 400       const fY1 = Math.min(range1[0].rowIndex, range1[1].rowIndex) || 0;
 401       const fX2 = Math.max(range1[0].colIndex, range1[1].colIndex) || 0;
 402       const fY2 = Math.max(range1[0].rowIndex, range1[1].rowIndex) || 0;
 403 
 404       const sX1 = Math.min(range2[0].colIndex, range2[1].colIndex) || 0;
 405       const sY1 = Math.min(range2[0].rowIndex, range2[1].rowIndex) || 0;
 406       const sX2 = Math.max(range2[0].colIndex, range2[1].colIndex) || 0;
 407       const sY2 = Math.max(range2[0].rowIndex, range2[1].rowIndex) || 0;
 408 
 409       if (fX2 - fX1 != sX2 - sX1 || fY2 - fY1 != sY2 - sY1) {
 410         console.error("只能对两个尺寸相等的区域进行对换", arguments);
 411         return null;
 412       }
 413 
 414       let rowIdList = [];
 415       let changedData = [];
 416       const selectable = this._getColumns()
 417         .filter((c) => c.colDef.cellRenderer === "SsCellRender")
 418         .map((c) => c.colId);
 419 
 420       for (let i = 0; i + fY1 <= fY2; i++) {
 421         const fRowId = this._getRowId(i + fY1);
 422         const sRowId = this._getRowId(i + sY1);
 423 
 424         for (let j = 0; j + fX1 <= fX2; j++) {
 425           const fColId = this._getColId(j + fX1);
 426           const sColId = this._getColId(j + sX1);
 427           if (selectable.includes(fColId) && selectable.includes(sColId)) {
 428             const fData = this._getCellData(fRowId, fColId);
 429             const sData = this._getCellData(sRowId, sColId);
 430             this._setCellData(fRowId, fColId, sData);
 431             this._setCellData(sRowId, sColId, fData);
 432             rowIdList.push(fRowId);
 433             rowIdList.push(sRowId);
 434           }
 435         }
 436       }
 437       let noRepeatRowIdList = Array.from(new Set(rowIdList));
 438       noRepeatRowIdList.forEach((rowId) => {
 439         changedData.push(this._getRowData(rowId));
 440       });
 441       this.$emit("changed", changedData);
 442     },
 443     /**
 444      * 修改一个区域的数据
 445      */
 446     _setRangValue(range, data) {
 447       const selectable = this._getColumns()
 448         .filter((c) => c.colDef.cellRenderer === "SsCellRender")
 449         .map((c) => c.colId);
 450       const x1 = Math.min(range[0].colIndex, range[1].colIndex) || 0;
 451       const y1 = Math.min(range[0].rowIndex, range[1].rowIndex) || 0;
 452       const x2 = Math.max(range[0].colIndex, range[1].colIndex) || 0;
 453       const y2 = Math.max(range[0].rowIndex, range[1].rowIndex) || 0;
 454 
 455       let rowIdList = [];
 456       let changedData = [];
 457       this.$el.querySelectorAll("[row-index]").forEach((row) => {
 458         const rowIndex = parseInt(row.getAttribute("row-index"));
 459         const rowId = row.getAttribute("row-id");
 460 
 461         if (rowIndex < y1 || rowIndex > y2) {
 462         } else {
 463           row.querySelectorAll("[aria-colindex]").forEach((col) => {
 464             const colIndex = parseInt(col.getAttribute("aria-colindex"));
 465             const colId = col.getAttribute("col-id");
 466 
 467             if (
 468               colIndex >= x1 &&
 469               colIndex <= x2 &&
 470               selectable.includes(colId)
 471             ) {
 472               this._setCellData(rowId, colId, _.cloneDeep(data));
 473               rowIdList.push(rowId);
 474             }
 475           });
 476         }
 477       });
 478       let noRepeatRowIdList = Array.from(new Set(rowIdList));
 479       noRepeatRowIdList.forEach((rowId) => {
 480         changedData.push(this._getRowData(rowId));
 481       });
 482       this.$emit("changed", changedData);
 483     },
 484     _showDropCopyHolder(rowId, colId) {
 485       const params1 = {
 486         rowNodes: [this._getRowNodeByID(rowId)],
 487         columns: [colId],
 488       };
 489       const instances1 = this.gridApi.getCellRendererInstances(params1);
 490       instances1.forEach((instance) => {
 491         instance.isShowDropCopyHolder = true;
 492       });
 493     },
 494     _clearDropCopyHolder() {
 495       const instances = this.gridApi.getCellRendererInstances();
 496       instances.forEach((instance) => {
 497         instance.isShowDropCopyHolder = false;
 498       });
 499     },
 500     _clearSelectedCells(range) {
 501       if (!range) {
 502         this.$el
 503           .querySelectorAll(".ag-center-cols-container [row-index]")
 504           .forEach((row) => {
 505             row.querySelectorAll("[aria-colindex]").forEach((col) => {
 506               col.classList.remove(
 507                 "ag-cell-range-selected",
 508                 "ag-cell-range-selected-1",
 509                 "ag-cell-range-top",
 510                 "ag-cell-range-bottom",
 511                 "ag-cell-range-left",
 512                 "ag-cell-range-right"
 513               );
 514             });
 515           });
 516         return;
 517       }
 518 
 519       const x1 = Math.min(range[0].colIndex, range[1].colIndex) || 0;
 520       const y1 = Math.min(range[0].rowIndex, range[1].rowIndex) || 0;
 521       const x2 = Math.max(range[0].colIndex, range[1].colIndex) || 0;
 522       const y2 = Math.max(range[0].rowIndex, range[1].rowIndex) || 0;
 523 
 524       const selectable = this._getColumns()
 525         .filter((c) => c.colDef.cellRenderer === "SsCellRender")
 526         .map((c) => c.colId);
 527       let isStartPOS = (r, c) => {
 528         return range[0].rowId == r && range[0].colId == c;
 529       };
 530 
 531       for (let i = 0; i + y1 <= y2; i++) {
 532         const rowIndex = i + y1;
 533         const rowId = this._getRowId(rowIndex);
 534         const row = this.$el.querySelector(
 535           `.ag-center-cols-container [row-index="${rowIndex}"]`
 536         );
 537         for (let j = 0; j + x1 <= x2; j++) {
 538           const colIndex = j + x1;
 539           const colId = this._getColId(colIndex);
 540           if (selectable.includes(colId)) {
 541             const col = row.querySelector(`[aria-colindex="${colIndex}"]`);
 542             col.classList.remove(
 543               "ag-cell-range-selected",
 544               "ag-cell-range-selected-1",
 545               "ag-cell-range-top",
 546               "ag-cell-range-bottom",
 547               "ag-cell-range-left",
 548               "ag-cell-range-right"
 549             );
 550           }
 551         }
 552       }
 553     },
 554     /**
 555      * 选中一个区域
 556      */
 557     _selectRange(range) {
 558       const x1 = Math.min(range[0].colIndex, range[1].colIndex) || 0;
 559       const y1 = Math.min(range[0].rowIndex, range[1].rowIndex) || 0;
 560       const x2 = Math.max(range[0].colIndex, range[1].colIndex) || 0;
 561       const y2 = Math.max(range[0].rowIndex, range[1].rowIndex) || 0;
 562       const selectable = this._getColumns()
 563         .filter((c) => c.colDef.cellRenderer === "SsCellRender")
 564         .map((c) => c.colId);
 565       let isStartPOS = (r, c) => {
 566         return range[0].rowId == r && range[0].colId == c;
 567       };
 568 
 569       for (let i = 0; i + y1 <= y2; i++) {
 570         const rowIndex = i + y1;
 571         const rowId = this._getRowId(rowIndex);
 572         const row = this.$el.querySelector(
 573           `.ag-center-cols-container [row-index="${rowIndex}"]`
 574         );
 575         for (let j = 0; j + x1 <= x2; j++) {
 576           const colIndex = j + x1;
 577           const colId = this._getColId(colIndex);
 578           if (selectable.includes(colId)) {
 579             const col = row.querySelector(`[aria-colindex="${colIndex}"]`);
 580             //排除掉分组行
 581             if (col) {
 582               if (rowIndex == y1) {
 583                 col.classList.add("ag-cell-range-top");
 584               }
 585 
 586               if (rowIndex == y2) {
 587                 col.classList.add("ag-cell-range-bottom");
 588               }
 589 
 590               if (colIndex == x1) {
 591                 col.classList.add("ag-cell-range-left");
 592               }
 593 
 594               if (colIndex == x2) {
 595                 col.classList.add("ag-cell-range-right");
 596               }
 597 
 598               col.classList.add(
 599                 "ag-cell-range-selected",
 600                 "ag-cell-range-selected-1"
 601               );
 602             }
 603           }
 604         }
 605       }
 606 
 607       // this.$el.querySelectorAll("[row-index]").forEach((row) => {
 608       //   const rowIndex = parseInt(row.getAttribute("row-index"));
 609       //   const rowId = row.getAttribute("row-id");
 610       //   selecting = {};
 611 
 612       //   if (rowIndex < y1 || rowIndex > y2) {
 613       //     row.querySelectorAll("[aria-colindex]").forEach((col) => {
 614       //       const colId = col.getAttribute("col-id");
 615       //       col.classList.remove(
 616       //         "ag-cell-range-selected",
 617       //         "ag-cell-range-selected-1",
 618       //         "ag-cell-range-top",
 619       //         "ag-cell-range-bottom",
 620       //         "ag-cell-range-left",
 621       //         "ag-cell-range-right"
 622       //       );
 623 
 624       //       const params1 = {
 625       //         rowNodes: [this._getRowNodeByID(rowId)],
 626       //         columns: [colId],
 627       //       };
 628       //       const instances1 = this.gridApi.getCellRendererInstances(params1);
 629       //       instances1.forEach((instance) => {
 630       //         instance.isShowDropCopyHolder = false;
 631       //       });
 632       //     });
 633       //   } else {
 634       //     row.querySelectorAll("[aria-colindex]").forEach((col) => {
 635       //       const colIndex = parseInt(col.getAttribute("aria-colindex"));
 636       //       const colId = col.getAttribute("col-id");
 637       //       col.classList.remove(
 638       //         "ag-cell-range-selected",
 639       //         "ag-cell-range-selected-1",
 640       //         "ag-cell-range-top",
 641       //         "ag-cell-range-bottom",
 642       //         "ag-cell-range-left",
 643       //         "ag-cell-range-right"
 644       //       );
 645       //       if (
 646       //         colIndex >= x1 &&
 647       //         colIndex <= x2 &&
 648       //         selectable.includes(colId)
 649       //       ) {
 650       //         const params1 = {
 651       //           rowNodes: [this._getRowNodeByID(rowId)],
 652       //           columns: [colId],
 653       //         };
 654       //         const instances1 = this.gridApi.getCellRendererInstances(params1);
 655       //         instances1.forEach((instance) => {
 656       //           instance.isShowDropCopyHolder = isStartPOS(rowId, colId);
 657       //         });
 658 
 659       //         if (rowIndex == y1) {
 660       //           col.classList.add("ag-cell-range-top");
 661       //         }
 662 
 663       //         if (rowIndex == y2) {
 664       //           col.classList.add("ag-cell-range-bottom");
 665       //         }
 666 
 667       //         if (colIndex == x1) {
 668       //           col.classList.add("ag-cell-range-left");
 669       //         }
 670 
 671       //         if (colIndex == x2) {
 672       //           col.classList.add("ag-cell-range-right");
 673       //         }
 674 
 675       //         col.classList.add(
 676       //           "ag-cell-range-selected",
 677       //           "ag-cell-range-selected-1"
 678       //         );
 679       //       } else {
 680       //         const params1 = {
 681       //           rowNodes: [this._getRowNodeByID(rowId)],
 682       //           columns: [colId],
 683       //         };
 684       //         const instances1 = this.gridApi.getCellRendererInstances(params1);
 685       //         instances1.forEach((instance) => {
 686       //           instance.isShowDropCopyHolder = false;
 687       //         });
 688       //       }
 689       //     });
 690       //   }
 691       // });
 692 
 693       this.gridApi.refreshCells();
 694     },
 695     _selectAllRanges(ranges) {
 696       this._clearSelectedCells();
 697       // this._clearDropCopyHolder();
 698       ranges.forEach((range) => {
 699         this._selectRange(range);
 700       });
 701     },
 702     _selectCol(colId) {
 703       this.gridCtrl.api.deselectAll();
 704       const colIndex = this._getColumnIndex(colId);
 705       const firstRowId = this._getRowData("0").isRowGroup ? "1" : "0";
 706       const firstRowIndex = this._getRowIndex(firstRowId);
 707       const lastRowId = this.rowData.length - 1 + "";
 708       const lastRowIndex = this._getRowIndex(lastRowId);
 709 
 710       const range = [
 711         { colId, colIndex, rowId: firstRowId, rowIndex: firstRowIndex },
 712         { colId, colIndex, rowId: lastRowId, rowIndex: lastRowIndex },
 713       ];
 714 
 715       this._selectRange(range);
 716     },
 717     _selectRow(rowId) {
 718       const columns = this._getColumns();
 719       const rowIndex = this._getRowIndex(rowId);
 720       const firstColId = columns[0].colId;
 721       const firstColIndex = 1;
 722       const lastColId = columns[columns.length - 1].colId;
 723       const lastColIndex = columns.length;
 724 
 725       const range = [
 726         { rowId, rowIndex, colId: firstColId, colIndex: firstColIndex },
 727         { rowId, rowIndex, colId: lastColId, colIndex: lastColIndex },
 728       ];
 729 
 730       this._selectRange(range);
 731     },
 732     /**
 733      * 获取一个元素的位置
 734      * rowIndex,colIndex,rowId,colId
 735      */
 736     _getCellPos(element) {
 737       if (!element) {
 738         return null;
 739       }
 740 
 741       if (element instanceof HTMLElement) {
 742         let $agCell = $(element).is(".ag-cell")
 743           ? $(element)
 744           : $(element).closest(".ag-cell");
 745 
 746         if (!$agCell.length) {
 747           return null;
 748         }
 749 
 750         let $agRow = $agCell.closest(".ag-row");
 751         return {
 752           rowIndex: parseInt($agRow.attr("row-index")),
 753           rowId: $agRow.attr("row-id"),
 754           colIndex: $agCell.attr("aria-colindex"),
 755           colId: $agCell.attr("col-id"),
 756         };
 757       } else {
 758         return {
 759           rowIndex: element.rowIndex,
 760           rowId: element.node.id,
 761           colIndex: this._getColumnIndex(element.column.colId),
 762           colId: element.column.colId,
 763         };
 764       }
 765     },
 766     /**
 767      * 获取Row节点
 768      */
 769     _getRowNodeByID(id) {
 770       return this.gridApi.getRowNode(id);
 771     },
 772     /**
 773      * 获取Row数据
 774      */
 775     _getRowData(rowId) {
 776       return this._getRowNodeByID(rowId).data;
 777     },
 778     /**
 779      * 获取Cell数据
 780      */
 781     _getCellData(rowId, colId) {
 782       const data = this._getRowData(rowId);
 783       let field = this.columnDefs.find(
 784         (colDef) => colId === colDef.colId
 785       ).field;
 786       const shifts = data[field].shifts;
 787       return shifts;
 788     },
 789     /**
 790      * 设置Row数据
 791      */
 792     _setRowData(rowId, data) {
 793       this._getRowNodeByID(rowId).setData(data);
 794     },
 795     /**
 796      * 设置Cell数据
 797      */
 798     _setCellData(rowId, colId, value) {
 799       const data = this._getRowData(rowId);
 800       let field = this.columnDefs.find(
 801         (colDef) => colId === colDef.colId
 802       ).field;
 803 
 804       data[field].shifts = value;
 805       this._setRowData(rowId, data);
 806     },
 807     /**
 808      * 获取所有列定义
 809      */
 810     _getColumns() {
 811       return this.columnApi.getColumns() || [];
 812     },
 813     /**
 814      * 获取colIndex
 815      */
 816     _getColumnIndex(colId) {
 817       return this._getColumns().findIndex((c) => c.colId == colId) + 1;
 818     },
 819     _getRowIndex(rowId) {
 820       const row = this.gridApi.getModel().getRowNode(rowId);
 821       return row && row.rowIndex;
 822     },
 823     _getColId(colIndex) {
 824       const col = this._getColumns()[colIndex - 1];
 825       return col && col.colId;
 826     },
 827     _getRowId(rowIndex) {
 828       const row = this.$el.querySelector(`[row-index="${rowIndex}"]`);
 829       return row && row.getAttribute("row-id");
 830     },
 831 
 832     /**
 833      * 当点击列头时全选一整列
 834      * @param {*} event 点击事件对象
 835      * @param {*} params column 控制器
 836      */
 837     onSelectWholeColumn(event, params) {
 838       let { column } = params;
 839       this._selectCol(column.colId);
 840     },
 841 
 842     /**
 843      * 响应 contextmenu 事件
 844      * @param {*} event contextmenu 事件
 845      */
 846     onOpenContextMenu(event) {
 847       console.log("this.ctxMenuItems", this.ctxMenuItems);
 848       this.$refs.ctx.close();
 849       let row = this.getGridRow(event.target);
 850       let column = this.getGridColumn(event.target);
 851       if (!row || !column) {
 852         return;
 853       }
 854       let rowIndex = row.rowIndex;
 855       let colIndex = this._getColumnIndex(column.colId);
 856 
 857       if (row.data.isRowGroup || this.selectedRanges.length === 0) {
 858         return;
 859       } else {
 860         let range = this.selectedRanges[0];
 861         if (!range[0] || !range[1]) {
 862           return;
 863         }
 864         const x1 = Math.min(range[0].colIndex, range[1].colIndex) || 0;
 865         const y1 = Math.min(range[0].rowIndex, range[1].rowIndex) || 0;
 866         const x2 = Math.max(range[0].colIndex, range[1].colIndex) || 0;
 867         const y2 = Math.max(range[0].rowIndex, range[1].rowIndex) || 0;
 868         if (
 869           rowIndex >= y1 &&
 870           rowIndex <= y2 &&
 871           colIndex >= x1 &&
 872           colIndex <= x2
 873         ) {
 874           //可编辑区域显示右键菜单并且event.target必须在selecteRange选中区域内
 875           if (this.ctxMenuItems.length > 0) {
 876             this.$nextTick(() => {
 877               this.$refs.ctx.open(this.$event, this.ctxMenuItems, this.$el);
 878             });
 879           }
 880         }
 881       }
 882     },
 883     /**
 884      * 获取当前单元格所在的行
 885      * @param {*} el 单元格
 886      */
 887     getGridRow(el) {
 888       let agRow = el.closest(".ag-row") || el;
 889       if (!agRow.classList.contains("ag-row")) {
 890         return null;
 891       }
 892       let rowId = agRow.attributes["row-id"].value;
 893       let row = this.gridCtrl.api.getRowNode(+rowId);
 894       return row;
 895     },
 896     /**
 897      * 获取当前单元格所在的列
 898      * @param {*} el 单元格
 899      */
 900     getGridColumn(el) {
 901       let agCell = el.closest(".ag-cell") || el;
 902       if (!agCell.classList.contains("ag-cell")) {
 903         return null;
 904       }
 905       let colId = agCell.attributes["col-id"].value;
 906       let column = this.gridCtrl.columnApi.getColumn(colId);
 907       return column;
 908     },
 909 
 910     /**
 911      * contextmenu 打开后事件
 912      * @param {*} ctxMenu
 913      */
 914     onCtxOpened(ctxMenu) {
 915       this.resetCtxMenu();
 916     },
 917     /**
 918      * contextmenu 关闭后事件
 919      * @param {*} ctxMenu
 920      */
 921     onCtxClosed(ctxMenu) {
 922       // console.log("close");
 923     },
 924     /**
 925      * 重置 contextmenu
 926      */
 927     resetCtxMenu() {
 928       this.selectedCtxMenu = null;
 929       this.subMenuItems = [];
 930       this.showChildCtxMenu = false;
 931       this.ctxMenuBodyStyle.width = this.ctxMenuBodyWidth + "px";
 932     },
 933     /**
 934      * 点击菜单项操作
 935      */
 936     onCtxMenuItemClick(menuItem) {
 937       console.log("onCtxMenuItemClick", menuItem);
 938       this.selectedCtxMenu = menuItem;
 939       this.$emit("command", menuItem, this.selectedRanges);
 940     },
 941     /**
 942      * 鼠标停留菜单项,需显示二级菜单
 943      * @param {*} item 当前菜单项
 944      */
 945     onCtxMenuMouseEnter(item) {
 946       if (this.mouseEnterCtxMenuItem) {
 947         clearTimeout(this.mouseEnterCtxMenuItem);
 948         this.mouseEnterCtxMenuItem = null;
 949       }
 950       this.mouseEnterCtxMenuItem = setTimeout(() => {
 951         this.showChildCtxMenu = !!(item.children && item.children.length);
 952         if (this.showChildCtxMenu) {
 953           this.selectedCtxMenu = item;
 954           this.subMenuItems = item.children;
 955           this.ctxMenuBodyStyle.width = this.ctxMenuBodyWidth * 2 + "px";
 956         } else {
 957           this.resetCtxMenu();
 958         }
 959         this.mouseEnterCtxMenuItem = null;
 960       }, 500);
 961     },
 962     onCtxMenuMouseLeave(item) {},
 963 
 964     //提供以下几种api
 965     //选中一行
 966     selectRow(rowId) {
 967       console.log("selectRow", arguments);
 968       this._getRowNodeByID(rowId).setSelected(true, true);
 969     },
 970     //选中一列
 971     selectColumn(colId) {
 972       console.log("selectColumn", arguments);
 973       this._selectCol(colId);
 974     },
 975     //选中单元格
 976     selectCells(range) {
 977       console.log("selectCells", arguments);
 978       this._selectRange(range);
 979     },
 980     //行上移
 981     moveRowUp() {
 982       console.log("moveRowUp", arguments);
 983       let row = this.gridCtrl.api.getSelectedNodes();
 984       if (!row || !row.length) {
 985         Message.error("请选择一条数据");
 986         return;
 987       }
 988       row = row[0];
 989       if (row.data.isRowGroup) {
 990         return;
 991       }
 992       if (row.rowIndex === 0) {
 993         Message.error("已是最顶层");
 994         return;
 995       } else {
 996         let currentRowData = this._getRowData(row.id);
 997         let targetRowData = this._getRowData(+row.id - 1);
 998         if (targetRowData.isRowGroup) {
 999           Message.error("已是组内最顶层");
1000         } else {
1001           this._setRowData(+row.id - 1, currentRowData);
1002           this._setRowData(row.id, targetRowData);
1003           this._getRowNodeByID(+row.id - 1).setSelected(true, true);
1004           this.$emit("changed", [currentRowData, targetRowData]);
1005         }
1006       }
1007     },
1008     //行下移
1009     moveRowDown() {
1010       console.log("moveRowDown", arguments);
1011       let row = this.gridCtrl.api.getSelectedNodes();
1012       if (!row || !row.length) {
1013         Message.error("请选择一条数据");
1014         return;
1015       }
1016       row = row[0];
1017       if (row.data.isRowGroup) {
1018         return;
1019       }
1020       if (row.rowIndex === this.rowData.length - 1) {
1021         Message.error("已是最底层");
1022         return;
1023       } else {
1024         let currentRowData = this._getRowData(row.id);
1025         let targetRowData = this._getRowData(+row.id + 1);
1026         if (targetRowData.isRowGroup) {
1027           Message.error("已是组内最底层");
1028         } else {
1029           this._setRowData(+row.id + 1, currentRowData);
1030           this._setRowData(row.id, targetRowData);
1031           this._getRowNodeByID(+row.id + 1).setSelected(true, true);
1032           this.$emit("changed", [targetRowData, currentRowData]);
1033         }
1034       }
1035     },
1036     // 排班数据上移
1037     moveDaysUp() {
1038       console.log("moveDaysUp", arguments);
1039       let row = this.gridCtrl.api.getSelectedNodes();
1040       if (!row || !row.length) {
1041         Message.error("请选择一条数据");
1042         return;
1043       }
1044       row = row[0];
1045       if (row.data.isRowGroup) {
1046         return;
1047       }
1048       if (row.rowIndex === 0) {
1049         Message.error("已是最顶层");
1050         return;
1051       } else {
1052         let currentRowData = this._getRowData(row.id);
1053         let targetRowId = +row.id - 1;
1054         let targetRowData = this._getRowData(targetRowId);
1055         //分组行为第一行
1056         if (targetRowData.isRowGroup) {
1057           let targetIndex = this.rowData.findIndex((d) => {
1058             return d.groupNO === targetRowData.groupNO;
1059           });
1060           if (targetIndex === 0) {
1061             return;
1062           } else {
1063             targetRowId = +row.id - 2;
1064             targetRowData = this._getRowData(targetRowId);
1065           }
1066         }
1067         const fields = [
1068           "monday",
1069           "tuesday",
1070           "wednesday",
1071           "thursday",
1072           "friday",
1073           "saturday",
1074           "sunday",
1075         ];
1076         fields.forEach((field) => {
1077           let value = currentRowData[field];
1078           currentRowData[field] = targetRowData[field];
1079           targetRowData[field] = value;
1080         });
1081         this._setRowData(targetRowId, targetRowData);
1082         this._setRowData(row.id, currentRowData);
1083         this._getRowNodeByID(targetRowId).setSelected(true, true);
1084         this.$emit("changed", [targetRowData, currentRowData]);
1085       }
1086     },
1087     // 排班数据下移
1088     moveDaysDown() {
1089       console.log("moveRowDown", arguments);
1090       let row = this.gridCtrl.api.getSelectedNodes();
1091       if (!row || !row.length) {
1092         Message.error("请选择一条数据");
1093         return;
1094       }
1095       row = row[0];
1096       if (row.data.isRowGroup) {
1097         return;
1098       }
1099       if (row.rowIndex === this.rowData.length - 1) {
1100         Message.error("已是最底层");
1101         return;
1102       } else {
1103         let currentRowData = this._getRowData(row.id);
1104         let targetRowId = +row.id + 1;
1105         let targetRowData = this._getRowData(targetRowId);
1106         if (targetRowData.isRowGroup) {
1107           targetRowId = +row.id + 2;
1108           targetRowData = this._getRowData(targetRowId);
1109         }
1110 
1111         const fields = [
1112           "monday",
1113           "tuesday",
1114           "wednesday",
1115           "thursday",
1116           "friday",
1117           "saturday",
1118           "sunday",
1119         ];
1120         fields.forEach((field) => {
1121           let value = currentRowData[field];
1122           currentRowData[field] = targetRowData[field];
1123           targetRowData[field] = value;
1124         });
1125         this._setRowData(targetRowId, targetRowData);
1126         this._setRowData(row.id, currentRowData);
1127         this._getRowNodeByID(targetRowId).setSelected(true, true);
1128         this.$emit("changed", [currentRowData, targetRowData]);
1129       }
1130     },
1131     //交换两行排班数据
1132     exchangeDays() {
1133       console.log("exchangeDays", arguments);
1134       if (this.selectedRanges.length === 2) {
1135         this._swapRanges(this.selectedRanges[0], this.selectedRanges[1]);
1136       } else {
1137         return "必须选中两个相同大小的区域,且不能重叠。";
1138       }
1139     },
1140     // 获取单元格Cell数据
1141     getCellData(rowId, colId) {
1142       return this._getCellData(rowId, colId);
1143     },
1144     //设置单元格Cell数据
1145     setCellData(rowId, colId, value) {
1146       this._setCellData(rowId, colId, value);
1147     },
1148     //获取行Row数据
1149     getRowData(rowId) {
1150       return this._getRowData(rowId);
1151     },
1152     //设置区域为某个值
1153     setRangeValue(range, data) {
1154       this._setRangValue(range, data);
1155     },
1156   },
1157   components: {
1158     AgGridVue,
1159     SsCellRender,
1160     SsHeaderRender,
1161     SsRowHeaderRender,
1162     contextMenu,
1163   },
1164 };
1165 </script>
1166 <style lang="scss">
1167 .drag-copying {
1168   cursor: copy;
1169   .ag-cell.ag-cell-range-selected {
1170     background: lightpink !important;
1171   }
1172 }
1173 </style>
1174 <style lang="scss" scoped>
1175 .JheGridTable {
1176   width: 100%;
1177   height: 100%;
1178   background: #fff;
1179   ::v-deep .group-cell {
1180     background-color: #d7e7f8;
1181     font-weight: bold;
1182   }
1183   ::v-deep .ag-cell {
1184     padding: 3px 11px;
1185     font-size: 14px;
1186   }
1187 
1188   ::v-deep .ag-pinned-left-cols-container {
1189     .ag-cell {
1190       border-right: 1px solid #d9dcde !important;
1191     }
1192     .ag-cell-focus {
1193       border-right: 1px solid #0091ea !important;
1194     }
1195   }
1196   ::v-deep .ag-center-cols-container {
1197     .ag-cell {
1198       border-right: 1px solid #d9dcde;
1199     }
1200   }
1201   ::v-deep .ag-center-cols-container {
1202     .ag-theme-balham .ag-ltr .ag-cell {
1203       border-right: 1px solid #d9dcde !important;
1204     }
1205     .ag-cell-focus {
1206       border-right: 1px solid #0091ea !important;
1207     }
1208   }
1209   ::v-deep .ag-pinned-right-cols-container {
1210     .ag-cell {
1211       border-right: 1px solid #d9dcde !important;
1212     }
1213     .ag-cell-focus {
1214       border-right: 1px solid #0091ea !important;
1215     }
1216   }
1217 
1218   .ag-theme-balham .ag-cell-range-selected:not(.ag-cell-focus) {
1219     //border-right: 1px solid #d9dcde!important;
1220   }
1221   //.ag-cell-range-selected{border-right: 1px solid #0091ea}
1222   ::v-deep .ag-selection-checkbox:not(.ag-hidden) ~ .ag-cell-value:not(:empty) {
1223     margin: 0;
1224   }
1225 
1226   ::v-deep .ag-theme-balham .ag-header-cell::after,
1227   ::v-deep .ag-theme-balham .ag-header-group-cell::after {
1228     border-right: 1px solid rgba(189, 195, 199, 0.5);
1229     content: " ";
1230     height: 100%;
1231     margin-top: 0;
1232     position: absolute;
1233     text-indent: -2000px;
1234     top: 0;
1235   }
1236 
1237   ::v-deep .ag-header-cell-label {
1238     justify-content: center;
1239     text-align: center;
1240   }
1241   ::v-deep .ag-root-wrapper-body.ag-layout-normal {
1242     height: 100% !important;
1243   }
1244   ::v-deep .ctx-menu-body {
1245     display: flex;
1246     flex-flow: row nowrap;
1247     align-items: stretch;
1248     min-width: 160px;
1249   }
1250 }
1251 </style>
View Code

ss-cell-render.vue 内容如下:

  1 <!--
  2     Component: SsCellRender
  3     Description: 电子表格单元格渲染组建
  4 -->
  5 
  6 <template>
  7   <div :class="['SsCellRender', selectedClass]">
  8     <el-row v-if="shifts.length > 0">
  9       <el-col
 10         v-for="(s, i) in shifts"
 11         :key="i"
 12         :span="Math.floor(24 / shifts.length)"
 13         :style="s"
 14         ><!--{{cellName(s.id)}}-->{{ s.shiftName }}</el-col
 15       >
 16     </el-row>
 17     <el-row v-else>
 18       <el-col></el-col>
 19     </el-row>
 20     <div class="ss-cell-mask"></div>
 21     <div
 22       v-show="isShowDropCopyHolder"
 23       class="DragCopyHolder"
 24       @mousedown="onMouseHold"
 25     >
 26       <!-- <Icon type="md-add" color="white" /> -->
 27       <i class="el-icon-plus" style="color: white"></i>
 28     </div>
 29   </div>
 30 </template>
 31 <script>
 32 export default {
 33   name: "SsCellRender",
 34   data() {
 35     return {
 36       data: {},
 37       rowIndex: null,
 38       colId: null,
 39       rowId: null,
 40       context: null,
 41       isShowDropCopyHolder: false,
 42       value: "",
 43       insideParams: null,
 44       shiftName: "",
 45     };
 46   },
 47   computed: {
 48     // 班次背景色方法
 49     styles() {
 50       return this.shiftIdInfo;
 51     },
 52 
 53     selectedClass() {
 54       return {
 55         // "ag-cell-range-selected": this.isSelecting,
 56         "is-drag-copying": this.isDragCopying,
 57       };
 58     },
 59     shifts() {
 60       return this.value.shifts;
 61     },
 62   },
 63   watch: {},
 64   methods: {
 65     initialize(params) {
 66       this.value = params.value;
 67       this.data = params.data;
 68       // this.data.rowHeight = this.shifts.length * 26;
 69       this.rowIndex = params.rowIndex;
 70       this.rowId = params.node.id;
 71       this.colId = params.column.colId;
 72       this.params.eGridCell.style["padding"] = 0;
 73       // this.params.eGridCell.style["padding-right"] = 0;
 74       this.context = params.context;
 75       // console.log(this.params, this);
 76     },
 77     cellName(id) {
 78       let shiftName = "";
 79       this.shifts.forEach((e) => {
 80         if (this.shiftIdInfo[id]) {
 81           if (e.days !== null && e.days !== undefined) {
 82             shiftName = this.shiftIdInfo[id].name + "-" + e.days;
 83           } else {
 84             shiftName = this.shiftIdInfo[id].name;
 85           }
 86         }
 87       });
 88       return shiftName;
 89     },
 90     onMouseHold() {
 91       this.context.isDragCopying = true;
 92     },
 93   },
 94   beforeUpdate() {
 95     this.initialize(this.params);
 96   },
 97   created() {
 98     this.initialize(this.params);
 99   },
100   mounted() {},
101   beforeDestroy() {},
102 };
103 </script>
104 
105 <style lang="scss" scoped>
106 .SsCellRender {
107   padding: 5px 11px;
108   //height: 100%;
109   position: relative;
110   cursor: cell;
111 
112   .ss-cell-mask {
113     position: absolute;
114     top: 0;
115     left: 0;
116     right: 0;
117     bottom: 0;
118     background: #0091ea;
119     opacity: 0;
120   }
121   ::v-deep .ag-cell-range-selected .ss-cell-mask {
122     opacity: 0.3;
123   }
124 
125   .DragCopyHolder {
126     position: absolute;
127     right: 0px;
128     bottom: 0px;
129     font-size: 10px;
130     background: red;
131     width: 12px;
132     height: 12px;
133     border: 0;
134     cursor: copy;
135   }
136   .DragCopyHolder:hover {
137     border: 1px solid whitesmoke;
138     width: 14px;
139     height: 14px;
140   }
141   .DragCopyHolder i {
142     position: absolute;
143     left: 1px;
144     top: 1px;
145   }
146 
147   ::v-deep .el-col {
148     height: 22px;
149     overflow: hidden;
150     line-height: 22px;
151   }
152   ::v-deep .el-col:first-child {
153     border-radius: 11px 0 0 11px;
154   }
155   ::v-deep .el-col:last-child {
156     border-radius: 0 11px 11px 0;
157   }
158   ::v-deep .el-col:first-child:last-child {
159     border-radius: 11px;
160   }
161 }
162 </style>
View Code

ss-header-render.vue内容如下:

  1 <!--
  2     Component: SsHeaderRender
  3     Description: 电子表格的自定义Header
  4 -->
  5 <template>
  6   <div
  7     class="SsHeaderRender ag-cell-label-container"
  8     role="presentation"
  9     :style="style"
 10   >
 11     <!-- <span ref="eMenu" class="ag-header-icon ag-header-cell-menu-button"></span> -->
 12 
 13     <div
 14       ref="eLabel"
 15       class="ag-header-cell-label"
 16       role="presentation"
 17       style="flex-wrap: wrap"
 18       @click="onSortChanged"
 19     >
 20       <!-- <div
 21         ref="eText"
 22         class="ag-header-cell-text"
 23         role="columnheader"
 24         style="width:100%;border-bottom:1px solid #d9dcde"
 25       >{{title}}</div>
 26       <div ref="eText" class="ag-header-cell-text" role="columnheader">{{subtitle}}</div>-->
 27       <div ref="eText" class="ag-header-cell-text" role="columnheader">
 28         {{ title }} {{ subtitle }}
 29       </div>
 30 
 31       <!-- <span ref="eFilter" class="ag-header-icon ag-filter-icon"></span> -->
 32       <!-- <span v-if="isSortAscending" ref="eSortOrder" class="ag-header-icon ag-sort-order"></span> -->
 33       <span
 34         v-if="isSortAscending"
 35         ref="eSortAsc"
 36         class="ag-header-icon ag-sort-ascending-icon"
 37       >
 38         <span class="ag-icon ag-icon-asc" unselectable="on"></span>
 39       </span>
 40       <span
 41         v-if="isSortDescending"
 42         ref="eSortDesc"
 43         class="ag-header-icon ag-sort-descending-icon"
 44       >
 45         <span class="ag-icon ag-icon-desc" unselectable="on"></span>
 46       </span>
 47       <span
 48         v-if="params.enableMenu"
 49         ref="eMenu"
 50         class="ag-header-icon ag-header-cell-menu-button"
 51         aria-hidden="true"
 52         @click.stop="onMenuClicked"
 53       >
 54         <span class="ag-icon ag-icon-menu" unselectable="on"></span>
 55       </span>
 56     </div>
 57   </div>
 58 </template>
 59 <script>
 60 export default {
 61   name: "SsHeaderRender",
 62   // components: {},
 63   // directives: {},
 64   // filters: {},
 65   data() {
 66     return {
 67       style: {},
 68     };
 69   },
 70   // props: [],
 71   computed: {
 72     title() {
 73       if (
 74         this.params.displayName === "周六" ||
 75         this.params.displayName === "周日"
 76       ) {
 77         this.style = {
 78           color: "#CC0001",
 79         };
 80       } else {
 81         this.style = {};
 82       }
 83       return this.params.displayName;
 84     },
 85     subtitle() {
 86       return this.params.subtitle;
 87     },
 88     isSortAscending() {
 89       return this.params.enableSorting && this.params.column.isSortAscending();
 90     },
 91     isSortDescending() {
 92       return this.params.enableSorting && this.params.column.isSortDescending();
 93     },
 94   },
 95   // watch: {},
 96   methods: {
 97     onMenuClicked() {
 98       this.params.showColumnMenu(this.$refs.eMenu);
 99     },
100     onSortChanged(event) {
101       this.params.enableSorting && this.params.progressSort();
102       this.params.onColumnClick &&
103         this.params.onColumnClick(event, this.params);
104       // console.log(
105       //   "onSortChanged",
106       //   this.params,
107       //   this.params.api.getDisplayedRowCount()
108       // );
109     },
110   },
111 };
112 </script>
113 <style lang="scss" scoped>
114 .ag-header-cell .SsHeaderRender:hover {
115   .ag-header-icon.ag-header-cell-menu-button {
116     display: inline;
117     opacity: 1 !important;
118     transition: opacity 0.2s ease 0s, border 0.2s ease 0s;
119   }
120 }
121 .SsHeaderRender {
122   .ag-header-icon.ag-header-cell-menu-button {
123     display: none;
124     opacity: 0 !important;
125     transition: opacity 0.2s ease 0s, border 0.2s ease 0s;
126   }
127 }
128 </style>
View Code

ss-row-header-render.vue内容如下:

 1 <!--
 2     Component: SsRowHeaderRender
 3     Description: 电子表格行头的Render
 4 -->
 5 <template>
 6   <div :class="['SsRowHeaderRender']" @mousedown="selectRow">
 7     <span>{{ rowIndex + 1 }}</span>
 8   </div>
 9 </template>
10 <script>
11 export default {
12   name: "SsRowHeaderRender",
13   data() {
14     return {
15       columnDefines: null,
16     };
17   },
18   computed: {
19     rowIndex() {
20       return this.params.rowIndex;
21     },
22 
23     value() {
24       return +this.params.value;
25     },
26   },
27   watch: {},
28   methods: {
29     initialize(params) {
30       this.columnDefines = params.columnApi.getColumns();
31       this.params.eGridCell.style["padding-left"] = 0;
32       this.params.eGridCell.style["padding-right"] = 0;
33     },
34     selectRow() {
35       this.params.node.setSelected(true, true);
36     },
37   },
38   beforeUpdate() {
39     this.initialize(this.params);
40   },
41   created() {
42     this.initialize(this.params);
43   },
44   mounted() {},
45   beforeDestroy() {},
46 };
47 </script>
48 
49 <style lang="scss" scoped>
50 .SsRowHeaderRender {
51   & {
52     padding-left: 11px;
53     padding-right: 11px;
54     height: 100%;
55   }
56 }
57 
58 .ag-selection-checkbox {
59   padding-left: 11px;
60 }
61 </style>
View Code

ctx-menu.vue内容如下:

  1 <template>
  2   <div
  3     :id="id"
  4     ref="contextMenu"
  5     :style="ctxStyle"
  6     class="ctx-menu-container"
  7     @click.stop
  8     @contextmenu.stop
  9   >
 10     <div style="background-color: transparent" class="ctx open">
 11       <ul
 12         role="menu"
 13         class="ctx-menu"
 14         :class="{
 15           'ctx-menu-right': align === 'right',
 16           'ctx-menu-left': align === 'left',
 17         }"
 18       >
 19         <slot />
 20       </ul>
 21     </div>
 22   </div>
 23 </template>
 24 
 25 <script>
 26 import { createBodyClickListener } from "./body-click-listener";
 27 
 28 // const EVENT_LIST = ['click', 'contextmenu', 'keydown']
 29 
 30 export default {
 31   name: "ContextMenu",
 32   props: {
 33     id: {
 34       type: String,
 35       default: "default-ctx",
 36     },
 37   },
 38   data() {
 39     return {
 40       locals: {},
 41       align: "left",
 42       ctxTop: 0,
 43       ctxLeft: 0,
 44       ctxVisible: false,
 45       bodyClickListener: createBodyClickListener((e) => {
 46         const isOpen = !!this.ctxVisible;
 47         const outsideClick = isOpen && !this.$el.contains(e.target);
 48 
 49         if (outsideClick) {
 50           if (e.which !== 1) {
 51             e.preventDefault();
 52             e.stopPropagation();
 53             return false;
 54           } else {
 55             this.ctxVisible = false;
 56             this.$emit("ctx-cancel", this.locals);
 57             e.stopPropagation();
 58           }
 59         } else {
 60           this.ctxVisible = false;
 61           this.$emit("ctx-close", this.locals);
 62         }
 63       }),
 64     };
 65   },
 66   computed: {
 67     ctxStyle() {
 68       return {
 69         display: this.ctxVisible ? "block" : "none",
 70         top: (this.ctxTop || 0) + "px",
 71         left: (this.ctxLeft || 0) + "px",
 72       };
 73     },
 74   },
 75   watch: {
 76     ctxVisible(newVal, oldVal) {
 77       if (oldVal === true && newVal === false) {
 78         this.bodyClickListener.stop((e) => {
 79           // this.locals = {}
 80         });
 81       }
 82     },
 83   },
 84   methods: {
 85     /*
 86      * this function handles some cross-browser compat issues
 87      * thanks to https://github.com/callmenick/Custom-Context-Menu
 88      */
 89     setPositionFromEvent(e, data, parentPosition) {
 90       e = e || window.event;
 91 
 92       const scrollingElement =
 93         document.scrollingElement || document.documentElement;
 94 
 95       if (e.pageX || e.pageY) {
 96         this.ctxLeft = e.pageX;
 97         this.ctxTop = e.pageY - scrollingElement.scrollTop;
 98       } else if (e.clientX || e.clientY) {
 99         this.ctxLeft = e.clientX + scrollingElement.scrollLeft;
100         this.ctxTop = e.clientY + scrollingElement.scrollTop;
101       }
102       this.ctxTop = this.ctxTop - parentPosition.top;
103       this.ctxLeft = this.ctxLeft - parentPosition.left;
104 
105       this.$nextTick(() => {
106         const menu = this.$el;
107         const minHeight =
108           (menu.style.minHeight || menu.style.height).replace("px", "") || 32;
109         const minWidth =
110           (menu.style.minWidth || menu.style.width).replace("px", "") || 32;
111         const scrollHeight = menu.scrollHeight || minHeight;
112         let scrollWidth = menu.scrollWidth || minWidth;
113         const findSubItem = data.find((item) => {
114           return item.children && item.children.length > 0;
115         }); // 存在二级菜单
116         if (findSubItem) {
117           scrollWidth = menu.scrollWidth * 2 || minWidth;
118         }
119         const largestHeight =
120           window.innerHeight - scrollHeight - parentPosition.top - 25;
121         const largestWidth =
122           window.innerWidth - scrollWidth - parentPosition.left - 25;
123         if (this.ctxTop > largestHeight) this.ctxTop = largestHeight;
124         if (this.ctxLeft > largestWidth) this.ctxLeft = largestWidth;
125       });
126       return e;
127     },
128     getElementLeftAndTop(element) {
129       var left = element.offsetLeft; // 当前元素左边距
130       var top = element.offsetTop; // 当前元素上边距
131       var parent = element.offsetParent; // 当前元素的父级元素
132       while (parent !== null) {
133         left += parent.offsetLeft; // 累加左边距
134         top += parent.offsetTop; // 累加上边距
135         parent = parent.offsetParent; // 依次获取父元素
136       }
137       return { left, top };
138     },
139 
140     open(e, data, parentElement) {
141       if (this.ctxVisible) this.ctxVisible = false;
142       this.ctxVisible = true;
143       this.$emit("ctx-open", (this.locals = data || {}));
144       const parentPosition = this.getElementLeftAndTop(parentElement);
145       this.setPositionFromEvent(e, data, parentPosition);
146       this.$el.setAttribute("tab-index", -1);
147       this.bodyClickListener.start();
148       return this;
149     },
150 
151     close() {
152       this.ctxVisible = false;
153     },
154   },
155 };
156 </script>
157 
158 <style lang="scss" scoped>
159 .ctx {
160   position: relative;
161 }
162 
163 .ctx-menu {
164   position: absolute;
165   top: 100%;
166   left: 0;
167   z-index: 1000;
168   display: none;
169   float: left;
170   min-width: 160px;
171   padding: 5px 0;
172   margin: 2px 0 0;
173   font-size: 0.9rem;
174   color: #373a3c;
175   text-align: left;
176   list-style: none;
177   background-color: #fff;
178   -webkit-background-clip: padding-box;
179   background-clip: padding-box;
180   border: 1px solid rgba(0, 0, 0, 0.15);
181   border-radius: 0.25rem;
182   -moz-box-shadow: 0 0 5px #ccc;
183   -webkit-box-shadow: 0 0 5px #ccc;
184   box-shadow: 0 0 5px #ccc;
185 }
186 
187 .ctx-divider {
188   height: 1px;
189   margin: 0.5rem 0;
190   overflow: hidden;
191   background-color: #e5e5e5;
192 }
193 
194 .ctx-group {
195   width: 100%;
196 }
197 .ctx-item {
198   display: block;
199   padding: 7px 16px;
200   clear: both;
201   font-weight: 14px;
202   line-height: normal;
203   color: #373a3c;
204   text-align: inherit;
205   white-space: nowrap;
206   background: none;
207   border: 0;
208   cursor: pointer;
209   display: flex;
210   justify-content: space-between;
211 }
212 
213 .ctx-item:focus,
214 .ctx-item:hover {
215   color: #2b2d2f;
216   text-decoration: none;
217   background-color: #f5f5f5;
218   cursor: normal;
219 }
220 
221 .ctx-item.active,
222 .ctx-item.active:focus,
223 .ctx-item.active:hover {
224   color: #fff;
225   text-decoration: none;
226   background-color: #0275d8;
227   outline: 0;
228 }
229 
230 .ctx-item.disabled,
231 .ctx-item.disabled:focus,
232 .ctx-item.disabled:hover {
233   color: #818a91;
234 }
235 
236 .ctx-item.disabled:focus,
237 .ctx-item.disabled:hover {
238   text-decoration: none;
239   cursor: not-allowed;
240   background-color: transparent;
241   background-image: none;
242   filter: "progid:DXImageTransform.Microsoft.gradient(enabled = false)";
243 }
244 
245 .open > .ctx-menu {
246   display: block;
247 }
248 
249 .open > a {
250   outline: 0;
251 }
252 
253 .ctx-menu-right {
254   right: 0;
255   left: auto;
256 }
257 
258 .ctx-menu-left {
259   right: auto;
260   left: 0;
261 }
262 
263 .ctx-header {
264   display: block;
265   padding: 3px 20px;
266   font-size: 0.9rem;
267   line-height: 1.5;
268   color: #818a91;
269   white-space: nowrap;
270 }
271 
272 .ctx-backdrop {
273   position: fixed;
274   top: 0;
275   right: 0;
276   bottom: 0;
277   left: 0;
278   z-index: 990;
279 }
280 
281 .pull-right > .ctx-menu {
282   right: 0;
283   left: auto;
284 }
285 
286 .ctx-menu-container {
287   position: fixed;
288   padding: 0;
289   border: 1px solid #bbb;
290   background-color: whitesmoke;
291   z-index: 99999;
292   box-shadow: 0 5px 11px 0 rgba(0, 0, 0, 0.18), 0 4px 15px 0 rgba(0, 0, 0, 0.15);
293 }
294 </style>
View Code

body-click-listener.js内容如下:

 1 /**
 2  * When listening for an outside click, we set useCapture = true.
 3  * This way, we can prevent other click listeners from firing when performing the 'click-out'.
 4  * If useCapture is set to false, the handlers fire backwards
 5  */
 6 export const createBodyClickListener = function(fn) {
 7   let isListening = false;
 8 
 9   /* === public api ========================================== */
10   return {
11     get isListening() {
12       return isListening;
13     },
14 
15     start(cb) {
16       window.addEventListener("click", _onclick, true);
17       window.addEventListener("keyup", _onescape, true);
18       isListening = true;
19       if (typeof cb === "function") cb();
20     },
21 
22     stop(cb) {
23       window.removeEventListener("click", _onclick, true);
24       window.removeEventListener("keyup", _onescape, true);
25       isListening = false;
26       if (typeof cb === "function") cb();
27     }
28   };
29 
30   /* === private helpers ===================================== */
31   function _onclick(e) {
32     e.preventDefault();
33     if (typeof fn === "function") fn(e);
34   }
35 
36   function _onescape(e) {
37     if (e.keyCode === 27) _onclick(e);
38   }
39 };
View Code

utils下tools.js内容如下:

 1 /**
 2  * 获得原时间前后几天的日期
 3  * @param {*} src 原时间
 4  * @param {*} offset 偏移量,正负天数
 5  */
 6 export const offsetDate = (src, offset) => {
 7   let dest = new Date(src);
 8 
 9   let timespan = dest.setDate(dest.getDate() + offset);
10   dest = new Date(timespan);
11 
12   return dest;
13 };
14 
15 /**
16  * 获得原日期所在周的所有日期
17  * @param {*} src 原日期
18  */
19 export const getOneWeekDate = (src) => {
20   let source = new Date(src);
21   let keys = [
22     "sunday",
23     "monday",
24     "tuesday",
25     "wednesday",
26     "thursday",
27     "friday",
28     "saturday",
29     "sunday",
30   ];
31   let mapWeekDays = {};
32 
33   let date = source;
34   let wd = date.getDay();
35   mapWeekDays[keys[wd]] = date;
36 
37   for (wd = date.getDay() - 1; wd >= 1; wd--) {
38     date = offsetDate(date, -1);
39     mapWeekDays[keys[wd]] = date;
40   }
41   date = source;
42   for (wd = source.getDay() + 1; wd <= 8; wd++) {
43     date = offsetDate(date, +1);
44     mapWeekDays[keys[wd]] = date;
45   }
46 
47   return mapWeekDays;
48 };
View Code

父组件的用法示例:

   1 <template>
   2   <div style="width: 100%; height: 500px">
   3     <div>
   4       <jhe-button @click="initData">加载(2022-12-25)周数据</jhe-button>
   5       <jhe-button @click="handleSelectRow">选中第二行</jhe-button>
   6       <jhe-button @click="handleSelectColumn">选中周一列</jhe-button>
   7       <jhe-button @click="handleSelectCells">选中单元格</jhe-button>
   8       <jhe-button @click="handleMoveRowUp">行上移</jhe-button>
   9       <jhe-button @click="handleMoveRowDown">行下移</jhe-button>
  10       <jhe-button @click="handleMoveDaysUp">排班数据上移</jhe-button>
  11       <jhe-button @click="handleMoveDaysDown">排班数据下移</jhe-button>
  12       <jhe-button @click="handleExchangeDays">班次对换</jhe-button>
  13       <jhe-button @click="handleGetCellData"
  14         >获取单元格数据(第二行,周二列)</jhe-button
  15       >
  16       <jhe-button @click="handleSetCellData"
  17         >设置单元格数据(第三行,周四列)</jhe-button
  18       >
  19       <jhe-button @click="handleGetRowData">获取行数据(第五行)</jhe-button>
  20       <jhe-button @click="handleSetRangeValue">设置区域值</jhe-button>
  21     </div>
  22     <jhe-grid-table
  23       :startDate="startDate"
  24       :columns="columns"
  25       :rowData="rowData"
  26       :headerHeight="headerHeight"
  27       :ctxMenuItems="ctxMenuItems"
  28       @init="onInit"
  29       @loaded="onLoaded"
  30       @changed="onChanged"
  31       @cellClicked="onCellClicked"
  32       @command="onCommand"
  33     ></jhe-grid-table>
  34   </div>
  35 </template>
  36 <script>
  37 export default {
  38   name: "DemoJheGridTable",
  39   data() {
  40     return {
  41       //需要显示的数据
  42       rowData: [],
  43       headerHeight: 30,
  44       columns: [],
  45       jheGridApi: null,
  46       startDate: null,
  47       targetDate: new Date("2022-12-05"),
  48       ctxMenuItems: [], //右键菜单项
  49       cellClickedPositon: null,
  50       cellClickdSchedule: null,
  51       changedRowData: null,
  52       selectedRanges: null,
  53     };
  54   },
  55   created() {
  56     this.startDate = this.getStartDateByTargetDate(this.targetDate);
  57     this.columns = [
  58       {
  59         colId: 1,
  60         headerName: "组号",
  61         field: "groupNO",
  62         minWidth: 60,
  63         //pinned: "left",
  64         sortable: false,
  65         filter: false,
  66         colSpan: (params) => {
  67           if (params.data.isRowGroup === 1) {
  68             return this.columns.length;
  69           } else {
  70             return 1;
  71           }
  72         },
  73         cellClassRules: {
  74           "group-cell": "data.isRowGroup === 1",
  75         },
  76       },
  77       {
  78         colId: 2,
  79         headerName: "姓名",
  80         field: "userName",
  81         minWidth: 80,
  82         //pinned: "left",
  83         sortable: false,
  84         filter: false,
  85       },
  86       {
  87         colId: 3,
  88         headerName: "层级",
  89         field: "level",
  90         minWidth: 60,
  91         //pinned: "left",
  92         sortable: false,
  93         filter: false,
  94       },
  95       {
  96         colId: 4,
  97         headerName: "岗位",
  98         field: "post",
  99         minWidth: 80,
 100         //pinned: "left",
 101         sortable: false,
 102         filter: false,
 103       },
 104       {
 105         colId: 5,
 106         headerName: "职称",
 107         field: "titleName",
 108         minWidth: 90,
 109         //pinned: "left",
 110         sortable: false,
 111         filter: false,
 112       },
 113       {
 114         colId: "w1",
 115         headerName: "周一",
 116         field: "monday",
 117         minWidth: 90,
 118         sortable: false,
 119         filter: false,
 120         selectable: true,
 121       },
 122       {
 123         colId: "w2",
 124         headerName: "周二",
 125         field: "tuesday",
 126         minWidth: 90,
 127         sortable: false,
 128         filter: false,
 129         selectable: true,
 130       },
 131       {
 132         colId: "w3",
 133         headerName: "周三",
 134         field: "wednesday",
 135         minWidth: 90,
 136         sortable: false,
 137         filter: false,
 138         selectable: true,
 139       },
 140       {
 141         colId: "w4",
 142         headerName: "周四",
 143         field: "thursday",
 144         minWidth: 90,
 145         sortable: false,
 146         filter: false,
 147         selectable: true,
 148       },
 149       {
 150         colId: "w5",
 151         headerName: "周五",
 152         field: "friday",
 153         minWidth: 90,
 154         sortable: false,
 155         filter: false,
 156         selectable: true,
 157       },
 158       {
 159         colId: "w6",
 160         headerName: "周六",
 161         field: "saturday",
 162         minWidth: 90,
 163         sortable: false,
 164         filter: false,
 165         selectable: true,
 166       },
 167       {
 168         colId: "w7",
 169         headerName: "周日",
 170         field: "sunday",
 171         minWidth: 90,
 172         sortable: false,
 173         filter: false,
 174         selectable: true,
 175       },
 176       {
 177         colId: 13,
 178         headerName: "公休",
 179         //field: "dayOff",
 180         minWidth: 65,
 181         //pinned: "right",
 182         sortable: false,
 183         filter: false,
 184         hide: false,
 185         valueGetter: (params) => {
 186           let keys = [
 187             "monday",
 188             "tuesday",
 189             "wednesday",
 190             "thursday",
 191             "friday",
 192             "saturday",
 193             "sunday",
 194           ];
 195           let allDays = 0;
 196           keys.forEach((key) => {
 197             params.data[key].shifts.forEach((s) => {
 198               allDays = allDays + s.days;
 199             });
 200           });
 201           return allDays;
 202         },
 203       },
 204       {
 205         colId: 14,
 206         headerName: "管床",
 207         field: "beds",
 208         minWidth: 70,
 209         sortable: false,
 210         //pinned: "right",
 211         filter: false,
 212         hide: true,
 213       },
 214     ];
 215     let data = [
 216       {
 217         isRowGroup: 1,
 218         groupNO: "一组",
 219       },
 220       {
 221         id: "220",
 222         userName: "孙丽",
 223         employeeNO: "220",
 224         beds: "4,5,6",
 225         level: "0",
 226         memo: null,
 227         displayOrder: 1000,
 228         groupNO: "一组",
 229         durations: 0,
 230         dayOff: 15,
 231         monday: {
 232           id: "73098",
 233           date: "2022-12-05",
 234           shifts: [],
 235         },
 236         tuesday: {
 237           id: "73099",
 238           date: "2022-12-06",
 239           shifts: [],
 240         },
 241         wednesday: {
 242           id: "73100",
 243           date: "2022-12-07",
 244           shifts: [],
 245         },
 246         thursday: {
 247           id: "73101",
 248           date: "2022-12-08",
 249           shifts: [],
 250         },
 251         friday: {
 252           id: "73102",
 253           date: "2022-12-09",
 254           shifts: [],
 255         },
 256         saturday: {
 257           id: "73103",
 258           date: "2022-12-10",
 259           shifts: [],
 260         },
 261         sunday: {
 262           id: "73104",
 263           date: "2022-12-11",
 264           shifts: [],
 265         },
 266         post: "5",
 267         title: "",
 268         titleName: "",
 269       },
 270       {
 271         id: "21",
 272         userName: "刘世卿",
 273         employeeNO: "21",
 274         beds: null,
 275         level: "0",
 276         memo: null,
 277         displayOrder: 1001,
 278         groupNO: "一组",
 279         durations: 46800000,
 280         dayOff: 15,
 281         monday: {
 282           id: "73091",
 283           date: "2022-12-05",
 284           shifts: [],
 285         },
 286         tuesday: {
 287           id: "73092",
 288           date: "2022-12-06",
 289           shifts: [
 290             {
 291               id: 2860,
 292               shiftName: "观P2",
 293               background: "#2D8CF0",
 294               color: "#FFFFFF",
 295               days: 1,
 296               totalDays: null,
 297             },
 298           ],
 299         },
 300         wednesday: {
 301           id: "73093",
 302           date: "2022-12-07",
 303           shifts: [
 304             {
 305               id: 2860,
 306               shiftName: "观P2",
 307               background: "#2D8CF0",
 308               color: "#FFFFFF",
 309               days: 1,
 310               totalDays: null,
 311             },
 312           ],
 313         },
 314         thursday: {
 315           id: "73094",
 316           date: "2022-12-08",
 317           shifts: [],
 318         },
 319         friday: {
 320           id: "73095",
 321           date: "2022-12-09",
 322           shifts: [],
 323         },
 324         saturday: {
 325           id: "73096",
 326           date: "2022-12-10",
 327           shifts: [],
 328         },
 329         sunday: {
 330           id: "73097",
 331           date: "2022-12-11",
 332           shifts: [],
 333         },
 334         post: "0",
 335         title: "",
 336         titleName: "",
 337       },
 338       {
 339         id: "354",
 340         userName: "孙娉",
 341         employeeNO: "354",
 342         beds: null,
 343         level: "0",
 344         memo: null,
 345         displayOrder: 1002,
 346         groupNO: "一组",
 347         durations: 0,
 348         dayOff: 15,
 349         monday: {
 350           id: "73105",
 351           date: "2022-12-05",
 352           shifts: [],
 353         },
 354         tuesday: {
 355           id: "73106",
 356           date: "2022-12-06",
 357           shifts: [],
 358         },
 359         wednesday: {
 360           id: "73107",
 361           date: "2022-12-07",
 362           shifts: [],
 363         },
 364         thursday: {
 365           id: "73108",
 366           date: "2022-12-08",
 367           shifts: [],
 368         },
 369         friday: {
 370           id: "73109",
 371           date: "2022-12-09",
 372           shifts: [],
 373         },
 374         saturday: {
 375           id: "73110",
 376           date: "2022-12-10",
 377           shifts: [],
 378         },
 379         sunday: {
 380           id: "73111",
 381           date: "2022-12-11",
 382           shifts: [],
 383         },
 384         post: "0",
 385         title: "1",
 386         titleName: "初级(护士)",
 387       },
 388       {
 389         id: "695",
 390         userName: "陈伟萍",
 391         employeeNO: "695",
 392         beds: null,
 393         level: "0",
 394         memo: null,
 395         displayOrder: 1003,
 396         groupNO: "一组",
 397         durations: 23400000,
 398         dayOff: 15,
 399         monday: {
 400           id: "73084",
 401           date: "2022-12-05",
 402           shifts: [],
 403         },
 404         tuesday: {
 405           id: "73085",
 406           date: "2022-12-06",
 407           shifts: [
 408             {
 409               id: 2860,
 410               shiftName: "观P2",
 411               background: "#2D8CF0",
 412               color: "#FFFFFF",
 413               days: 1,
 414               totalDays: null,
 415             },
 416           ],
 417         },
 418         wednesday: {
 419           id: "73086",
 420           date: "2022-12-07",
 421           shifts: [],
 422         },
 423         thursday: {
 424           id: "73087",
 425           date: "2022-12-08",
 426           shifts: [],
 427         },
 428         friday: {
 429           id: "73088",
 430           date: "2022-12-09",
 431           shifts: [],
 432         },
 433         saturday: {
 434           id: "73089",
 435           date: "2022-12-10",
 436           shifts: [],
 437         },
 438         sunday: {
 439           id: "73090",
 440           date: "2022-12-11",
 441           shifts: [],
 442         },
 443         post: "0",
 444         title: "",
 445         titleName: "",
 446       },
 447       {
 448         id: "133",
 449         userName: "纪丽鑫",
 450         employeeNO: "133",
 451         beds: "1111",
 452         level: "3",
 453         memo: null,
 454         displayOrder: 1005,
 455         groupNO: "一组",
 456         durations: 46800000,
 457         dayOff: 15,
 458         monday: {
 459           id: "73147",
 460           date: "2022-12-05",
 461           shifts: [],
 462         },
 463         tuesday: {
 464           id: "73148",
 465           date: "2022-12-06",
 466           shifts: [
 467             {
 468               id: 1000,
 469               shiftName: "抢N",
 470               background: "#EA1A1A",
 471               color: "black",
 472               days: 2,
 473               totalDays: null,
 474             },
 475           ],
 476         },
 477         wednesday: {
 478           id: "73149",
 479           date: "2022-12-07",
 480           shifts: [
 481             {
 482               id: 2860,
 483               shiftName: "观P2",
 484               background: "#2D8CF0",
 485               color: "#FFFFFF",
 486               days: 1,
 487               totalDays: null,
 488             },
 489           ],
 490         },
 491         thursday: {
 492           id: "73150",
 493           date: "2022-12-08",
 494           shifts: [],
 495         },
 496         friday: {
 497           id: "73151",
 498           date: "2022-12-09",
 499           shifts: [],
 500         },
 501         saturday: {
 502           id: "73152",
 503           date: "2022-12-10",
 504           shifts: [],
 505         },
 506         sunday: {
 507           id: "73153",
 508           date: "2022-12-11",
 509           shifts: [],
 510         },
 511         post: "4",
 512         title: "",
 513         titleName: "",
 514       },
 515       {
 516         id: "110110",
 517         userName: "童谣",
 518         employeeNO: "110110",
 519         beds: null,
 520         level: "1",
 521         memo: null,
 522         displayOrder: 1007,
 523         groupNO: "一组",
 524         durations: 46800000,
 525         dayOff: 15,
 526         monday: {
 527           id: "73182",
 528           date: "2022-12-05",
 529           shifts: [],
 530         },
 531         tuesday: {
 532           id: "73183",
 533           date: "2022-12-06",
 534           shifts: [
 535             {
 536               id: 2860,
 537               shiftName: "观P2",
 538               background: "#2D8CF0",
 539               color: "#FFFFFF",
 540               days: 1,
 541               totalDays: null,
 542             },
 543           ],
 544         },
 545         wednesday: {
 546           id: "73184",
 547           date: "2022-12-07",
 548           shifts: [
 549             {
 550               id: 2860,
 551               shiftName: "观P2",
 552               background: "#2D8CF0",
 553               color: "#FFFFFF",
 554               days: 1,
 555               totalDays: null,
 556             },
 557           ],
 558         },
 559         thursday: {
 560           id: "73185",
 561           date: "2022-12-08",
 562           shifts: [],
 563         },
 564         friday: {
 565           id: "73186",
 566           date: "2022-12-09",
 567           shifts: [],
 568         },
 569         saturday: {
 570           id: "73187",
 571           date: "2022-12-10",
 572           shifts: [],
 573         },
 574         sunday: {
 575           id: "73188",
 576           date: "2022-12-11",
 577           shifts: [],
 578         },
 579         post: "6",
 580         title: "1",
 581         titleName: "初级(护士)",
 582       },
 583       {
 584         id: "134",
 585         userName: "辛琤琤",
 586         employeeNO: "134",
 587         beds: "7,8,9",
 588         level: "2",
 589         memo: null,
 590         displayOrder: 1008,
 591         groupNO: "一组",
 592         durations: 0,
 593         dayOff: 15,
 594         monday: {
 595           id: "73077",
 596           date: "2022-12-05",
 597           shifts: [],
 598         },
 599         tuesday: {
 600           id: "73078",
 601           date: "2022-12-06",
 602           shifts: [],
 603         },
 604         wednesday: {
 605           id: "73079",
 606           date: "2022-12-07",
 607           shifts: [],
 608         },
 609         thursday: {
 610           id: "73080",
 611           date: "2022-12-08",
 612           shifts: [],
 613         },
 614         friday: {
 615           id: "73081",
 616           date: "2022-12-09",
 617           shifts: [],
 618         },
 619         saturday: {
 620           id: "73082",
 621           date: "2022-12-10",
 622           shifts: [],
 623         },
 624         sunday: {
 625           id: "73083",
 626           date: "2022-12-11",
 627           shifts: [],
 628         },
 629         post: "3",
 630         title: "",
 631         titleName: "",
 632       },
 633       {
 634         isRowGroup: 1,
 635         groupNO: "二组",
 636       },
 637       {
 638         id: "389",
 639         userName: "张小婧",
 640         employeeNO: "389",
 641         beds: null,
 642         level: "0",
 643         memo: null,
 644         displayOrder: 2005,
 645         groupNO: "二组",
 646         durations: 0,
 647         dayOff: 15,
 648         monday: {
 649           id: "73035",
 650           date: "2022-12-05",
 651           shifts: [],
 652         },
 653         tuesday: {
 654           id: "73036",
 655           date: "2022-12-06",
 656           shifts: [],
 657         },
 658         wednesday: {
 659           id: "73037",
 660           date: "2022-12-07",
 661           shifts: [],
 662         },
 663         thursday: {
 664           id: "73038",
 665           date: "2022-12-08",
 666           shifts: [],
 667         },
 668         friday: {
 669           id: "73039",
 670           date: "2022-12-09",
 671           shifts: [],
 672         },
 673         saturday: {
 674           id: "73040",
 675           date: "2022-12-10",
 676           shifts: [],
 677         },
 678         sunday: {
 679           id: "73041",
 680           date: "2022-12-11",
 681           shifts: [],
 682         },
 683         post: "0",
 684         title: "",
 685         titleName: "",
 686       },
 687       {
 688         id: "394",
 689         userName: "刘利慧",
 690         employeeNO: "394",
 691         beds: null,
 692         level: "0",
 693         memo: null,
 694         displayOrder: 2010,
 695         groupNO: "二组",
 696         durations: 0,
 697         dayOff: 15,
 698         monday: {
 699           id: "73042",
 700           date: "2022-12-05",
 701           shifts: [],
 702         },
 703         tuesday: {
 704           id: "73043",
 705           date: "2022-12-06",
 706           shifts: [],
 707         },
 708         wednesday: {
 709           id: "73044",
 710           date: "2022-12-07",
 711           shifts: [],
 712         },
 713         thursday: {
 714           id: "73045",
 715           date: "2022-12-08",
 716           shifts: [],
 717         },
 718         friday: {
 719           id: "73046",
 720           date: "2022-12-09",
 721           shifts: [],
 722         },
 723         saturday: {
 724           id: "73047",
 725           date: "2022-12-10",
 726           shifts: [],
 727         },
 728         sunday: {
 729           id: "73048",
 730           date: "2022-12-11",
 731           shifts: [],
 732         },
 733         post: "0",
 734         title: "",
 735         titleName: "",
 736       },
 737       {
 738         id: "437",
 739         userName: "闫丽平",
 740         employeeNO: "437",
 741         beds: null,
 742         level: "0",
 743         memo: null,
 744         displayOrder: 2012,
 745         groupNO: "二组",
 746         durations: 0,
 747         dayOff: 15,
 748         monday: {
 749           id: "73063",
 750           date: "2022-12-05",
 751           shifts: [],
 752         },
 753         tuesday: {
 754           id: "73064",
 755           date: "2022-12-06",
 756           shifts: [],
 757         },
 758         wednesday: {
 759           id: "73065",
 760           date: "2022-12-07",
 761           shifts: [],
 762         },
 763         thursday: {
 764           id: "73066",
 765           date: "2022-12-08",
 766           shifts: [],
 767         },
 768         friday: {
 769           id: "73067",
 770           date: "2022-12-09",
 771           shifts: [],
 772         },
 773         saturday: {
 774           id: "73068",
 775           date: "2022-12-10",
 776           shifts: [],
 777         },
 778         sunday: {
 779           id: "73069",
 780           date: "2022-12-11",
 781           shifts: [],
 782         },
 783         post: "0",
 784         title: "",
 785         titleName: "",
 786       },
 787     ];
 788     this.rowData = [...data];
 789     this.ctxMenuItems = [
 790       {
 791         id: "copy",
 792         title: "复制",
 793       },
 794       {
 795         id: "paste",
 796         title: "粘贴",
 797       },
 798       {
 799         id: "clear",
 800         title: "清除",
 801       },
 802       {
 803         id: "exchange",
 804         title: "对换",
 805       },
 806       {
 807         id: "P",
 808         title: "P",
 809         children: [
 810           {
 811             id: "观P1",
 812             title: "观P1",
 813             background: "#f27979",
 814             color: "#000",
 815           },
 816           {
 817             id: "观P2",
 818             title: "观P2",
 819             background: "#f27979",
 820             color: "#83e4ec",
 821           },
 822         ],
 823       },
 824       {
 825         id: "X",
 826         title: "X",
 827         background: "#98F279",
 828         color: "#FFD8D7",
 829       },
 830       {
 831         id: "其他",
 832         title: "其他",
 833         children: [
 834           {
 835             id: "抢N",
 836             title: "抢N",
 837             background: "#EA1A1A",
 838             color: "black",
 839           },
 840         ],
 841       },
 842     ];
 843   },
 844   computed: {},
 845   methods: {
 846     initData() {
 847       this.startDate = this.getStartDateByTargetDate(new Date("2022-12-25"));
 848       let data = [
 849         {
 850           isRowGroup: 1,
 851           groupNO: "一组",
 852         },
 853         {
 854           id: "220",
 855           userName: "孙丽11",
 856           employeeNO: "220",
 857           beds: "4,5,6",
 858           level: "0",
 859           memo: null,
 860           displayOrder: 1000,
 861           groupNO: "一组",
 862           durations: 0,
 863           dayOff: 15,
 864           monday: {
 865             id: "73098",
 866             date: "2022-12-19",
 867             shifts: [
 868               {
 869                 id: 1000,
 870                 shiftName: "抢N",
 871                 background: "#EA1A1A",
 872                 color: "black",
 873                 days: 2,
 874                 totalDays: null,
 875               },
 876             ],
 877           },
 878           tuesday: {
 879             id: "73099",
 880             date: "2022-12-20",
 881             shifts: [],
 882           },
 883           wednesday: {
 884             id: "73100",
 885             date: "2022-12-21",
 886             shifts: [],
 887           },
 888           thursday: {
 889             id: "73101",
 890             date: "2022-12-22",
 891             shifts: [],
 892           },
 893           friday: {
 894             id: "73102",
 895             date: "2022-12-23",
 896             shifts: [],
 897           },
 898           saturday: {
 899             id: "73103",
 900             date: "2022-12-24",
 901             shifts: [],
 902           },
 903           sunday: {
 904             id: "73104",
 905             date: "2022-12-25",
 906             shifts: [],
 907           },
 908           post: "5",
 909           title: "",
 910           titleName: "",
 911         },
 912         {
 913           id: "21",
 914           userName: "刘世卿",
 915           employeeNO: "21",
 916           beds: null,
 917           level: "0",
 918           memo: null,
 919           displayOrder: 1001,
 920           groupNO: "一组",
 921           durations: 46800000,
 922           dayOff: 15,
 923           monday: {
 924             id: "73091",
 925             date: "2022-12-19",
 926             shifts: [],
 927           },
 928           tuesday: {
 929             id: "73092",
 930             date: "2022-12-20",
 931             shifts: [
 932               {
 933                 id: 2860,
 934                 shiftName: "观P2",
 935                 background: "#2D8CF0",
 936                 color: "#FFFFFF",
 937                 days: 1,
 938                 totalDays: null,
 939               },
 940             ],
 941           },
 942           wednesday: {
 943             id: "73093",
 944             date: "2022-12-21",
 945             shifts: [
 946               {
 947                 id: 2860,
 948                 shiftName: "观P2",
 949                 background: "#2D8CF0",
 950                 color: "#FFFFFF",
 951                 days: 1,
 952                 totalDays: null,
 953               },
 954             ],
 955           },
 956           thursday: {
 957             id: "73094",
 958             date: "2022-12-22",
 959             shifts: [],
 960           },
 961           friday: {
 962             id: "73095",
 963             date: "2022-12-23",
 964             shifts: [],
 965           },
 966           saturday: {
 967             id: "73096",
 968             date: "2022-12-24",
 969             shifts: [],
 970           },
 971           sunday: {
 972             id: "73097",
 973             date: "2022-12-25",
 974             shifts: [],
 975           },
 976           post: "0",
 977           title: "",
 978           titleName: "",
 979         },
 980         {
 981           id: "354",
 982           userName: "孙娉",
 983           employeeNO: "354",
 984           beds: null,
 985           level: "0",
 986           memo: null,
 987           displayOrder: 1002,
 988           groupNO: "一组",
 989           durations: 0,
 990           dayOff: 15,
 991           monday: {
 992             id: "73105",
 993             date: "2022-12-19",
 994             shifts: [],
 995           },
 996           tuesday: {
 997             id: "73106",
 998             date: "2022-12-20",
 999             shifts: [],
1000           },
1001           wednesday: {
1002             id: "73107",
1003             date: "2022-12-21",
1004             shifts: [],
1005           },
1006           thursday: {
1007             id: "73108",
1008             date: "2022-12-22",
1009             shifts: [],
1010           },
1011           friday: {
1012             id: "73109",
1013             date: "2022-12-23",
1014             shifts: [],
1015           },
1016           saturday: {
1017             id: "73110",
1018             date: "2022-12-24",
1019             shifts: [],
1020           },
1021           sunday: {
1022             id: "73111",
1023             date: "2022-12-25",
1024             shifts: [],
1025           },
1026           post: "0",
1027           title: "1",
1028           titleName: "初级(护士)",
1029         },
1030         {
1031           id: "695",
1032           userName: "陈伟萍",
1033           employeeNO: "695",
1034           beds: null,
1035           level: "0",
1036           memo: null,
1037           displayOrder: 1003,
1038           groupNO: "一组",
1039           durations: 23400000,
1040           dayOff: 15,
1041           monday: {
1042             id: "73084",
1043             date: "2022-12-19",
1044             shifts: [],
1045           },
1046           tuesday: {
1047             id: "73085",
1048             date: "2022-12-20",
1049             shifts: [
1050               {
1051                 id: 2860,
1052                 shiftName: "观P2",
1053                 background: "#2D8CF0",
1054                 color: "#FFFFFF",
1055                 days: 1,
1056                 totalDays: null,
1057               },
1058             ],
1059           },
1060           wednesday: {
1061             id: "73086",
1062             date: "2022-12-21",
1063             shifts: [],
1064           },
1065           thursday: {
1066             id: "73087",
1067             date: "2022-12-22",
1068             shifts: [],
1069           },
1070           friday: {
1071             id: "73088",
1072             date: "2022-12-23",
1073             shifts: [],
1074           },
1075           saturday: {
1076             id: "73089",
1077             date: "2022-12-24",
1078             shifts: [],
1079           },
1080           sunday: {
1081             id: "73090",
1082             date: "2022-12-25",
1083             shifts: [],
1084           },
1085           post: "0",
1086           title: "",
1087           titleName: "",
1088         },
1089         {
1090           id: "133",
1091           userName: "纪丽鑫",
1092           employeeNO: "133",
1093           beds: "1111",
1094           level: "3",
1095           memo: null,
1096           displayOrder: 1005,
1097           groupNO: "一组",
1098           durations: 46800000,
1099           dayOff: 15,
1100           monday: {
1101             id: "73147",
1102             date: "2022-12-19",
1103             shifts: [],
1104           },
1105           tuesday: {
1106             id: "73148",
1107             date: "2022-12-20",
1108             shifts: [
1109               {
1110                 id: 1000,
1111                 shiftName: "抢N",
1112                 background: "#EA1A1A",
1113                 color: "black",
1114                 days: 2,
1115                 totalDays: null,
1116               },
1117             ],
1118           },
1119           wednesday: {
1120             id: "73149",
1121             date: "2022-12-21",
1122             shifts: [
1123               {
1124                 id: 2860,
1125                 shiftName: "观P2",
1126                 background: "#2D8CF0",
1127                 color: "#FFFFFF",
1128                 days: 1,
1129                 totalDays: null,
1130               },
1131             ],
1132           },
1133           thursday: {
1134             id: "73150",
1135             date: "2022-12-22",
1136             shifts: [],
1137           },
1138           friday: {
1139             id: "73151",
1140             date: "2022-12-23",
1141             shifts: [],
1142           },
1143           saturday: {
1144             id: "73152",
1145             date: "2022-12-24",
1146             shifts: [],
1147           },
1148           sunday: {
1149             id: "73153",
1150             date: "2022-12-25",
1151             shifts: [],
1152           },
1153           post: "4",
1154           title: "",
1155           titleName: "",
1156         },
1157         {
1158           id: "110110",
1159           userName: "童谣",
1160           employeeNO: "110110",
1161           beds: null,
1162           level: "1",
1163           memo: null,
1164           displayOrder: 1007,
1165           groupNO: "一组",
1166           durations: 46800000,
1167           dayOff: 15,
1168           monday: {
1169             id: "73182",
1170             date: "2022-12-19",
1171             shifts: [],
1172           },
1173           tuesday: {
1174             id: "73183",
1175             date: "2022-12-20",
1176             shifts: [
1177               {
1178                 id: 2860,
1179                 shiftName: "观P2",
1180                 background: "#2D8CF0",
1181                 color: "#FFFFFF",
1182                 days: 1,
1183                 totalDays: null,
1184               },
1185             ],
1186           },
1187           wednesday: {
1188             id: "73184",
1189             date: "2022-12-21",
1190             shifts: [
1191               {
1192                 id: 2860,
1193                 shiftName: "观P2",
1194                 background: "#2D8CF0",
1195                 color: "#FFFFFF",
1196                 days: 1,
1197                 totalDays: null,
1198               },
1199             ],
1200           },
1201           thursday: {
1202             id: "73185",
1203             date: "2022-12-22",
1204             shifts: [],
1205           },
1206           friday: {
1207             id: "73186",
1208             date: "2022-12-23",
1209             shifts: [],
1210           },
1211           saturday: {
1212             id: "73187",
1213             date: "2022-12-24",
1214             shifts: [],
1215           },
1216           sunday: {
1217             id: "73188",
1218             date: "2022-12-25",
1219             shifts: [],
1220           },
1221           post: "6",
1222           title: "1",
1223           titleName: "初级(护士)",
1224         },
1225         {
1226           id: "134",
1227           userName: "辛琤琤",
1228           employeeNO: "134",
1229           beds: "7,8,9",
1230           level: "2",
1231           memo: null,
1232           displayOrder: 1008,
1233           groupNO: "一组",
1234           durations: 0,
1235           dayOff: 15,
1236           monday: {
1237             id: "73077",
1238             date: "2022-12-19",
1239             shifts: [],
1240           },
1241           tuesday: {
1242             id: "73078",
1243             date: "2022-12-20",
1244             shifts: [],
1245           },
1246           wednesday: {
1247             id: "73079",
1248             date: "2022-12-21",
1249             shifts: [],
1250           },
1251           thursday: {
1252             id: "73080",
1253             date: "2022-12-22",
1254             shifts: [],
1255           },
1256           friday: {
1257             id: "73081",
1258             date: "2022-12-23",
1259             shifts: [],
1260           },
1261           saturday: {
1262             id: "73082",
1263             date: "2022-12-24",
1264             shifts: [],
1265           },
1266           sunday: {
1267             id: "73083",
1268             date: "2022-12-25",
1269             shifts: [],
1270           },
1271           post: "3",
1272           title: "",
1273           titleName: "",
1274         },
1275         {
1276           isRowGroup: 1,
1277           groupNO: "二组",
1278         },
1279         {
1280           id: "389",
1281           userName: "张小婧",
1282           employeeNO: "389",
1283           beds: null,
1284           level: "0",
1285           memo: null,
1286           displayOrder: 2005,
1287           groupNO: "二组",
1288           durations: 0,
1289           dayOff: 15,
1290           monday: {
1291             id: "73035",
1292             date: "2022-12-19",
1293             shifts: [],
1294           },
1295           tuesday: {
1296             id: "73036",
1297             date: "2022-12-20",
1298             shifts: [],
1299           },
1300           wednesday: {
1301             id: "73037",
1302             date: "2022-12-21",
1303             shifts: [],
1304           },
1305           thursday: {
1306             id: "73038",
1307             date: "2022-12-22",
1308             shifts: [],
1309           },
1310           friday: {
1311             id: "73039",
1312             date: "2022-12-23",
1313             shifts: [],
1314           },
1315           saturday: {
1316             id: "73040",
1317             date: "2022-12-24",
1318             shifts: [],
1319           },
1320           sunday: {
1321             id: "73041",
1322             date: "2022-12-25",
1323             shifts: [],
1324           },
1325           post: "0",
1326           title: "",
1327           titleName: "",
1328         },
1329         {
1330           id: "394",
1331           userName: "刘利慧",
1332           employeeNO: "394",
1333           beds: null,
1334           level: "0",
1335           memo: null,
1336           displayOrder: 2010,
1337           groupNO: "二组",
1338           durations: 0,
1339           dayOff: 15,
1340           monday: {
1341             id: "73042",
1342             date: "2022-12-19",
1343             shifts: [],
1344           },
1345           tuesday: {
1346             id: "73043",
1347             date: "2022-12-20",
1348             shifts: [],
1349           },
1350           wednesday: {
1351             id: "73044",
1352             date: "2022-12-21",
1353             shifts: [],
1354           },
1355           thursday: {
1356             id: "73045",
1357             date: "2022-12-22",
1358             shifts: [],
1359           },
1360           friday: {
1361             id: "73046",
1362             date: "2022-12-23",
1363             shifts: [],
1364           },
1365           saturday: {
1366             id: "73047",
1367             date: "2022-12-24",
1368             shifts: [],
1369           },
1370           sunday: {
1371             id: "73048",
1372             date: "2022-12-25",
1373             shifts: [],
1374           },
1375           post: "0",
1376           title: "",
1377           titleName: "",
1378         },
1379         {
1380           id: "437",
1381           userName: "闫丽平",
1382           employeeNO: "437",
1383           beds: null,
1384           level: "0",
1385           memo: null,
1386           displayOrder: 2012,
1387           groupNO: "二组",
1388           durations: 0,
1389           dayOff: 15,
1390           monday: {
1391             id: "73063",
1392             date: "2022-12-19",
1393             shifts: [],
1394           },
1395           tuesday: {
1396             id: "73064",
1397             date: "2022-12-20",
1398             shifts: [],
1399           },
1400           wednesday: {
1401             id: "73065",
1402             date: "2022-12-21",
1403             shifts: [],
1404           },
1405           thursday: {
1406             id: "73066",
1407             date: "2022-12-22",
1408             shifts: [],
1409           },
1410           friday: {
1411             id: "73067",
1412             date: "2022-12-23",
1413             shifts: [],
1414           },
1415           saturday: {
1416             id: "73068",
1417             date: "2022-12-24",
1418             shifts: [],
1419           },
1420           sunday: {
1421             id: "73069",
1422             date: "2022-12-25",
1423             shifts: [],
1424           },
1425           post: "0",
1426           title: "",
1427           titleName: "",
1428         },
1429       ];
1430       this.rowData = [...data];
1431     },
1432     getStartDateByTargetDate(targetDate) {
1433       let dayList = [1, 2, 3, 4, 5, 6, 0];
1434       let day = targetDate.getDay();
1435       let index = dayList.findIndex((d) => d === day); //代表当前天距离周一有几天
1436       let startDate = new Date(
1437         targetDate.getTime() - index * 24 * 60 * 60 * 1000
1438       ); //计算出周一是哪一天
1439       return startDate;
1440     },
1441     //ag-grid创建完成后执行的事件
1442     onInit(api) {
1443       this.jheGridApi = api;
1444     },
1445     onLoaded(params) {
1446       console.log("onLoaded", params);
1447     },
1448     onChanged(data) {
1449       console.log("onChanged", data);
1450       this.changedRowData = data;
1451     },
1452     onCellClicked(positon, data) {
1453       console.log("onCellClicked", positon, data);
1454       this.cellClickedPositon = positon;
1455       this.cellClickdSchedule = data;
1456     },
1457     //点击菜单项触发
1458     onCommand(menuItem, selectedRanges) {
1459       console.log("onCommand", menuItem, selectedRanges);
1460       this.selectedRanges = selectedRanges;
1461       switch (menuItem.id) {
1462         // 复制选中的数据
1463         case "copy":
1464           //to do something...
1465           break;
1466         // 粘贴复制的数据到指定区域
1467         case "paste":
1468           //to do something...
1469           break;
1470         // 清除选中区域的数据
1471         case "clear":
1472           //to do something...
1473           break;
1474         case "exchange":
1475           //to do something...
1476           break;
1477         default:
1478           //to do something...
1479           break;
1480       }
1481     },
1482     //提供的api有如下几种:
1483     //选中一行
1484     handleSelectRow() {
1485       this.jheGridApi.selectRow("1");
1486     },
1487     //选中一列
1488     handleSelectColumn() {
1489       this.jheGridApi.selectColumn("w1");
1490     },
1491     //选中单元格
1492     handleSelectCells() {
1493       let range = [
1494         { rowId: "1", rowIndex: 1, colId: "w1", colIndex: 7 },
1495         { rowId: "2", rowIndex: 2, colId: "w2", colIndex: 8 },
1496       ];
1497       this.jheGridApi.selectCells(range);
1498     },
1499     //行上移
1500     handleMoveRowUp() {
1501       this.jheGridApi.moveRowUp();
1502     },
1503     //行下移
1504     handleMoveRowDown() {
1505       this.jheGridApi.moveRowDown();
1506     },
1507     //排班数据上移
1508     handleMoveDaysUp() {
1509       this.jheGridApi.moveDaysUp();
1510     },
1511     //排班数据下移
1512     handleMoveDaysDown() {
1513       this.jheGridApi.moveDaysDown();
1514     },
1515     //班次对换
1516     handleExchangeDays() {
1517       this.jheGridApi.exchangeDays();
1518     },
1519     //获取单元格数据
1520     handleGetCellData() {
1521       let data = this.jheGridApi.getCellData("1", "w2");
1522       console.log("handleGetCellData", data);
1523     },
1524     //设置单元格数据
1525     handleSetCellData() {
1526       let data = this.jheGridApi.getCellData("4", "w2");
1527       this.jheGridApi.setCellData("2", "w4", data);
1528     },
1529     //获取行数据
1530     handleGetRowData() {
1531       let data = this.jheGridApi.getRowData("4");
1532       console.log("handleGetRowData", data);
1533     },
1534     //设置区域为某个值
1535     handleSetRangeValue() {
1536       let range = [
1537         { rowId: "0", rowIndex: 0, colId: "w1", colIndex: 7 },
1538         { rowId: "1", rowIndex: 1, colId: "w2", colIndex: 8 },
1539       ];
1540       let data = this.jheGridApi.getCellData("4", "w2");
1541       this.jheGridApi.setRangeValue(range, data);
1542     },
1543   },
1544 };
1545 </script>
1546 <style lang="scss">
1547 .group-cell {
1548   background-color: #d7e7f8 !important;
1549   font-weight: bold !important;
1550   text-align: left !important;
1551   padding-left: 36px !important;
1552 }
1553 </style>
View Code

效果图如下:

 

posted @ 2022-12-23 17:57  yuwenjing  阅读(1117)  评论(0编辑  收藏  举报