From 13de19a27f4d1ded022badc8e64cf0811bfc7864 Mon Sep 17 00:00:00 2001 From: likunming Date: Wed, 28 Aug 2024 15:42:21 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A1=A8=E6=A0=BC=E6=8B=96=E6=8B=BD=E4=BC=98?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/platform/components/grid/GridBody.vue | 103 ++++++---------- .../platform/components/grid/GridHeader.vue | 1 + .../platform/components/grid/TreeGridRow.vue | 114 ++++++++---------- .../src/platform/components/grid/WGrid.vue | 73 ++++++++++- .../src/platform/components/grid/ts/grid.ts | 2 + 5 files changed, 156 insertions(+), 137 deletions(-) diff --git a/io.sc.platform.core.frontend/src/platform/components/grid/GridBody.vue b/io.sc.platform.core.frontend/src/platform/components/grid/GridBody.vue index 8d6b2fe6..6a900d6f 100644 --- a/io.sc.platform.core.frontend/src/platform/components/grid/GridBody.vue +++ b/io.sc.platform.core.frontend/src/platform/components/grid/GridBody.vue @@ -22,20 +22,13 @@ ref="trRef" :class="props.scope.row[table.selectedField] ? 'selected' : ''" :props="props.scope" - :draggable=" - ((typeof props.grid.props.draggable === 'boolean' && props.grid.props.draggable) || - (typeof props.grid.props.draggable === 'string' && props.grid.props.draggable === 'local')) && - table.bodyEditStatus === 'none' - ? true - : false - " - @click.stop="rowClick($event, scope.row, scope.rowIndex)" - @dblclick.stop="rowDbClick($event, scope.row, scope.rowIndex)" - @dragenter="onDragEnter($event, scope)" - @dragleave="onDragLeave" - @dragover="onDragOver($event, scope)" - @drop="onDrop($event, scope)" - @dragstart="onDragStart($event, scope)" + :draggable="draggableComputed" + @click.stop="draggableComputed ? rowClick($event, scope.row, scope.rowIndex) : () => {}" + @dblclick.stop="draggableComputed ? rowDbClick($event, scope.row, scope.rowIndex) : () => {}" + @dragleave="draggableComputed ? onDragLeave($event) : () => {}" + @dragover="draggableComputed ? onDragOver($event, scope) : () => {}" + @drop="draggableComputed ? onDrop($event, scope) : () => {}" + @dragstart="draggableComputed ? onDragStart($event, scope) : () => {}" > import { computed, inject, ref, toRaw } from 'vue'; import { Tools } from '@/platform'; +import { draggableImage } from './ts/grid'; import TreeGridRow from './TreeGridRow.vue'; import GridTd from './GridTd.vue'; import GridEditToolbar from './GridEditToolbar.vue'; @@ -142,6 +136,10 @@ const props = defineProps({ return 0; }, }, + allTickedStatus: { + type: Function, + default: () => {}, + }, }); const table = inject('table'); @@ -177,6 +175,15 @@ const setTreeRowComponentRef = (el, row) => { } }; +const draggableComputed = computed(() => { + if (typeof props.grid.props.draggable === 'boolean' && props.grid.props.draggable && table.bodyEditStatus === 'none') { + return true; + } else if (typeof props.grid.props.draggable === 'string' && props.grid.props.draggable === 'local' && table.bodyEditStatus === 'none') { + return true; + } + return false; +}); + const isSelectedRowComputed = computed(() => { const selected = props.grid.getSelectedRow(); if (!Tools.isEmpty(selected)) { @@ -196,6 +203,9 @@ const gridTrMiddleHeightComputed = computed(() => { // 拖拽开始 const onDragStart = (e, scope) => { + const img = new Image(); + img.src = draggableImage; + e.dataTransfer.setDragImage(img, 0, 0); const currPageIndex = table.rows.findIndex((item) => { return item[props.rowKeyName] === scope.row[props.rowKeyName]; }); @@ -244,15 +254,6 @@ const removeDragBottomStyle = (e) => { } } }; -// 拖拽至可放置区域触发 -const onDragEnter = (e, scope) => { - if (table.dragRow.rowIndex !== scope.rowIndex && table.dragRow.currPageStartIndex + e.target.parentNode.parentNode.children.length === scope.rowIndex + 1) { - // 最后一行 - addDragBottomStyle(e); - } else if (table.dragRow.rowIndex !== scope.rowIndex) { - addDragTopStyle(e); - } -}; // 拖拽至不可放置区域触发 const onDragLeave = (e) => { removeDragTopStyle(e); @@ -260,49 +261,41 @@ const onDragLeave = (e) => { }; // 拖拽过程触发 const onDragOver = (e, scope) => { - if ( - e.offsetY >= gridTrMiddleHeightComputed.value && - table.dragRow.rowIndex !== scope.rowIndex && - table.dragRow.currPageStartIndex + e.target.parentNode.parentNode.children.length === scope.rowIndex + 1 - ) { - removeDragTopStyle(e); - addDragBottomStyle(e); - } else if ( - e.offsetY < gridTrMiddleHeightComputed.value && - table.dragRow.rowIndex !== scope.rowIndex && - table.dragRow.currPageStartIndex + e.target.parentNode.parentNode.children.length === scope.rowIndex + 1 - ) { + e.preventDefault(); + if (e.target.nodeName === 'TD' && e.offsetY <= gridTrMiddleHeightComputed.value) { removeDragBottomStyle(e); addDragTopStyle(e); + } else if (e.target.nodeName === 'TD' && e.offsetY > gridTrMiddleHeightComputed.value) { + removeDragTopStyle(e); + addDragBottomStyle(e); } - e.preventDefault(); }; // 拖拽放置时触发 const onDrop = (e, scope) => { e.preventDefault(); + removeDragTopStyle(e); + removeDragBottomStyle(e); if (table.dragRow.rowIndex === scope.rowIndex) { return; } const dragRow = table.dragRow.row; const currPageStartIndex = table.dragRow.currPageStartIndex; table.rows.splice(table.dragRow.currPageIndex, 1); - if (e.offsetY < gridTrMiddleHeightComputed.value && table.dragRow.rowIndex < scope.rowIndex) { + if (e.offsetY <= gridTrMiddleHeightComputed.value && table.dragRow.rowIndex < scope.rowIndex) { table.rows.splice(scope.rowIndex - currPageStartIndex - 1, 0, dragRow); + } else if (e.offsetY > gridTrMiddleHeightComputed.value && table.dragRow.rowIndex > scope.rowIndex) { + table.rows.splice(scope.rowIndex - currPageStartIndex + 1, 0, dragRow); } else { table.rows.splice(scope.rowIndex - currPageStartIndex, 0, dragRow); } - removeDragTopStyle(e); - removeDragBottomStyle(e); const updateData = []; - table.rows.forEach((item, index) => { if (!Tools.isEmpty(item)) { - item[props.grid.props.orderBy] = currPageStartIndex + index + 1; + item[props.grid.props.draggableOrderBy] = currPageStartIndex + index + 1; updateData.push(toRaw(item)); } }); - if (typeof props.grid.props.draggable === 'boolean' && props.grid.props.draggable) { // 访问后端更新排序 props.grid.updates(updateData); @@ -311,30 +304,10 @@ const onDrop = (e, scope) => { props.afterRowDraggable(updateData); }; -// 处理当前页所有数据勾选状态 -const allTickedStatus = () => { - // 存在一条勾选的记录设置为 null - // 一条勾选的记录都没有设置为 false - // 全部勾选设置为 true - const ticked_ = []; - table.rows.forEach((item) => { - if (item[table.tickedField]) { - ticked_.push(item); - } - }); - if (ticked_.length === table.rows.length) { - table.allTicked = true; - } else if (ticked_.length > 0) { - table.allTicked = null; - } else { - table.allTicked = false; - } -}; - const updateTicked = (evt: Event, row: any) => { if (table.bodyEditStatus === 'none') { props.getRow(table.rows, row[props.rowKeyName], false)[table.selectedField] = row[table.tickedField]; - allTickedStatus(); + props.allTickedStatus(); if (props.grid.props.onUpdateTicked) { props.grid.emit('updateTicked', evt, row); } @@ -342,10 +315,6 @@ const updateTicked = (evt: Event, row: any) => { props.getRow(table.rows, row[props.rowKeyName], false)[table.tickedField] = !props.getRow(table.rows, row[props.rowKeyName], false)[table.tickedField]; } }; - -defineExpose({ - allTickedStatus, -}); diff --git a/io.sc.platform.core.frontend/src/platform/components/grid/GridHeader.vue b/io.sc.platform.core.frontend/src/platform/components/grid/GridHeader.vue index 24fcf749..51547df3 100644 --- a/io.sc.platform.core.frontend/src/platform/components/grid/GridHeader.vue +++ b/io.sc.platform.core.frontend/src/platform/components/grid/GridHeader.vue @@ -188,6 +188,7 @@ const allTickedUpdateFun = (value, evt) => { } else if (table.bodyEditStatus === 'rowsEdit') { table.allTicked = false; } + props.grid.emit('updateTickeds', value); }; const handlerStickyChildrenColumn = (item, columns) => { diff --git a/io.sc.platform.core.frontend/src/platform/components/grid/TreeGridRow.vue b/io.sc.platform.core.frontend/src/platform/components/grid/TreeGridRow.vue index 14d9139e..8f6f30f8 100644 --- a/io.sc.platform.core.frontend/src/platform/components/grid/TreeGridRow.vue +++ b/io.sc.platform.core.frontend/src/platform/components/grid/TreeGridRow.vue @@ -2,20 +2,13 @@
@@ -137,6 +130,7 @@ import { ref, computed, inject, toRaw } from 'vue'; import { Tools, NotifyManager } from '@/platform'; import GridEditToolbar from './GridEditToolbar.vue'; +import { draggableImage } from './ts/grid'; const trRef = ref(); const tdDivRef = ref(); @@ -235,6 +229,15 @@ const style = { }, }; +const draggableComputed = computed(() => { + if (typeof props.grid.props.draggable === 'boolean' && props.grid.props.draggable && table.bodyEditStatus === 'none') { + return true; + } else if (typeof props.grid.props.draggable === 'string' && props.grid.props.draggable === 'local' && table.bodyEditStatus === 'none') { + return true; + } + return false; +}); + const isSelectedRowComputed = computed(() => { const selected = props.grid.getSelectedRow(); if (!Tools.isEmpty(selected)) { @@ -384,7 +387,7 @@ document.addEventListener('drop', function (e) { // 拖拽开始 const onDragStart = (e, dataRow) => { const img = new Image(); - img.src = `data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' %3E%3Cpath /%3E%3C/svg%3E`; + img.src = draggableImage; e.dataTransfer.setDragImage(img, 0, 0); const selecteds = props.grid.getSelectedRows(); if ( @@ -500,30 +503,6 @@ const dragRecordsContains = (dataRow) => { ); }; -// 根据传入节点判断该节点是否为所在层级的最后一个节点 -const isLastNode = (dataRow) => { - if (Tools.isEmpty(dataRow[props.grid.props.foreignKey])) { - if (table.rows[table.rows.length - 1][props.grid.props.primaryKey] === dataRow[props.grid.props.primaryKey]) { - return true; - } - } else { - const parent = props.getRow(table.rows, dataRow[props.grid.props.foreignKey], true); - if (parent.children[parent.children.length - 1][props.grid.props.primaryKey] === dataRow[props.grid.props.primaryKey]) { - return true; - } - } - return false; -}; - -// 拖拽至可放置区域触发 -const onDragEnter = (e, dataRow) => { - if (e.target.nodeName === 'TD' && e.offsetY <= gridTrMiddleHeightComputed.value && !dragRecordsContains(dataRow)) { - addDragTopStyle(e); - } else if (isLastNode(dataRow) && e.target.nodeName === 'TD' && e.offsetY > gridTrMiddleHeightComputed.value && !dragRecordsContains(dataRow)) { - addDragBottomStyle(e); - } -}; - // 拖拽至不可放置区域触发 const onDragLeave = (e, dataRow) => { removeDragTopStyle(e); @@ -549,7 +528,7 @@ const onDragOver = (e, dataRow) => { if (e.target.nodeName === 'TD' && e.offsetY <= gridTrMiddleHeightComputed.value && !dragRecordsContains(dataRow)) { removeDragBottomStyle(e); addDragTopStyle(e); - } else if (isLastNode(dataRow) && e.target.nodeName === 'TD' && e.offsetY > gridTrMiddleHeightComputed.value && !dragRecordsContains(dataRow)) { + } else if (e.target.nodeName === 'TD' && e.offsetY > gridTrMiddleHeightComputed.value && !dragRecordsContains(dataRow)) { removeDragTopStyle(e); addDragBottomStyle(e); } @@ -583,42 +562,57 @@ const removeRecord = (arr, removeData) => { // 待更新的排序数据 const updateOrderData = []; +// 处理树节点的增加 +const nodeSplice = (e, dragIndex, targetIndex, drag, target, arr) => { + if ( + (Tools.isEmpty(drag[props.grid.props.foreignKey]) && Tools.isEmpty(target[props.grid.props.foreignKey])) || + drag[props.grid.props.foreignKey] === target[props.grid.props.foreignKey] + ) { + const lessThanResult = dragLessThanTarget(dragIndex, targetIndex); + // 父节点相同的同级处理 + if (e.offsetY <= gridTrMiddleHeightComputed.value && lessThanResult) { + arr.splice(targetIndex - 1, 0, drag); + } else if (e.offsetY > gridTrMiddleHeightComputed.value && !lessThanResult) { + arr.splice(targetIndex + 1, 0, drag); + } else { + arr.splice(targetIndex, 0, drag); + } + } else { + // 拖拽节点与目标节点不同级处理 + if (e.offsetY <= gridTrMiddleHeightComputed.value) { + arr.splice(targetIndex, 0, drag); + } else if (e.offsetY > gridTrMiddleHeightComputed.value) { + arr.splice(targetIndex + 1, 0, drag); + } + } +}; + // 设置排序号 const setOrder = (arr) => { arr.forEach((item, index) => { - item[props.grid.props.orderBy] = index + 1; + item[props.grid.props.draggableOrderBy] = index + 1; // 添加至待更新集合中 updateOrderData.push({ ...toRaw(item), children: null }); }); }; // 增加并重新设置父属性 -const addRecord = (e, arr, addData, targetData, dragIndex, targetIndex) => { +const childrenResetOrder = (e, arr, addData, targetData, dragIndex, targetIndex) => { for (let i = 0; i < arr.length; i++) { if (arr[i][props.grid.props.primaryKey] === targetData[props.grid.props.foreignKey]) { - if ( - e.offsetY <= gridTrMiddleHeightComputed.value && - isTrue(dragIndex, targetIndex) && - addData[props.grid.props.foreignKey] === targetData[props.grid.props.foreignKey] - ) { - arr[i].children.splice(targetIndex - 1, 0, addData); - } else if (e.offsetY > gridTrMiddleHeightComputed.value && addData[props.grid.props.foreignKey] !== targetData[props.grid.props.foreignKey]) { - arr[i].children.splice(arr[i].children.length, 0, addData); - } else { - arr[i].children.splice(targetIndex, 0, addData); - } + nodeSplice(e, dragIndex, targetIndex, addData, targetData, arr[i].children); // 修改父 addData[props.grid.props.foreignKey] = arr[i][props.grid.props.primaryKey]; // 重新设置排序号 setOrder(arr[i].children); break; } else if (arr[i].children && arr[i].children.length > 0) { - addRecord(e, arr[i].children, addData, targetData, dragIndex, targetIndex); + childrenResetOrder(e, arr[i].children, addData, targetData, dragIndex, targetIndex); } } }; -const isTrue = (dragIndex, targetIndex) => { +const dragLessThanTarget = (dragIndex, targetIndex) => { if (dragIndex < targetIndex) { return true; } @@ -627,23 +621,15 @@ const isTrue = (dragIndex, targetIndex) => { // 数据处理 const resetOrderDataHandler = (e, dragRecords, targetData, targetIndex) => { - // 1、从表格数据中将拖拽数据删除 dragRecords.forEach((item) => { + // 从表格数据中将拖拽数据删除 const itemIndex = removeRecord(table.rows, item); - // 2、表格数据中根据目标位置添加数据 if (Tools.isEmpty(targetData[props.grid.props.foreignKey])) { - // 3、修正位置,当拖拽至行的上半部分,且拖拽对象跟目标对象处于同级,且下标小于目标时,使用splice添加到指定下标时需将下标-1(扣除自身所占的1个下标) - if (e.offsetY <= gridTrMiddleHeightComputed.value && Tools.isEmpty(item[props.grid.props.foreignKey]) && isTrue(itemIndex, targetIndex)) { - table.rows.splice(targetIndex - 1, 0, item); - } else { - table.rows.splice(targetIndex, 0, item); - } + nodeSplice(e, itemIndex, targetIndex, item, targetData, table.rows); item[props.grid.props.foreignKey] = null; setOrder(table.rows); - // 根目录下顺序变化,直接将根目录下所有数据放到待更新集合中 - // updateOrderData.push(...toRaw(table.rows)); } else { - addRecord(e, table.rows, item, targetData, itemIndex, targetIndex); + childrenResetOrder(e, table.rows, item, targetData, itemIndex, targetIndex); } }); }; diff --git a/io.sc.platform.core.frontend/src/platform/components/grid/WGrid.vue b/io.sc.platform.core.frontend/src/platform/components/grid/WGrid.vue index ecccceab..530e7a6c 100644 --- a/io.sc.platform.core.frontend/src/platform/components/grid/WGrid.vue +++ b/io.sc.platform.core.frontend/src/platform/components/grid/WGrid.vue @@ -71,6 +71,7 @@ :get-row="getRow" :set-old-value="setOldValue" :no-data-tr-colspan="noDataTrColspanComputed" + :all-ticked-status="allTickedStatus" > @@ -146,6 +147,7 @@ const props = defineProps({ title: { type: String, default: '' }, // 表格标题 autoFetchData: { type: Boolean, default: true }, // 自动加载数据 draggable: { type: [Boolean, String], default: false }, // 是否启用行拖拽,默认不启用,布尔true为启用行拖拽且访问后端进行排序,字符串local为本地排序,只根据配置的字段进行本地排序,不会将数据发送至后端。 + draggableOrderBy: { type: String, default: 'order' }, // 拖拽排序时根据哪个字段进行排序 pageable: { type: Boolean, default: true }, // 是否需要分页,当启用树形表格模式时该属性失效,树形表格不支持分页。 configButton: { type: Boolean, default: true }, // 是否显示表格配置按钮 dataUrl: { type: String, default: '' }, // 表格数据操作请求的URL前缀 @@ -170,15 +172,21 @@ const props = defineProps({ treeRelationship: { type: String, default: 'parent' }, // 树形表格模式的数据关系,包括:parent, children,当为parent时组件根据数据主键与数据外键构建树形数据,否则需要自己构建好树形数据放到children属性中。 primaryKey: { type: String, default: 'id' }, // 数据主键(常规表格模式时,该字段可用作内置的编辑删除等功能对应的后端API入参,如:继承RestCrudController的update所需的入参。树形表格模式时,该字段为构建树数据的主键) foreignKey: { type: String, default: 'parent' }, // 数据外键(常规表格模式时,该字段暂时无用,将来可用作多个表格的数据关系字段。树形表格模式时,该字段为构建树数据的关系字段) - orderBy: { type: String, default: 'order' }, // 拖拽排序时根据哪个字段进行排序 refreshData: { type: Boolean, default: false }, // 新增、删除、修改成功后是否刷新数据列表,默认不刷新但是新增修改后台必须返回对应的行数据对象,删除则必须返回删除的记录集primaryKey集合。 - dbClickOperation: { type: String, default: 'view' }, // 默认的双击操作:可填写内置或自定义按钮name,执行的操作为按钮对应的click,固定值提供:expand(展开双击的行) + dbClickOperation: { type: String, default: 'view' }, // 默认的双击操作:可填写内置或自定义按钮name,执行的操作为按钮对应的click,固定值提供:expand(展开双击的行)、none(双击不执行任何动作) sortBy: { type: Array, default: () => { return []; }, }, // 默认排序字段,示例:['userName', '-lastModifyDate'],其中“-”开头表示倒序。 + tickedRecord: { + // 默认勾选的记录,传入一个对象,包含:columnName(列名称,字符串类型,该属性不传默认根据数据主键查找)、data(需要勾选的数据,数组类型) + type: Object, + default: () => { + return {}; + }, + }, queryCriteria: { // 查询条件,查询、翻页、刷新等操作都会带上的查询条件 type: Object, @@ -286,6 +294,8 @@ const emit = defineEmits<{ (e: 'rowDbClick', evt: Event, row: any, index: number): void; // 行数据checkbox勾选状态改变事件 (e: 'updateTicked', evt: Event, row: any): void; + // 表格列头全部勾选checkbox状态改变事件 + (e: 'updateTickeds', value: boolean): void; ( e: 'beforeRequestData', // 表格请求数据前触发事件 requestParams: URLSearchParams | any, // 第一个参数,请求参数 @@ -578,7 +588,7 @@ const rowClick = (evt: any, row: any, index: any) => { } row[table.selectedField] = true; row[table.tickedField] = true; - bodyRef.value?.allTickedStatus(); + allTickedStatus(); if (props.onRowClick) { emit('rowClick', evt, row, index); } @@ -590,7 +600,7 @@ const rowDbClick = (evt, row, index) => { emit('rowDbClick', evt, row, index); } else if (props.dbClickOperation === 'view') { viewRef.value?.view(); - } else { + } else if (props.dbClickOperation !== 'none') { topRef.value?.dbClickOperation(row); } } @@ -756,6 +766,7 @@ const onRequest = async (ops: any) => { state.pagination.sortBy = ops.pagination.sortBy; state.pagination.descending = ops.pagination.descending; setRowDataExtraProperty(table.rows); + allTickedStatus(); stickyHeaderColumn(100); emit('afterRequestData', table.rows); // 判断数据加载后是否默认展开,是的话直接展开树形表格 @@ -764,6 +775,56 @@ const onRequest = async (ops: any) => { } }; +// 处理当前页所有数据勾选状态 +const allTickedStatus = () => { + // 存在一条勾选的记录设置为 null + // 一条勾选的记录都没有设置为 false + // 全部勾选设置为 true + if (props.checkboxSelection) { + const ticked_ = []; + table.rows.forEach((item) => { + if (item[table.tickedField]) { + ticked_.push(item); + } + }); + if (ticked_.length === table.rows.length) { + table.allTicked = true; + } else if (ticked_.length > 0) { + table.allTicked = null; + } else { + table.allTicked = false; + } + } +}; + +const getInitRowTicked = (rowData) => { + if (rowData[rowDataExtraPropertyName.ticked]) { + return true; + } else if (Object.keys(props.tickedRecord).length > 0 && props.tickedRecord['data']?.length > 0) { + const columnName = props.tickedRecord['columnName'] || props.primaryKey; + const data = props.tickedRecord['data']; + if ( + data.findIndex((item) => { + return item === rowData[columnName]; + }) > -1 + ) { + return true; + } + } + return false; +}; +const getInitRowSelected = (rowData) => { + if (rowData[rowDataExtraPropertyName.selected]) { + return true; + } else if (!props.tree && rowData[rowDataExtraPropertyName.ticked]) { + return true; + } else if (props.tree && !props.checkboxSelection && rowData[rowDataExtraPropertyName.ticked]) { + return true; + } else { + return false; + } +}; + /** * 行数据附加属性名称 */ @@ -782,8 +843,8 @@ const rowDataExtraPropertyName = { */ const initRowDataExtraProperty = (rowData) => { rowData[rowDataExtraPropertyName.rowKey] = Tools.uuid(); - rowData[rowDataExtraPropertyName.ticked] = rowData[rowDataExtraPropertyName.ticked] || false; - rowData[rowDataExtraPropertyName.selected] = rowData[rowDataExtraPropertyName.selected] || false; + rowData[rowDataExtraPropertyName.ticked] = getInitRowTicked(rowData); + rowData[rowDataExtraPropertyName.selected] = getInitRowSelected(rowData); rowData[rowDataExtraPropertyName.rowOldValue] = {}; setOldValue(rowData); if (props.tree) { diff --git a/io.sc.platform.core.frontend/src/platform/components/grid/ts/grid.ts b/io.sc.platform.core.frontend/src/platform/components/grid/ts/grid.ts index e6682682..0993c0f0 100644 --- a/io.sc.platform.core.frontend/src/platform/components/grid/ts/grid.ts +++ b/io.sc.platform.core.frontend/src/platform/components/grid/ts/grid.ts @@ -57,3 +57,5 @@ export const columnDefaultProps = (columns: any, sortNo: boolean = true) => { } return []; }; + +export const draggableImage = `data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' %3E%3Cpath /%3E%3C/svg%3E`;