diff --git a/io.sc.platform.core.frontend/src/platform/components/grid/GridConfig.vue b/io.sc.platform.core.frontend/src/platform/components/grid/GridConfig.vue index 9c7bebc9..0a7a4df7 100644 --- a/io.sc.platform.core.frontend/src/platform/components/grid/GridConfig.vue +++ b/io.sc.platform.core.frontend/src/platform/components/grid/GridConfig.vue @@ -93,7 +93,7 @@ unelevated @click=" () => { - table.columns[0].hidden = false; + table.columns[0].showIf = true; table.sortNo = true; grid.refreshStyle(100); } @@ -107,7 +107,7 @@ unelevated @click=" () => { - table.columns[0].hidden = true; + table.columns[0].showIf = false; table.sortNo = false; grid.refreshStyle(100); } @@ -238,9 +238,7 @@ + + + @@ -128,7 +133,7 @@ import GridPagination from './GridPagination.vue'; import GridEditor from './GridEditor.vue'; import CellEditor from './CellEditor.vue'; import GridView from './GridView.vue'; -import { selectMode as selectMode_, getMergeColumns, sortByProperties, editStatus } from './ts/grid.ts'; +import { selectMode as selectMode_, sortByProperties, editStatus, groupMode as groupMode_ } from './ts/grid.ts'; import { columnDefaultProps } from './ts/grid.ts'; @@ -183,10 +188,13 @@ const props = defineProps({ foreignKey: { type: String, default: 'parent' }, // 数据外键(常规表格模式时,该字段暂时无用,将来可用作多个表格的数据关系字段。树形表格模式时,该字段为构建树数据的关系字段) refreshData: { type: Boolean, default: false }, // 新增、删除、修改成功后是否刷新数据列表,默认不刷新但是新增修改后台必须返回对应的行数据对象,删除则必须返回删除的记录集primaryKey集合。 dbClickOperation: { type: String, default: 'view' }, // 默认的双击操作:可填写内置或自定义按钮name,执行的操作为按钮对应的click,固定值提供:expand(展开双击的行)、none(双击不执行任何动作) - separator: { type: String, default: 'horizontal' }, - groupMode: { type: String, default: '' }, - group: { - type: Array, + separator: { type: String, default: 'cell' }, // 表格分割线,支持:horizontal、vertical、cell、none + hideHeader: { type: Boolean, default: false }, // 隐藏表头 + groupMode: { type: String, default: undefined }, // 分组模式,支持:alone、merge + groupStartOpen: { type: [String, Array], default: undefined }, // alone分组模式下默认展开的组,字符串支持:all、first、none,数组可配置多个组名。 + groupByField: { + // 分组字段配置,当分组模式为 alone 时若配置的为数组,取数组第一个字段。 + type: [String, Array], default: () => { return []; }, @@ -343,7 +351,6 @@ const tableColumnsMap = ref(arrayToMap('name', rawColumns.value)); const rowKey_ = '_rowKey_'; // 行数据中前端附加的UUID字段名 const queryFormFieldsMap = arrayToMap('name', props.queryFormFields); const tableColumns = ref(columnDefaultProps(rawColumns.value, props.sortNo)); -const mergeColumns = getMergeColumns(tableColumns.value); const url = { dataUrl: props.dataUrl, fetchDataUrl: props.fetchDataUrl, @@ -450,8 +457,12 @@ const denseBottomComputed = computed(() => { const visibleColumnsComputed = computed(() => { const visibleColumns: string[] = []; table.columns.forEach((item) => { - if (!item.hidden && (!props.tree || (props.tree && item.name !== '_sortNo_'))) { - visibleColumns.push(item.name); + if (!props.tree || (props.tree && item.name !== '_sortNo_')) { + if (Tools.isEmpty(item.showIf)) { + visibleColumns.push(item.name); + } else if (typeof item.showIf === 'boolean' && item.showIf) { + visibleColumns.push(item.name); + } } }); return visibleColumns; @@ -472,8 +483,8 @@ const state = reactive({ middleScrollWidth: 0, // 表格出现滚动条时的宽度,若无滚动条则与 middleWidth 一致 middleHeight: 0, // 表格当前middle区域高度(表格列头及数据行区域) columnHeadHeight: 0, // 表格当前列头高度 - tableTitleWidth: 0, // 当前表格title宽度 titleTotalHeight: 0, // 当前表格title排除无数据行的总高度 + hideHeaderNoDataHeight: 0, // 隐藏表头时无数据提示区域高度 }, pagination: { config: { @@ -559,6 +570,14 @@ const noDataTrHeightComputed = computed(() => { }; return style; }); +const hideHeaderAndNoDataStyleComputed = computed(() => { + return { + height: state.refHeightWidth.hideHeaderNoDataHeight + 'px', + display: 'flex', + 'align-items': 'center', + 'justify-content': 'center', + }; +}); const noDataTrColspanComputed = computed(() => { let colspan = excludeColumnNum.value; @@ -625,6 +644,7 @@ const onResize = () => { state.refHeightWidth.middleWidth = tableRef.value.$el.getElementsByClassName('q-table__middle')[0]?.clientWidth; state.refHeightWidth.middleScrollWidth = tableRef.value.$el.getElementsByClassName('q-table__middle')[0]?.scrollWidth; state.refHeightWidth.columnHeadHeight = tableRef.value.$el.getElementsByTagName('thead')[0]?.clientHeight; + state.refHeightWidth.hideHeaderNoDataHeight = tableRef.value.$el.getElementsByClassName('q-table__middle')[0]?.clientHeight; // 判断是否有数据,没数据修改 middleHeight if ((table.rows && table.rows.length > 0) || attrs['hide-bottom']) { state.refHeightWidth.middleHeight = tableRef.value.$el.getElementsByClassName('q-table__middle')[0]?.clientHeight; @@ -635,12 +655,15 @@ const onResize = () => { } state.refHeightWidth.middleHeight = state.refHeightWidth.columnHeadHeight + scrollHeight; } - state.refHeightWidth.tableTitleWidth = tableRef.value.$el.getElementsByClassName('_table-title')[0]?.clientWidth; - let titleTotalHeight = tableRef.value.$el.getElementsByTagName('thead')[0].offsetHeight; + let titleTotalHeight = tableRef.value.$el.getElementsByTagName('thead')[0]?.offsetHeight; // 无数据时列头会增加一行,多表头的top距离计算会出错,需减掉多出来的提示行。 if (table.rows.length === 0) { - const noDataTrHeight = tableRef.value.$el.getElementsByClassName('noDataTr')[0].offsetHeight; - titleTotalHeight = titleTotalHeight - noDataTrHeight; + const noDataTrHeight = tableRef.value.$el.getElementsByClassName('noDataTr')[0]?.offsetHeight; + if (titleTotalHeight && titleTotalHeight > 0) { + titleTotalHeight = titleTotalHeight - noDataTrHeight; + } else { + titleTotalHeight = noDataTrHeight; + } } state.refHeightWidth.titleTotalHeight = titleTotalHeight; } @@ -901,10 +924,10 @@ const initRowDataExtraProperty = (rowData) => { * @param rows 数据行集合 */ const setRowDataExtraProperty = (rows: []) => { - if (mergeColumns.length > 0 && !props.tree) { + if (props.groupMode === groupMode_.merge && !props.tree) { // 如果存在需要合并的字段,并且不是树表格,重新对数据进行排序 table.mergeRecords = {}; - sortByProperties(rows, mergeColumns); + // sortByProperties(rows, mergeColumns); } if (rows && rows.length > 0) { rows.forEach((item: any, index) => { @@ -954,20 +977,20 @@ const setOldValue = (rowData) => { * desc: { 天安门: [5,1] } */ const addMergeRecords = (rowData) => { - if (mergeColumns.length > 0 && !props.tree) { - mergeColumns.forEach((columnName) => { - const tmpArr = [rowData[rowDataExtraPropertyName.rowKey]]; - if (table.mergeRecords[columnName]) { - if (table.mergeRecords[columnName][rowData[columnName]]) { - table.mergeRecords[columnName][rowData[columnName]].push(rowData[rowDataExtraPropertyName.rowKey]); - } else { - table.mergeRecords[columnName][rowData[columnName]] = tmpArr; - } - } else { - table.mergeRecords[columnName] = { [rowData[columnName]]: tmpArr }; - } - }); - } + // if (mergeColumns.length > 0 && !props.tree) { + // mergeColumns.forEach((columnName) => { + // const tmpArr = [rowData[rowDataExtraPropertyName.rowKey]]; + // if (table.mergeRecords[columnName]) { + // if (table.mergeRecords[columnName][rowData[columnName]]) { + // table.mergeRecords[columnName][rowData[columnName]].push(rowData[rowDataExtraPropertyName.rowKey]); + // } else { + // table.mergeRecords[columnName][rowData[columnName]] = tmpArr; + // } + // } else { + // table.mergeRecords[columnName] = { [rowData[columnName]]: tmpArr }; + // } + // }); + // } }; watchEffect(() => { @@ -1004,7 +1027,7 @@ watchEffect(() => { }); const tableClassComputed = computed(() => { - const classArr = ['sticky-header-column-table', 'w-grid']; + const classArr = ['sticky-header-column-table']; if (table.stickyNum && table.stickyNum > 0) { if (headerRef.value?.getColumnTitleState()?.columnTitleRowNum > 1) { // 存在多行列头 @@ -1666,14 +1689,14 @@ const refreshStyle = (time = 500) => { if (tableRef.value) { state.refHeightWidth.yLocation = tableRef.value.$el.getBoundingClientRect()?.y; if (tableRef.value.$el.getElementsByClassName('noDataTr').length > 0) { - state.refHeightWidth.noDataTrYLocation = tableRef.value.$el.getElementsByClassName('noDataTr')[0].getBoundingClientRect().y; + state.refHeightWidth.noDataTrYLocation = tableRef.value.$el.getElementsByClassName('noDataTr')[0]?.getBoundingClientRect().y; } state.refHeightWidth.topHeight = tableRef.value.$el.getElementsByClassName('q-table__top')[0]?.clientHeight; state.refHeightWidth.bottomHeight = tableRef.value.$el.getElementsByClassName('q-table__bottom')[0]?.clientHeight; state.refHeightWidth.middleWidth = tableRef.value.$el.getElementsByClassName('q-table__middle')[0]?.clientWidth; state.refHeightWidth.middleScrollWidth = tableRef.value.$el.getElementsByClassName('q-table__middle')[0]?.scrollWidth; state.refHeightWidth.columnHeadHeight = tableRef.value.$el.getElementsByTagName('thead')[0]?.clientHeight; - state.refHeightWidth.tableTitleWidth = tableRef.value.$el.getElementsByClassName('_table-title')[0]?.clientWidth; + state.refHeightWidth.hideHeaderNoDataHeight = tableRef.value.$el.getElementsByClassName('q-table__middle')[0]?.clientHeight; // 判断是否有数据,没数据修改 middleHeight if ((table.rows && table.rows.length > 0) || attrs['hide-bottom']) { state.refHeightWidth.middleHeight = tableRef.value.$el.getElementsByClassName('q-table__middle')[0]?.clientHeight; @@ -1728,11 +1751,15 @@ const refreshStyle = (time = 500) => { column1Width + column2Width + column3Width + column4Width + column5Width + column6Width + column7Width + column8Width + column9Width + 'px', ); } - let titleTotalHeight = tableDom.getElementsByTagName('thead')[0].offsetHeight; + let titleTotalHeight = tableDom.getElementsByTagName('thead')[0]?.offsetHeight; // 无数据时列头会增加一行,多表头的top距离计算会出错,需减掉多出来的提示行。 if (table.rows.length === 0) { - const noDataTrHeight = tableRef.value.$el.getElementsByClassName('noDataTr')[0].offsetHeight; - titleTotalHeight = titleTotalHeight - noDataTrHeight; + const noDataTrHeight = tableRef.value.$el.getElementsByClassName('noDataTr')[0]?.offsetHeight; + if (titleTotalHeight && titleTotalHeight > 0) { + titleTotalHeight = titleTotalHeight - noDataTrHeight; + } else { + titleTotalHeight = noDataTrHeight; + } } state.refHeightWidth.titleTotalHeight = titleTotalHeight; } diff --git a/io.sc.platform.core.frontend/src/platform/components/grid/css/separator.css b/io.sc.platform.core.frontend/src/platform/components/grid/css/separator.css index c61e53f1..9033b69e 100644 --- a/io.sc.platform.core.frontend/src/platform/components/grid/css/separator.css +++ b/io.sc.platform.core.frontend/src/platform/components/grid/css/separator.css @@ -45,6 +45,9 @@ .w-grid .q-table--vertical-separator th:first-child.firstColumn { border-left: 0; } +.w-grid .q-table--vertical-separator th:first-child:not([rowspan]) { + border-left: 0; +} /* * vertical * 数据最后一行底部边框 @@ -71,6 +74,9 @@ .w-grid .q-table--cell-separator th:first-child.firstColumn { border-left: 0; } +.w-grid .q-table--cell-separator th:first-child:not([rowspan]) { + border-left: 0; +} /* * cell * 数据最后一行底部边框 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 ef5f0ad4..85e8944d 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 @@ -14,6 +14,12 @@ export const selectMode = { cell: 'cell', // 单元格选择 }; +// 分组模式 +export const groupMode = { + alone: 'alone', // 单独行进行分组 + merge: 'merge', // 合并行进行分组 +}; + // 表格内容区域快速编辑状态 export const editStatus = { none: 'none', // 不在编辑状态 @@ -62,7 +68,7 @@ const childrenHandler = (item: any, gridColumns: any) => { } else { columnStyle(item); const col = { - ...{ align: 'left', label: item.name, field: item.name, name: item.name, sortable: true, hidden: false }, + ...{ align: 'left', label: item.name, field: item.name, name: item.name, sortable: true, showIf: true }, ...item, }; if (Tools.isEmpty(col.name)) { @@ -76,7 +82,7 @@ const childrenHandler = (item: any, gridColumns: any) => { export const columnDefaultProps = (columns: any, sortNo: boolean) => { const gridColumns = []; if (columns && columns.length > 0) { - gridColumns.push({ name: '_sortNo_', align: 'center', label: t('rownum'), field: '_sortNo_', hidden: sortNo ? false : true }); + gridColumns.push({ name: '_sortNo_', align: 'center', label: t('rownum'), field: '_sortNo_', showIf: sortNo }); columns.forEach((item: any) => { childrenHandler(item, gridColumns); }); @@ -85,19 +91,6 @@ export const columnDefaultProps = (columns: any, sortNo: boolean) => { return []; }; -// 获取所有需要合并的列名 -export const getMergeColumns = (columns) => { - const columnNames = []; - if (columns && columns.length > 0) { - columns.forEach((item) => { - if (Tools.hasOwnProperty(item, 'autoMerge') && item['autoMerge']) { - columnNames.push(item['name']); - } - }); - } - return columnNames; -}; - export const sortByProperties = (arr, properties) => { for (const prop of properties) { arr.sort((a, b) => {