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> 41 <context- menu 42 id="testingctx" 43 ref="ctx" 44 @ctx-open="onCtxOpened" 45 @ctx-cancel="resetCtxMenu" 46 @ctx-close="onCtxClosed" 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)" 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" 71 < div 72 class="ctx-item" 73 :key="'sub_' + index" 74 v- for ="(item, index) in subMenuItems" 75 @click="onCtxMenuItemClick(item)" 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" ; 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]; 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 } 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 }, 308 onCellMouseDown(event) { 309 if (event.event.button != 0 ) { 310 // 不是鼠标左键 311 return ; 312 } 314 this .isDraging = true ; 315 console.log("onCellMouseDown" , arguments); 317 if (! event.event.ctrlKey) { 318 this .selectedRanges = []; 319 this ._clearSelectedCells(); 320 } 322 this ._clearDropCopyHolder(); 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 ; 331 if (event.button != 0 ) { 332 // 不是鼠标左键 333 return ; 334 } 336 console.log("onCellMouseUp", arguments, this .gridApi); 337 const end = this ._getCellPos(event.target); 338 if (end == null ) { 339 // 不是单元格 340 return ; 341 } 343 const range = this .selectedRanges.pop(); 344 if (! range) { 345 return ; 346 } 347 range[1] = end; 349 this .selectedRanges.push(range); 350 this ._selectRange(range); 351 this .gridApi.clearFocusedCell(); 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 } 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); 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 }, 393 _swapRanges(range1, range2) { 394 if (range1 == null || range2 == null ) { 395 console.error("只能对两个尺寸相等的区域进行对换" , arguments); 396 return null ; 397 } 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 ; 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 ; 409 if (fX2 - fX1 != sX2 - sX1 || fY2 - fY1 != sY2 - sY1) { 410 console.error("只能对两个尺寸相等的区域进行对换" , arguments); 411 return null ; 412 } 414 let rowIdList = []; 415 let changedData = []; 416 const selectable = this ._getColumns() 417 .filter((c) => c.colDef.cellRenderer === "SsCellRender" ) 418 .map((c) => c.colId); 420 for (let i = 0; i + fY1 <= fY2; i++ ) { 421 const fRowId = this ._getRowId(i + fY1); 422 const sRowId = this ._getRowId(i + sY1); 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 ; 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" ); 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" ); 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 } 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 ; 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 }; 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 }; 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 } 586 if (rowIndex == y2) { 587 col.classList.add("ag-cell-range-bottom" ); 588 } 590 if (colIndex == x1) { 591 col.classList.add("ag-cell-range-left" ); 592 } 594 if (colIndex == x2) { 595 col.classList.add("ag-cell-range-right" ); 596 } 598 col.classList.add( 599 "ag-cell-range-selected" , 600 "ag-cell-range-selected-1" 601 ); 602 } 603 } 604 } 605 } 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 = {}; 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 // ); 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 // }); 659 // if (rowIndex == y1) { 660 // col.classList.add("ag-cell-range-top"); 661 // } 663 // if (rowIndex == y2) { 664 // col.classList.add("ag-cell-range-bottom"); 665 // } 667 // if (colIndex == x1) { 668 // col.classList.add("ag-cell-range-left"); 669 // } 671 // if (colIndex == x2) { 672 // col.classList.add("ag-cell-range-right"); 673 // } 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 // }); 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); 710 const range = [ 711 { colId, colIndex, rowId: firstRowId, rowIndex: firstRowIndex }, 712 { colId, colIndex, rowId: lastRowId, rowIndex: lastRowIndex }, 713 ]; 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; 725 const range = [ 726 { rowId, rowIndex, colId: firstColId, colIndex: firstColIndex }, 727 { rowId, rowIndex, colId: lastColId, colIndex: lastColIndex }, 728 ]; 730 this ._selectRange(range); 731 }, 732 /* * 733 * 获取一个元素的位置 734 * rowIndex,colIndex,rowId,colId 735 */ 736 _getCellPos(element) { 737 if (! element) { 738 return null ; 739 } 741 if (element instanceof HTMLElement) { 742 let $agCell = $(element).is(".ag-cell" ) 743 ? $(element) 744 : $(element).closest(".ag-cell" ); 746 if (! $agCell.length) { 747 return null ; 748 } 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; 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 }, 832 /* * 833 * 当点击列头时全选一整列 834 * @param {*} event 点击事件对象 835 * @param {*} params column 控制器 836 */ 837 onSelectWholeColumn(event, params) { 838 let { column } = params; 839 this ._selectCol(column.colId); 840 }, 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); 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 }, 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) {}, 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 } 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 } 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 } 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 } 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 } 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: 电子表格单元格渲染组建
  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
 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"
 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     },
 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>
105 <style lang="scss" scoped>
106 .SsCellRender {
107   padding: 5px 11px;
108   //height: 100%;
109   position: relative;
110   cursor: cell;
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   }
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   }
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
  5 <template>
  6   <div
  7     class="SsHeaderRender ag-cell-label-container"
  8     role="presentation"
  9     :style="style"
 11     <!-- <span ref="eMenu" class="ag-header-icon ag-header-cell-menu-button"></span> -->
 13     <div
 14       ref="eLabel"
 15       class="ag-header-cell-label"
 16       role="presentation"
 17       style="flex-wrap: wrap"
 18       @click="onSortChanged"
 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>
 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"
 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"
 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"
 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
 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     },
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>
49 <style lang="scss" scoped>
50 .SsRowHeaderRender {
51   & {
52     padding-left: 11px;
53     padding-right: 11px;
54     height: 100%;
55   }
56 }
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
 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         }"
 19         <slot />
 20       </ul>
 21     </div>
 22   </div>
 23 </template>
 25 <script>
 26 import { createBodyClickListener } from "./body-click-listener";
 28 // const EVENT_LIST = ['click', 'contextmenu', 'keydown']
 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);
 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;
 92       const scrollingElement =
 93         document.scrollingElement || document.documentElement;
 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;
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     },
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     },
151     close() {
152       this.ctxVisible = false;
153     },
154   },
155 };
156 </script>
158 <style lang="scss" scoped>
159 .ctx {
160   position: relative;
161 }
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 }
187 .ctx-divider {
188   height: 1px;
189   margin: 0.5rem 0;
190   overflow: hidden;
191   background-color: #e5e5e5;
192 }
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 }
213 .ctx-item:focus,
214 .ctx-item:hover {
215   color: #2b2d2f;
216   text-decoration: none;
217   background-color: #f5f5f5;
218   cursor: normal;
219 }
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 }
230 .ctx-item.disabled,
231 .ctx-item.disabled:focus,
232 .ctx-item.disabled:hover {
233   color: #818a91;
234 }
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 }
245 .open > .ctx-menu {
246   display: block;
247 }
249 .open > a {
250   outline: 0;
251 }
253 .ctx-menu-right {
254   right: 0;
255   left: auto;
256 }
258 .ctx-menu-left {
259   right: auto;
260   left: 0;
261 }
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 }
272 .ctx-backdrop {
273   position: fixed;
274   top: 0;
275   right: 0;
276   bottom: 0;
277   left: 0;
278   z-index: 990;
279 }
281 .pull-right > .ctx-menu {
282   right: 0;
283   left: auto;
284 }
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;
 9   /* === public api ========================================== */
10   return {
11     get isListening() {
12       return isListening;
13     },
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     },
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   };
30   /* === private helpers ===================================== */
31   function _onclick(e) {
32     e.preventDefault();
33     if (typeof fn === "function") fn(e);
34   }
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);
 9   let timespan = dest.setDate(dest.getDate() + offset);
10   dest = new Date(timespan);
12   return dest;
13 };
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 = {};
33   let date = source;
34   let wd = date.getDay();
35   mapWeekDays[keys[wd]] = date;
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   }
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
  16       <jhe-button @click="handleSetCellData"
  17         >设置单元格数据(第三行,周四列)</jhe-button
  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

效果图如下: