From 6c2c3c66afc1d7f75f7975ab2e929fa4d28d13b9 Mon Sep 17 00:00:00 2001 From: BoBoooooo <17746714@qq.com> Date: Mon, 1 Mar 2021 21:02:11 +0800 Subject: [PATCH] =?UTF-8?q?feat(@0.8.8-7):=20=E6=96=B0=E5=A2=9E=E8=A1=A8?= =?UTF-8?q?=E6=A0=BC=E5=B8=83=E5=B1=80,=E5=90=88=E5=B9=B6=E5=90=8E?= =?UTF-8?q?=E5=88=A0=E9=99=A4=E8=A1=8C=E5=88=97=E9=80=BB=E8=BE=91=E5=BE=85?= =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- .../form-designer/src/FormDesigner.vue | 24 +- .../form-designer/src/GenerateForm.vue | 53 +++ .../form-designer/src/WidgetConfig.vue | 23 +- .../form-designer/src/WidgetForm.vue | 343 ++++++++++++++---- .../form-designer/src/componentsConfig.ts | 17 + .../form-designer/src/styles/index.scss | 51 ++- 7 files changed, 427 insertions(+), 86 deletions(-) diff --git a/package.json b/package.json index 70d109f..5eb42a4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "element-pro-crud", - "version": "0.8.8-6", + "version": "0.8.8-7", "author": "BoBo", "main": "lib/ProCrud.umd.min.js", "files": [ diff --git a/src/component/form-designer/src/FormDesigner.vue b/src/component/form-designer/src/FormDesigner.vue index 7287c75..b0e7be2 100644 --- a/src/component/form-designer/src/FormDesigner.vue +++ b/src/component/form-designer/src/FormDesigner.vue @@ -262,7 +262,7 @@ export default { "list": [], "config": { "labelWidth": 100, - "labelPosition": "top", + "labelPosition": "right", "size": "small" } }`, @@ -279,7 +279,6 @@ export default { methods: { // 切换布局 changeMode(mode) { - console.log(mode); this.currentMode = mode; }, // 深拷贝防止拖拽clone后污染原组件,统一给所有拖拽出来的组件设置key,model @@ -302,6 +301,27 @@ export default { cloneOrigin.options.remoteFunc = `func_${key}`; } + // 如果为表格布局,默认添加一个 + if (type === 'grid-table') { + const tdKey = `td_${Math.ceil(Math.random() * 99999)}`; + cloneOrigin.rows[0].columns.push( + { + type: 'td', + options: { + colspan: 1, + rowspan: 1, + align: 'left', + valign: 'top', + width: '', + height: '', + }, + list: [], + key: tdKey, + model: tdKey, + }, + ); + } + return cloneOrigin; }, // 返回当前表单设计器对象 diff --git a/src/component/form-designer/src/GenerateForm.vue b/src/component/form-designer/src/GenerateForm.vue index 494ad3d..fac8350 100644 --- a/src/component/form-designer/src/GenerateForm.vue +++ b/src/component/form-designer/src/GenerateForm.vue @@ -73,6 +73,46 @@ :widget="item"> + + + + diff --git a/src/component/form-designer/src/WidgetForm.vue b/src/component/form-designer/src/WidgetForm.vue index 83ae071..0875816 100644 --- a/src/component/form-designer/src/WidgetForm.vue +++ b/src/component/form-designer/src/WidgetForm.vue @@ -1,18 +1,9 @@ @@ -160,27 +199,125 @@ export default { }; }, methods: { + // 处理TD设置 + handleTdSettingCommand(command, table, row, rowIndex, col, colIndex) { + switch (command) { + case 'left-col': this.handleColAdd(table, row, 'left'); break; + case 'right-col': this.handleColAdd(table, row, 'right'); break; + case 'top-row': this.handleRowAdd(table, 'top'); break; + case 'bottom-row': this.handleRowAdd(table, 'bottom'); break; + case 'merge-right': this.handleTdSpanMerge(table, row, rowIndex, col, colIndex, 'right'); break; + case 'merge-bottom': this.handleTdSpanMerge(table, row, rowIndex, col, colIndex, 'bottom'); break; + case 'split-col': this.handleTdSplitToCol(table, row, rowIndex, col, colIndex); break; + case 'split-row': this.handleTdSplitToRow(table, row, rowIndex, col, colIndex); break; + case 'remove-col': this.handleTdRemove(table, row, rowIndex, col, colIndex, 'col'); break; + case 'remove-row': this.handleTdRemove(table, row, rowIndex, col, colIndex, 'row'); break; + // eslint-disable-next-line no-unused-expressions + default: () => this.$message('暂无此功能'); + break; + } + }, + generateNewTd() { + return { + type: 'td', + options: { + colspan: 1, + rowspan: 1, + align: 'left', + valign: 'middle', + width: '', + height: '', + }, + list: [], + key: `td_${Math.ceil(Math.random() * 99999)}`, + }; + }, + handleTdSplitToRow(table, row, rowIndex, col, colIndex) { + const { rowspan } = col.options; + const newCol = this.generateNewTd(); + const rows = table.rows.slice(rowIndex + 1, rowIndex + rowspan); + rows.forEach((_) => { + _.columns.splice(colIndex, 0, newCol); + }); + col.options.rowspan = 1; + }, + handleTdSplitToCol(table, row, rowIndex, col, colIndex) { + const { colspan } = col.options; + for (let i = 0; i < colspan - 1; i += 1) { + const newCol = this.generateNewTd(); + row.columns.splice(colIndex, 0, newCol); + } + col.options.colspan = 1; + }, + // 处理删除当前行当前列 + handleTdRemove(table, row, rowIndex, col, colIndex, direction) { + if (direction === 'col') { + table.rows.forEach((_) => { + _.columns.splice(colIndex, 1); + }); + } else { + table.rows.splice(rowIndex, 1); + } + }, + // 处理TD合并问题 + handleTdSpanMerge(table, row, rowIndex, col, colIndex, direction) { + // 当前td向右合并 + if (direction === 'right') { + const { length } = row.columns; + const nextColIndex = colIndex + col.options.colspan; + if (nextColIndex < length) { + // 当前td colspsan改为2 + col.options.colspan += 1; + // 删除右侧元素 + row.columns.splice(nextColIndex, 1); + } else { + this.$message.error('当前列已是最后一列'); + } + } else { + const { length } = table.rows; + // 注意此处不能直接+1,否则删除的td一直是第二行的,在合并了之后继续向下合并时会有问题 + const nextRowIndex = rowIndex + col.options.rowspan; + if (nextRowIndex < length) { + // 当前td rowspan改为2 + col.options.rowspan += 1; + // 删除下一行当前列元素 + table.rows[nextRowIndex].columns.splice(colIndex, 1); + } else { + this.$message.error('当前行已是最后一列'); + } + } + }, handleSelectWidget(index) { console.log(`子项被点击:${index}`); this.selectWidget = this.data.list[index]; }, + handleSelectTdWidget(col) { + console.log(`td项被点击:${col.key}`); + this.selectWidget = col; + }, handleWidgetAdd(evt) { // console.log('元素被拖到外层handleWidgetAdd,evt:', evt); const { newIndex } = evt; console.log(this.data.list[newIndex]); this.selectWidget = this.data.list[newIndex]; }, + handleWidgetTdAdd($event, col) { + const { newIndex, oldIndex, item } = $event; + // 防止布局元素的嵌套拖拽 + if (item.className.indexOf('data-grid') >= 0) { + col.list[newIndex].splice(newIndex, 1); + return false; + } + this.selectWidget = col.list[newIndex]; + return null; + }, handleWidgetColAdd($event, row, colIndex) { const { newIndex, oldIndex, item } = $event; // 防止布局元素的嵌套拖拽 if (item.className.indexOf('data-grid') >= 0) { // 如果是列表中拖拽的元素需要还原到原来位置 if (item.tagName === 'DIV') { - this.data.list.splice( - oldIndex, - 0, - row.columns[colIndex].list[newIndex], - ); + this.data.list.splice(oldIndex, 0, row.columns[colIndex].list[newIndex]); } row.columns[colIndex].list.splice(newIndex, 1); return false; @@ -204,6 +341,36 @@ export default { this.data.list.splice(index, 1); }); }, + handleColAdd(table, rowIndex, direction = 'right') { + const { rows } = table; + rows.forEach((row) => { + const { columns } = row; + const newCol = this.generateNewTd(); + // 此处判断是左添加列还是右添加列 + if (direction === 'right') { + columns.push(newCol); + } else { + columns.unshift(newCol); + } + }); + table.options.sumColSpan += 1; + }, + handleRowAdd(table, direction = 'bottom') { + const row = { + columns: [], + }; + for (let i = 0; i < table.options.sumColSpan; i += 1) { + const newCol = this.generateNewTd(); + row.columns.push(newCol); + } + // 此处判断是上方添加行还是下方添加行 + if (direction === 'bottom') { + table.rows.push(row); + } else { + table.rows.unshift(row); + } + table.options.sumRowSpan += 1; + }, handleGridAdd(grid) { grid.columns.push({ span: 24, @@ -228,6 +395,26 @@ export default { this.selectWidget = this.data.list[index + 1]; }); }, + handleTableClone(index) { + const table = JSON.parse(JSON.stringify(this.data.list[index])); + for (const row of table.rows) { + for (const col of row.columns) { + col.key = `td_${Math.ceil(Math.random() * 99999)}`; + for (const item of col.list) { + item.key = `${item.type}_${Math.ceil(Math.random() * 99999)}`; + item.model = item.key; + } + } + } + const cloneData = { + ...table, + key: `grid_${Math.ceil(Math.random() * 99999)}`, + }; + this.data.list.splice(index + 1, 0, cloneData); + this.$nextTick(() => { + this.selectWidget = this.data.list[index + 1]; + }); + }, }, watch: { select(val) { diff --git a/src/component/form-designer/src/componentsConfig.ts b/src/component/form-designer/src/componentsConfig.ts index 8fe173f..2a5a84e 100644 --- a/src/component/form-designer/src/componentsConfig.ts +++ b/src/component/form-designer/src/componentsConfig.ts @@ -499,6 +499,23 @@ export const layoutComponents = [ align: 'top', }, }, + { + type: 'grid-table', + name: '表格布局', + icon: 'th', + options: { + borderWidth: 1, + borderColor: '#999', + width: '100%', + sumColSpan: 1, + sumRowSpan: 1, + }, + rows: [ + { + columns: [], + }, + ], + }, { type: 'tabs', name: '标签页', diff --git a/src/component/form-designer/src/styles/index.scss b/src/component/form-designer/src/styles/index.scss index 3e3914c..497f216 100644 --- a/src/component/form-designer/src/styles/index.scss +++ b/src/component/form-designer/src/styles/index.scss @@ -155,7 +155,7 @@ $primary-background-color: #ecf5ff; } .widget-view { - padding-bottom: 18px; + // padding-bottom: 18px; position: relative; border: 1px dashed hsla(0, 0%, 66.7%, 0.7); background-color: rgba(236, 245, 255, 0.3); @@ -725,3 +725,52 @@ $primary-background-color: #ecf5ff; } } } + +.widget-grid-table-container{ + padding: 5px; + margin: 2px; + min-height: 50px; + .widget-grid-table{ + border: 1px solid #333; + width: 100%; + table-layout: fixed; + .widget-grid-table__td{ + padding: 4px; + position: relative; + border: 2px inset rgba(0,0,0,.1); + &.active{ + outline: 2px solid #e6a23c; + border: 1px solid #e6a23c; + outline-offset: -1px; + } + &:hover{ + outline: 2px solid #e6a23c; + border: 1px solid #e6a23c; + outline-offset: -1px; + } + .widget-td-setting{ + position: absolute; + background: #009688; + right: 0; + bottom: 0; + height: 20px; + line-height: 20px; + z-index: 9; + i { + font-size: 14px; + border-radius: 50%; + color: white; + margin: 0 5px; + cursor: pointer; + &:hover { + color: #f2f2f2; + } + } + } + } + } +} +.widget-td-setting-divider{ + margin: 5px auto!important; + width: 80%; +} \ No newline at end of file