Browse Source

表格优化提交

main
likunming 1 year ago
parent
commit
1d2665c940
  1. 2
      io.sc.platform.core.frontend/src/platform/components/form/WForm.vue
  2. 296
      io.sc.platform.core.frontend/src/platform/components/grid/GridConfig.vue
  3. 18
      io.sc.platform.core.frontend/src/platform/components/grid/TreeGridRow.vue
  4. 450
      io.sc.platform.core.frontend/src/platform/components/grid/WGrid.vue
  5. 14
      io.sc.platform.core.frontend/src/platform/components/toolbar/ChildrenBtn.vue
  6. 13
      io.sc.platform.core.frontend/src/platform/components/toolbar/WToolbar.vue
  7. 6
      io.sc.platform.core.frontend/src/platform/components/utils/componentComm.ts
  8. 112
      io.sc.platform.core.frontend/src/views/likm/Grid.vue
  9. 41
      io.sc.platform.core.frontend/src/views/likm/TreeGrid.vue

2
io.sc.platform.core.frontend/src/platform/components/form/WForm.vue

@ -72,7 +72,7 @@ const fiedType = {
const defaultValueHandler = (field) => { const defaultValueHandler = (field) => {
if (field.hasOwnProperty('defaultValue') && field.defaultValue !== null && field.defaultValue !== undefined) { if (field.hasOwnProperty('defaultValue') && field.defaultValue !== null && field.defaultValue !== undefined) {
return field.defaultValue; return field.defaultValue;
} else if (field.type === 'w-checkbox') { } else if (field.type === 'checkbox' || field.type === 'w-checkbox') {
return false; return false;
} }
return null; return null;

296
io.sc.platform.core.frontend/src/platform/components/grid/GridConfig.vue

@ -0,0 +1,296 @@
<template>
<q-list padding style="min-width: 250px">
<q-item :clickable="false" dense>
<q-item-section>
<q-item-label>全屏</q-item-label>
</q-item-section>
<q-item-section side>
<q-btn-group outline flat dense unelevated spread>
<q-btn
:color="!scope.inFullscreen ? 'primary' : ''"
:outline="scope.inFullscreen ? true : false"
dense
label="正常"
unelevated
@click="
() => {
if (scope.inFullscreen) {
scope.toggleFullscreen();
table.gridConfig = false;
}
}
"
/>
<q-btn
:color="scope.inFullscreen ? 'primary' : ''"
:outline="!scope.inFullscreen ? true : false"
dense
label="全屏"
unelevated
@click="
() => {
if (!scope.inFullscreen) {
scope.toggleFullscreen();
table.gridConfig = false;
}
}
"
/>
</q-btn-group>
</q-item-section>
</q-item>
<q-separator spaced />
<q-item :clickable="false" dense>
<q-item-section>
<q-item-label>复选框</q-item-label>
</q-item-section>
<q-item-section side>
<q-btn-group outline flat dense unelevated spread>
<q-btn
:color="table.checkboxSelection ? 'primary' : ''"
:outline="table.checkboxSelection ? false : true"
dense
label="显示"
unelevated
@click="
() => {
table.checkboxSelection = true;
grid.stickyHeaderColumn(100);
}
"
/>
<q-btn
:color="table.checkboxSelection ? '' : 'primary'"
:outline="table.checkboxSelection ? true : false"
dense
label="隐藏"
unelevated
@click="
() => {
table.checkboxSelection = false;
grid.stickyHeaderColumn(100);
}
"
/>
</q-btn-group>
</q-item-section>
</q-item>
<template v-if="!gridProps.tree">
<q-separator spaced />
<q-item :clickable="false" dense>
<q-item-section>
<q-item-label>序号</q-item-label>
</q-item-section>
<q-item-section side>
<q-btn-group outline flat dense unelevated spread>
<q-btn
:color="table.sortNo ? 'primary' : ''"
:outline="table.sortNo ? false : true"
dense
label="显示"
unelevated
@click="
() => {
table.columns[0].hidden = false;
table.sortNo = true;
grid.stickyHeaderColumn(100);
}
"
/>
<q-btn
:color="table.sortNo ? '' : 'primary'"
:outline="table.sortNo ? true : false"
dense
label="隐藏"
unelevated
@click="
() => {
table.columns[0].hidden = true;
table.sortNo = false;
grid.stickyHeaderColumn(100);
}
"
/>
</q-btn-group>
</q-item-section>
</q-item>
</template>
<q-separator spaced />
<q-expansion-item label="紧凑模式">
<q-card>
<q-card-section>
<q-item v-ripple tag="label" dense :disable="denseDisableComputed">
<q-item-section side>
<q-checkbox v-model="table.dense" dense :disable="denseDisableComputed" @update:model-value="denseChange()" />
</q-item-section>
<q-item-section>
<q-item-label>紧凑</q-item-label>
</q-item-section>
</q-item>
<q-item v-ripple tag="label" dense :disable="denseOtherDisableComputed">
<q-item-section side>
<q-checkbox v-model="table.denseToolbar" :disable="denseOtherDisableComputed" dense @update:model-value="denseChange" />
</q-item-section>
<q-item-section>
<q-item-label>按钮栏紧凑</q-item-label>
</q-item-section>
</q-item>
<q-item v-ripple tag="label" dense :disable="denseOtherDisableComputed">
<q-item-section side>
<q-checkbox v-model="table.denseHeader" :disable="denseOtherDisableComputed" dense @update:model-value="denseChange" />
</q-item-section>
<q-item-section>
<q-item-label>列头紧凑</q-item-label>
</q-item-section>
</q-item>
<q-item v-ripple tag="label" dense :disable="denseOtherDisableComputed">
<q-item-section side>
<q-checkbox v-model="table.denseBody" :disable="denseOtherDisableComputed" dense @update:model-value="denseChange" />
</q-item-section>
<q-item-section>
<q-item-label>内容紧凑</q-item-label>
</q-item-section>
</q-item>
<q-item v-ripple tag="label" dense :disable="denseOtherDisableComputed">
<q-item-section side>
<q-checkbox v-model="table.denseBottom" :disable="denseOtherDisableComputed" dense @update:model-value="denseChange" />
</q-item-section>
<q-item-section>
<q-item-label>分页栏紧凑</q-item-label>
</q-item-section>
</q-item>
</q-card-section>
</q-card>
</q-expansion-item>
<q-separator spaced />
<q-item :clickable="false" dense>
<q-item-section>
<q-item-label class="nowrap text-nowrap">固定列</q-item-label>
</q-item-section>
<q-item-section side>
<q-select
v-model="table.stickyNum"
emit-value
map-options
:hide-bottom-space="true"
:hide-hint="true"
:outlined="true"
:dense="true"
:options="stickyOptions"
@update:model-value="
() => {
grid.stickyHeaderColumn(500);
}
"
>
</q-select>
</q-item-section>
</q-item>
<q-separator spaced />
<q-item-label header>显示列</q-item-label>
<template v-for="col in table.columns" :key="col.name">
<q-item v-if="showColumn(col.name)" v-ripple tag="label" dense>
<q-item-section side>
<q-checkbox
v-model="col.hidden"
:false-value="true"
:true-value="false"
dense
@update:model-value="
() => {
grid.stickyHeaderColumn(100);
}
"
/>
</q-item-section>
<q-item-section>
<q-item-label>{{ col.label || col.name }}</q-item-label>
</q-item-section>
</q-item>
</template>
</q-list>
</template>
<script setup lang="ts">
import { ref, reactive, computed, watch, inject } from 'vue';
const props = defineProps({
scope: {
type: Object,
default: () => {
return {};
},
},
gridProps: {
type: Object,
default: () => {
return {};
},
},
moreColumnTitleArray: {
//
type: Array,
default: () => {
return [];
},
},
grid: {
type: Object,
default: () => {
return {};
},
},
});
const table = inject('table');
const stickyOptions = [
{ label: '不固定', value: 0 },
{ label: '固定1列', value: 1 },
{ label: '固定2列', value: 2 },
{ label: '固定3列', value: 3 },
{ label: '固定4列', value: 4 },
{ label: '固定5列', value: 5 },
{ label: '固定6列', value: 6 },
{ label: '固定7列', value: 7 },
{ label: '固定8列', value: 8 },
{ label: '固定9列', value: 9 },
{ label: '固定10列', value: 10 },
];
const sticky = ref(0);
const showColumn = (name) => {
if (props.moreColumnTitleArray.length > 0) {
if (
props.moreColumnTitleArray[0].findIndex((item) => {
return item.name === name;
}) > -1
) {
return true;
} else {
return false;
}
} else {
return true;
}
};
const denseChange = () => {
props.grid.stickyHeaderColumn(0);
};
const denseDisableComputed = computed(() => {
if (table.denseToolbar || table.denseHeader || table.denseBody || table.denseBottom) {
return true;
}
return false;
});
const denseOtherDisableComputed = computed(() => {
if (table.dense) {
return true;
}
return false;
});
</script>

18
io.sc.platform.core.frontend/src/platform/components/grid/TreeGridRow.vue

@ -16,13 +16,7 @@
<!--展开按钮占位符--> <!--展开按钮占位符-->
<span v-else style="width: 27px"></span> <span v-else style="width: 27px"></span>
<!--选择框--> <!--选择框-->
<q-checkbox <q-checkbox v-if="table.checkboxSelection" v-model="state.currRow.selected" flat dense @update:model-value="selectedFun(state.currRow.selected, row)" />
v-if="gridProps.checkboxSelection"
v-model="state.currRow.selected"
flat
dense
@update:model-value="selectedFun(state.currRow.selected, row)"
/>
<!--图标--> <!--图标-->
<q-icon v-if="typeof iconComputed === 'string'" :name="iconComputed" size="20px" class="px-1"></q-icon> <q-icon v-if="typeof iconComputed === 'string'" :name="iconComputed" size="20px" class="px-1"></q-icon>
<q-icon v-else-if="typeof iconComputed === 'object'" size="20px" v-bind="iconComputed" class="px-1"></q-icon> <q-icon v-else-if="typeof iconComputed === 'object'" size="20px" v-bind="iconComputed" class="px-1"></q-icon>
@ -38,8 +32,12 @@
</div> </div>
</q-td> </q-td>
<template v-for="(col, index) in cols" :key="col.name"> <template v-for="(col, index) in cols" :key="col.name">
<q-td v-if="index > 0" :title="col.classes?.indexOf('truncate') > -1 ? col.value : ''" @click="click($event, row, row.rowIndex)"> <q-td
<div class="flex flex-nowrap items-center"> v-if="index > 0"
:title="col.classes?.indexOf('truncate') > -1 && col.value && typeof col.value !== 'object' ? col.value : ''"
@click="click($event, row, row.rowIndex)"
>
<div :class="col.__thClass">
<template v-if="col.value && typeof col.value === 'object' && col.value.componentType"> <template v-if="col.value && typeof col.value === 'object' && col.value.componentType">
<component :is="col.value.componentType" v-bind="col.value.attrs"></component> <component :is="col.value.componentType" v-bind="col.value.attrs"></component>
</template> </template>
@ -59,7 +57,6 @@
:level="props.level + 1" :level="props.level + 1"
:grid-props="gridProps" :grid-props="gridProps"
:row-key="props.rowKey" :row-key="props.rowKey"
:selection="props.selection"
></TreeGridRow> ></TreeGridRow>
</template> </template>
</template> </template>
@ -92,7 +89,6 @@ const props = defineProps({
}, },
}, },
rowKey: { type: String, default: '_rowKey_' }, rowKey: { type: String, default: '_rowKey_' },
selection: { type: String, default: 'single' },
}); });
const table = inject('table'); const table = inject('table');

450
io.sc.platform.core.frontend/src/platform/components/grid/WGrid.vue

@ -2,22 +2,23 @@
<div> <div>
<q-table <q-table
ref="tableRef" ref="tableRef"
v-model:pagination="table.pagination" v-model:pagination="state.pagination"
v-model:selected="table.selected" v-model:selected="table.selected"
flat flat
binary-state-sort binary-state-sort
:no-data-label="table.noDataLabel" :no-data-label="state.noDataLabel"
:loading-label="table.loadingLabel" :loading-label="state.loadingLabel"
v-bind="attrs" v-bind="attrs"
:selection="selectionComputed" :selection="selectionComputed"
separator="cell" separator="cell"
:rows="table.rows" :rows="table.rows"
:columns="extractTableColumns" :columns="extractTableColumns"
:rows-per-page-options="pageable && !tree && table.refHeightWidth.middleWidth > 600 ? table.pagination.rowsPerPageOptions : []" :rows-per-page-options="pageable && !tree && state.refHeightWidth.middleWidth > 600 ? state.pagination.rowsPerPageOptions : []"
:loading="table.loading" :loading="state.loading"
:class="tableClassComputed" :class="tableClassComputed"
:table-style="tableHeightComputed" :table-style="tableHeightComputed"
:row-key="rowKey_" :row-key="rowKey_"
:visible-columns="visibleColumnsComputed"
@request="onRequest" @request="onRequest"
@fullscreen="tableFullscreenFun" @fullscreen="tableFullscreenFun"
> >
@ -29,6 +30,7 @@
<div class="flex-none">{{ title }}</div> <div class="flex-none">{{ title }}</div>
<div class="flex-1"> <div class="flex-1">
<w-toolbar <w-toolbar
:dense="denseToolbarComputed"
v-bind="toolbarConfigure" v-bind="toolbarConfigure"
:buttons="buttons_" :buttons="buttons_"
:grid-props="{ :grid-props="{
@ -37,11 +39,11 @@
}" }"
></w-toolbar> ></w-toolbar>
</div> </div>
<div v-if="fullScreenButton" class="flex-none pl-1"> <div v-if="configButton" class="flex-none pl-1">
<q-btn :icon="scope.inFullscreen ? IconEnum.退出全屏 : IconEnum.全屏" unelevated outline @click="scope.toggleFullscreen"> <q-btn round dense :size="denseToolbarComputed ? '13px' : '14px'" :icon="IconEnum.设置" unelevated outline>
<q-tooltip transition-show="rotate" transition-hide="rotate"> <q-popup-proxy v-model="table.gridConfig">
{{ scope.inFullscreen ? '退出全屏' : '全屏' }} <GridConfig :scope="scope" :grid-props="props" :more-column-title-array="columnTitleState.columnTitleArr" :grid="instance"></GridConfig>
</q-tooltip> </q-popup-proxy>
</q-btn> </q-btn>
</div> </div>
</div> </div>
@ -52,13 +54,15 @@
<template v-if="columnTitleState.columnTitleRowNum > 1"> <template v-if="columnTitleState.columnTitleRowNum > 1">
<q-tr v-for="(r, rIndex) in columnTitleState.columnTitleArr" :key="rIndex"> <q-tr v-for="(r, rIndex) in columnTitleState.columnTitleArr" :key="rIndex">
<q-th <q-th
v-if="rIndex === 0 && selectionComputed === 'multiple' && props.checkboxSelection && !props.tree" v-if="rIndex === 0 && selectionComputed === 'multiple' && table.checkboxSelection && !props.tree"
:rowspan="columnTitleState.columnTitleRowNum" :rowspan="columnTitleState.columnTitleRowNum"
:style="moreColumnTitleTableSelectionStyle" :style="moreColumnTitleTableSelectionStyle"
> >
<q-checkbox v-model="scope.selected" flat :dense="denseHeader || attrs.dense ? true : false" /> <q-checkbox v-model="scope.selected" flat :dense="denseHeaderComputed" />
</q-th>
<q-th v-if="rIndex === 0 && table.sortNo && !props.tree" :rowspan="columnTitleState.columnTitleRowNum" :style="moreColumnTitleTableSortNoStyle">
序号
</q-th> </q-th>
<q-th v-if="rIndex === 0 && props.sortNo" :rowspan="columnTitleState.columnTitleRowNum" :style="moreColumnTitleTableSortNoStyle"> 序号 </q-th>
<q-th <q-th
v-for="c in r" v-for="c in r"
:key="c.name" :key="c.name"
@ -67,6 +71,7 @@
:style="thStyleHandler(c, scope)" :style="thStyleHandler(c, scope)"
:class="c.classes" :class="c.classes"
:props="titleScopeHandler(c, scope)" :props="titleScopeHandler(c, scope)"
style="font-weight: bold"
> >
{{ c.label }} {{ c.label }}
</q-th> </q-th>
@ -75,33 +80,33 @@
<template v-else> <template v-else>
<q-tr :props="scope"> <q-tr :props="scope">
<q-th <q-th
v-if="selectionComputed === 'multiple' && props.checkboxSelection && !props.tree" v-if="selectionComputed === 'multiple' && table.checkboxSelection && !props.tree"
:style="props.tree ? '' : 'padding: 0; width: 50px'" :style="props.tree ? '' : 'padding: 0; width: 50px'"
auto-width auto-width
> >
<q-checkbox v-model="scope.selected" flat :dense="denseHeader || attrs.dense ? true : false" <q-checkbox v-model="scope.selected" flat :dense="denseHeaderComputed"
/></q-th> /></q-th>
<q-th v-else-if="props.checkboxSelection && !props.tree"></q-th> <q-th v-else-if="table.checkboxSelection && !props.tree"></q-th>
<q-th v-for="col in scope.cols" :key="col.name" :props="scope" :style="col.style" :class="col.classes"> <template v-for="col in scope.cols" :key="col.name">
<q-th
:props="scope"
:style="col.style + (col.name === '_sortNo_' ? 'padding: 0; width: 50px;' : '')"
:class="col.classes"
style="font-weight: bold"
>
{{ col.label }} {{ col.label }}
</q-th> </q-th>
</template>
</q-tr> </q-tr>
</template> </template>
</template> </template>
<template #body="scope"> <template #body="scope">
<template v-if="tree"> <template v-if="tree">
<TreeGridRow <TreeGridRow :columns-map="tableColumnsMap" :row="scope.row" :cols="scope.cols" :grid-props="props" :row-key="rowKey_"></TreeGridRow>
:columns-map="tableColumnsMap"
:row="scope.row"
:cols="scope.cols"
:grid-props="props"
:row-key="rowKey_"
:selection="selectionComputed"
></TreeGridRow>
</template> </template>
<q-tr v-else :props="scope" @click="rowClick($event, scope.row, scope.rowIndex)" @dblclick="rowDbClick($el, scope.row, scope.rowIndex)"> <q-tr v-else :props="scope" @click="rowClick($event, scope.row, scope.rowIndex)" @dblclick="rowDbClick($el, scope.row, scope.rowIndex)">
<q-td v-if="props.checkboxSelection" class="text-center" style="padding: 0; width: 50px"> <q-td v-if="table.checkboxSelection" class="text-center" style="padding: 0; width: 50px">
<q-checkbox v-model="scope.selected" flat :dense="denseBody || attrs.dense ? true : false" /> <q-checkbox v-model="scope.selected" flat :dense="denseBodyComputed" />
</q-td> </q-td>
<template v-if="draggable"> <template v-if="draggable">
<q-td <q-td
@ -128,7 +133,12 @@
</q-td> </q-td>
</template> </template>
<template v-else> <template v-else>
<q-td v-for="col in scope.cols" :key="col.name" :props="scope" :title="col.classes?.indexOf('truncate') > -1 ? col.value : ''"> <q-td
v-for="col in scope.cols"
:key="col.name"
:props="scope"
:title="col.classes?.indexOf('truncate') > -1 && col.value && typeof col.value !== 'object' ? col.value : ''"
>
<template v-if="col.name === '_sortNo_'"> <template v-if="col.name === '_sortNo_'">
{{ scope.rowIndex + 1 }} {{ scope.rowIndex + 1 }}
</template> </template>
@ -143,41 +153,43 @@
</q-tr> </q-tr>
</template> </template>
<template #loading> <template #loading>
<q-inner-loading :showing="table.loading" style="z-index: 999"> <q-inner-loading :showing="state.loading" style="z-index: 999">
<q-spinner-gears size="50px" color="primary" /> <q-spinner-gears size="50px" color="primary" />
</q-inner-loading> </q-inner-loading>
</template> </template>
<template #pagination="scope"> <template #pagination="scope">
<template v-if="pageable && !tree"> <template v-if="pageable && !tree">
<template v-if="table.refHeightWidth.middleWidth > 600"> <template v-if="state.refHeightWidth.middleWidth > 600">
<q-pagination <q-pagination
v-model="table.pagination.page" v-model="state.pagination.page"
:boundary-links="table.pagination.config.boundaryLinks" :boundary-links="state.pagination.config.boundaryLinks"
:boundary-numbers="table.pagination.config.boundaryNumbers" :boundary-numbers="state.pagination.config.boundaryNumbers"
:direction-links="table.pagination.config.directionLinks" :direction-links="state.pagination.config.directionLinks"
:ellipses="table.pagination.config.ellipses" :ellipses="state.pagination.config.ellipses"
:max-pages="table.pagination.config.maxPages" :max-pages="state.pagination.config.maxPages"
:min="1" :min="1"
:max="scope.pagesNumber" :max="scope.pagesNumber"
:size="denseBottomComputed ? '10px' : ''"
@update:model-value="pageChange" @update:model-value="pageChange"
/> />
</template> </template>
<template v-else> <template v-else>
<q-pagination <q-pagination
v-model="table.pagination.page" v-model="state.pagination.page"
:boundary-links="table.pagination.config.boundaryLinks" :boundary-links="state.pagination.config.boundaryLinks"
:boundary-numbers="table.pagination.config.boundaryNumbers" :boundary-numbers="state.pagination.config.boundaryNumbers"
:direction-links="table.pagination.config.directionLinks" :direction-links="state.pagination.config.directionLinks"
:ellipses="table.pagination.config.ellipses" :ellipses="state.pagination.config.ellipses"
:max-pages="3" :max-pages="3"
:min="1" :min="1"
:max="scope.pagesNumber" :max="scope.pagesNumber"
:size="denseBottomComputed ? '10px' : ''"
@update:model-value="pageChange" @update:model-value="pageChange"
/> />
</template> </template>
<span> {{ table.pagination.rowsNumber }} 条记录</span> <span> {{ state.pagination.rowsNumber }} 条记录</span>
</template> </template>
<template v-else> 当前未启用分页 {{ table.pagination.rowsNumber }} 条记录 </template> <template v-else> {{ state.pagination.rowsNumber }} 条记录 </template>
</template> </template>
<template v-if="!attrs.hideBottom" #no-data="{ message }"> <template v-if="!attrs.hideBottom" #no-data="{ message }">
<div class="full-width row flex-center text-dark q-gutter-sm" :style="`height:` + noDataBottomHeightComputed"> <div class="full-width row flex-center text-dark q-gutter-sm" :style="`height:` + noDataBottomHeightComputed">
@ -206,7 +218,7 @@ import { useQuasar, getCssVar, exportFile } from 'quasar';
import { IconEnum } from '@/platform/enums'; import { IconEnum } from '@/platform/enums';
import { extractTableColumnsProps, arrayToMap, OperatorTypeEnum, isEmpty, PageStatusEnum } from '@/platform/components/utils'; import { extractTableColumnsProps, arrayToMap, OperatorTypeEnum, isEmpty, PageStatusEnum } from '@/platform/components/utils';
import TreeGridRow from './TreeGridRow.vue'; import TreeGridRow from './TreeGridRow.vue';
import { mergeProps } from 'vue'; import GridConfig from './GridConfig.vue';
const attrs = useAttrs(); const attrs = useAttrs();
const gc = Environment.getConfigure(); const gc = Environment.getConfigure();
@ -221,16 +233,19 @@ const props = defineProps({
autoFetchData: { type: Boolean, default: true }, // autoFetchData: { type: Boolean, default: true }, //
draggable: { type: Boolean, default: false }, // draggable: { type: Boolean, default: false }, //
pageable: { type: Boolean, default: true }, // pageable: { type: Boolean, default: true }, //
fullScreenButton: { type: Boolean, default: true }, // configButton: { type: Boolean, default: true }, //
dataUrl: { type: String, default: '' }, // URL dataUrl: { type: String, default: '' }, // URL
fetchDataUrl: { type: String, default: '' }, // URL fetchDataUrl: { type: String, default: '' }, // URL
addDataUrl: { type: String, default: '' }, // url addDataUrl: { type: String, default: '' }, // url
editDataUrl: { type: String, default: '' }, // url editDataUrl: { type: String, default: '' }, // url
removeDataUrl: { type: String, default: '' }, // url removeDataUrl: { type: String, default: '' }, // url
denseHeader: { type: Boolean, default: false }, // dense: { type: Boolean, default: undefined }, //
denseBody: { type: Boolean, default: false }, // denseHeader: { type: Boolean, default: undefined }, //
denseBody: { type: Boolean, default: undefined }, //
denseBottom: { type: Boolean, default: undefined }, //
denseToolbar: { type: Boolean, default: undefined }, // toolbar
sortNo: { type: Boolean, default: false }, // sortNo: { type: Boolean, default: false }, //
leftColumnStickyNumber: { type: Number, default: 0 }, // 1-10el stickyNum: { type: Number, default: 0 }, // 1-10el
checkboxSelection: { type: Boolean, default: true }, // checkbox checkboxSelection: { type: Boolean, default: true }, // checkbox
tree: { type: Boolean, default: false }, // tree: { type: Boolean, default: false }, //
treeIcon: { type: Function, default: undefined }, // treeIcon: { type: Function, default: undefined }, //
@ -540,7 +555,7 @@ const buttonObj = {
.then((resp) => { .then((resp) => {
table.selected = []; table.selected = [];
NotifyManager.info('操作成功'); NotifyManager.info('操作成功');
onRequest({ pagination: table.pagination }); onRequest({ pagination: state.pagination });
}) })
.catch((error) => { .catch((error) => {
console.info('error====', error); console.info('error====', error);
@ -642,13 +657,85 @@ const table = reactive({
selected: <any>[], selected: <any>[],
ticked: <any>[], ticked: <any>[],
spaceHeight: 4, spaceHeight: 4,
headerCellHeight: props.denseHeader || attrs.dense ? 24 : 48, gridConfig: false,
bodyCellHeight: attrs.dense ? 24 : 48, stickyNum: props.stickyNum,
columns: extractTableColumns,
checkboxSelection: props.checkboxSelection,
sortNo: props.sortNo,
dense: props.dense !== undefined ? props.dense : false,
denseToolbar: props.denseToolbar !== undefined ? props.denseToolbar : false,
denseHeader: props.denseHeader !== undefined ? props.denseHeader : false,
denseBody: props.denseBody !== undefined ? props.denseBody : false,
denseBottom: props.denseBottom !== undefined ? props.denseBottom : false,
queryFormFields: [],
moreQueryStatus: false, //
rows: <any>[],
inFullscreen: false, //
});
provide('table', table);
const denseToolbarComputed = computed(() => {
if (table.denseToolbar) {
return true;
} else if (table.dense !== false) {
return true;
} else {
return false;
}
});
const denseHeaderComputed = computed(() => {
if (table.denseHeader) {
return true;
} else if (table.dense !== false) {
return true;
} else {
return false;
}
});
const denseBodyComputed = computed(() => {
if (table.denseBody) {
return true;
} else if (table.dense !== false) {
return true;
} else {
return false;
}
});
const denseBottomComputed = computed(() => {
if (table.denseBottom) {
return true;
} else if (table.dense !== false) {
return true;
} else {
return false;
}
});
const visibleColumnsComputed = computed(() => {
const visibleColumns: string[] = [];
table.columns.forEach((item) => {
if (!item.hidden && (!props.tree || (props.tree && item.name !== '_sortNo_'))) {
visibleColumns.push(item.name);
}
});
return visibleColumns;
});
const state = reactive({
noDataLabel: '没有可用数据', noDataLabel: '没有可用数据',
loading: false, loading: false,
loadingLabel: '数据加载中', loadingLabel: '数据加载中',
queryFormFields: [], bodyCellHeight: denseBodyComputed.value ? 24 : 48,
moreQueryStatus: false, //
refHeightWidth: {
yLocation: 0, // Y
topHeight: 0, // top
bottomHeight: 0, // bottom
middleWidth: 0, // middle
middleScrollWidth: 0, // middleWidth
middleHeight: 0, // middle()
columnHeadHeight: 0, //
tableTitleWidth: 0, // title
},
pagination: { pagination: {
config: { config: {
boundaryLinks: true, // boundaryLinks: true, //
@ -665,21 +752,7 @@ const table = reactive({
rowsNumber: 10, rowsNumber: 10,
rowsPerPageOptions: [5, 10, 20, 50, 100], rowsPerPageOptions: [5, 10, 20, 50, 100],
}, },
rows: <any>[],
//
refHeightWidth: {
yLocation: 0, // Y
topHeight: 0, // top
bottomHeight: 0, // bottom
middleWidth: 0, // middle
middleScrollWidth: 0, // middleWidth
middleHeight: 0, // middle()
columnHeadHeight: 0, //
tableTitleWidth: 0, // title
},
inFullscreen: false, //
}); });
provide('table', table);
const dialog = reactive({ const dialog = reactive({
dialogTitle: '新增', dialogTitle: '新增',
@ -865,9 +938,9 @@ const tableHeightComputed = computed(() => {
const otherHeight = table.spaceHeight || 4; const otherHeight = table.spaceHeight || 4;
const resultHeight = const resultHeight =
screenHeight - screenHeight -
table.refHeightWidth.yLocation - state.refHeightWidth.yLocation -
(table.refHeightWidth.topHeight || 0) - (state.refHeightWidth.topHeight || 0) -
(table.refHeightWidth.bottomHeight || 0) - (state.refHeightWidth.bottomHeight || 0) -
footerHeight - footerHeight -
mainPaddingBottom - mainPaddingBottom -
mainContainerPaddingBottom - mainContainerPaddingBottom -
@ -878,7 +951,7 @@ const tableHeightComputed = computed(() => {
}; };
} else { } else {
return { return {
height: table.refHeightWidth.middleHeight + 'px', height: state.refHeightWidth.middleHeight + 'px',
}; };
} }
}); });
@ -896,9 +969,9 @@ const noDataBottomHeightComputed = computed(() => {
const mainContainerPaddingBottom = gc.theme.main.containerPaddingBottom || 0; const mainContainerPaddingBottom = gc.theme.main.containerPaddingBottom || 0;
const resultHeight = const resultHeight =
screenHeight - screenHeight -
table.refHeightWidth.yLocation - state.refHeightWidth.yLocation -
table.refHeightWidth.topHeight - state.refHeightWidth.topHeight -
table.refHeightWidth.middleHeight - state.refHeightWidth.middleHeight -
mainPaddingBottom - mainPaddingBottom -
mainContainerPaddingBottom - mainContainerPaddingBottom -
footerHeight - footerHeight -
@ -915,9 +988,9 @@ let tableY = 0;
const tableFullscreenFun = (value) => { const tableFullscreenFun = (value) => {
table.inFullscreen = !table.inFullscreen; table.inFullscreen = !table.inFullscreen;
if (value) { if (value) {
tableY = table.refHeightWidth.yLocation; tableY = state.refHeightWidth.yLocation;
} else { } else {
table.refHeightWidth.yLocation = tableY; state.refHeightWidth.yLocation = tableY;
tableY = 0; tableY = 0;
} }
}; };
@ -943,22 +1016,22 @@ const rowDbClick = (evt, row, index) => {
const onResize = () => { const onResize = () => {
handlerQueryFormShowField(); handlerQueryFormShowField();
if (tableRef.value) { if (tableRef.value) {
table.refHeightWidth.yLocation = tableRef.value.$el.getBoundingClientRect().y; state.refHeightWidth.yLocation = tableRef.value.$el.getBoundingClientRect().y;
table.refHeightWidth.topHeight = tableRef.value.$el.getElementsByClassName('q-table__top')[0]?.clientHeight; state.refHeightWidth.topHeight = tableRef.value.$el.getElementsByClassName('q-table__top')[0]?.clientHeight;
table.refHeightWidth.middleWidth = tableRef.value.$el.getElementsByClassName('q-table__middle')[0]?.clientWidth; state.refHeightWidth.middleWidth = tableRef.value.$el.getElementsByClassName('q-table__middle')[0]?.clientWidth;
table.refHeightWidth.middleScrollWidth = tableRef.value.$el.getElementsByClassName('q-table__middle')[0]?.scrollWidth; state.refHeightWidth.middleScrollWidth = tableRef.value.$el.getElementsByClassName('q-table__middle')[0]?.scrollWidth;
table.refHeightWidth.columnHeadHeight = tableRef.value.$el.getElementsByTagName('thead')[0]?.clientHeight; state.refHeightWidth.columnHeadHeight = tableRef.value.$el.getElementsByTagName('thead')[0]?.clientHeight;
// middleHeight // middleHeight
if ((table.rows && table.rows.length > 0) || attrs.hideBottom) { if ((table.rows && table.rows.length > 0) || attrs.hideBottom) {
table.refHeightWidth.middleHeight = tableRef.value.$el.getElementsByClassName('q-table__middle')[0]?.clientHeight; state.refHeightWidth.middleHeight = tableRef.value.$el.getElementsByClassName('q-table__middle')[0]?.clientHeight;
} else { } else {
let scrollHeight = 0; let scrollHeight = 0;
if (table.refHeightWidth.middleScrollWidth - table.refHeightWidth.middleWidth > 0) { if (state.refHeightWidth.middleScrollWidth - state.refHeightWidth.middleWidth > 0) {
scrollHeight = 15; scrollHeight = 15;
} }
table.refHeightWidth.middleHeight = table.refHeightWidth.columnHeadHeight + scrollHeight; state.refHeightWidth.middleHeight = state.refHeightWidth.columnHeadHeight + scrollHeight;
} }
table.refHeightWidth.tableTitleWidth = tableRef.value.$el.getElementsByClassName('_table-title')[0]?.clientWidth; state.refHeightWidth.tableTitleWidth = tableRef.value.$el.getElementsByClassName('_table-title')[0]?.clientWidth;
} }
}; };
@ -1007,7 +1080,7 @@ const buildQueryEntity = (reqParams) => {
}; };
const pageChange = (value) => { const pageChange = (value) => {
table.pagination.page = value; state.pagination.page = value;
onRequest(table); onRequest(table);
}; };
const requestHandler = async (ops) => { const requestHandler = async (ops) => {
@ -1034,34 +1107,34 @@ const requestHandler = async (ops) => {
}); });
const resp = await axios.get(url.fetchDataUrl || url.dataUrl, { params: urlSearchParams }).catch((error) => { const resp = await axios.get(url.fetchDataUrl || url.dataUrl, { params: urlSearchParams }).catch((error) => {
console.info('error-------------', error); console.info('error-------------', error);
table.loading = false; state.loading = false;
}); });
return resp; return resp;
}; };
const onRequest = async (ops: any) => { const onRequest = async (ops: any) => {
table.loading = true; state.loading = true;
const resp: any = await requestHandler(ops); const resp: any = await requestHandler(ops);
table.loading = false; state.loading = false;
if (resp && resp.data && !props.tree) { if (resp && resp.data && !props.tree) {
const responseData = resp.data; const responseData = resp.data;
if (Array.isArray(responseData)) { if (Array.isArray(responseData)) {
table.rows = responseData; table.rows = responseData;
table.pagination.rowsNumber = responseData.length; state.pagination.rowsNumber = responseData.length;
} else if (typeof responseData === 'object' && responseData.content) { } else if (typeof responseData === 'object' && responseData.content) {
if (props.pageable) { if (props.pageable) {
table.pagination.page = table.pagination.reqPageStart === 0 ? responseData.number + 1 : responseData.number; state.pagination.page = state.pagination.reqPageStart === 0 ? responseData.number + 1 : responseData.number;
table.pagination.rowsPerPage = responseData.size || table.pagination.rowsPerPage; state.pagination.rowsPerPage = responseData.size || state.pagination.rowsPerPage;
} }
table.pagination.rowsNumber = responseData.totalElements; state.pagination.rowsNumber = responseData.totalElements;
table.pagination.sortBy = ops.pagination.sortBy; state.pagination.sortBy = ops.pagination.sortBy;
table.pagination.descending = ops.pagination.descending; state.pagination.descending = ops.pagination.descending;
table.rows = responseData.content; table.rows = responseData.content;
} }
} else if (resp && resp.data && props.tree) { } else if (resp && resp.data && props.tree) {
const responseData = resp.data; const responseData = resp.data;
if (Array.isArray(responseData)) { if (Array.isArray(responseData)) {
table.pagination.rowsNumber = responseData.length; state.pagination.rowsNumber = responseData.length;
table.pagination.rowsPerPage = 0; state.pagination.rowsPerPage = 0;
if (props.treeRelationship === 'parent') { if (props.treeRelationship === 'parent') {
const treeRows = TreeBuilder.build(responseData, props.foreignKey, props.primaryKey); const treeRows = TreeBuilder.build(responseData, props.foreignKey, props.primaryKey);
table.rows = treeRows; table.rows = treeRows;
@ -1069,8 +1142,8 @@ const onRequest = async (ops: any) => {
table.rows = responseData; table.rows = responseData;
} }
} else if (typeof responseData === 'object' && responseData.content) { } else if (typeof responseData === 'object' && responseData.content) {
table.pagination.rowsNumber = responseData.content.length; state.pagination.rowsNumber = responseData.content.length;
table.pagination.rowsPerPage = 0; state.pagination.rowsPerPage = 0;
if (props.treeRelationship === 'parent') { if (props.treeRelationship === 'parent') {
const treeRows = TreeBuilder.build(responseData.content, props.foreignKey, props.primaryKey); const treeRows = TreeBuilder.build(responseData.content, props.foreignKey, props.primaryKey);
table.rows = treeRows; table.rows = treeRows;
@ -1131,7 +1204,7 @@ const save = async () => {
emit('addEditDataSubmitAfter', resp.data); emit('addEditDataSubmitAfter', resp.data);
NotifyManager.info('操作成功'); NotifyManager.info('操作成功');
dialogRef.value.hide(); dialogRef.value.hide();
onRequest({ pagination: table.pagination }); onRequest({ pagination: state.pagination });
table.selected = []; table.selected = [];
}) })
.catch((error) => { .catch((error) => {
@ -1292,35 +1365,35 @@ watchEffect(() => {
const refresh = () => { const refresh = () => {
nextTick(() => { nextTick(() => {
onRequest({ onRequest({
pagination: table.pagination, pagination: state.pagination,
}); });
}); });
}; };
const stickyHeaderColumn = () => { const stickyHeaderColumn = (time = 500) => {
setTimeout(() => { setTimeout(() => {
// //
if (tableRef.value) { if (tableRef.value) {
table.refHeightWidth.yLocation = tableRef.value.$el.getBoundingClientRect()?.y; state.refHeightWidth.yLocation = tableRef.value.$el.getBoundingClientRect()?.y;
table.refHeightWidth.topHeight = tableRef.value.$el.getElementsByClassName('q-table__top')[0]?.clientHeight; state.refHeightWidth.topHeight = tableRef.value.$el.getElementsByClassName('q-table__top')[0]?.clientHeight;
table.refHeightWidth.bottomHeight = tableRef.value.$el.getElementsByClassName('q-table__bottom')[0]?.clientHeight; state.refHeightWidth.bottomHeight = tableRef.value.$el.getElementsByClassName('q-table__bottom')[0]?.clientHeight;
table.refHeightWidth.middleWidth = tableRef.value.$el.getElementsByClassName('q-table__middle')[0]?.clientWidth; state.refHeightWidth.middleWidth = tableRef.value.$el.getElementsByClassName('q-table__middle')[0]?.clientWidth;
table.refHeightWidth.middleScrollWidth = tableRef.value.$el.getElementsByClassName('q-table__middle')[0]?.scrollWidth; state.refHeightWidth.middleScrollWidth = tableRef.value.$el.getElementsByClassName('q-table__middle')[0]?.scrollWidth;
table.refHeightWidth.columnHeadHeight = tableRef.value.$el.getElementsByTagName('thead')[0]?.clientHeight; state.refHeightWidth.columnHeadHeight = tableRef.value.$el.getElementsByTagName('thead')[0]?.clientHeight;
table.refHeightWidth.tableTitleWidth = tableRef.value.$el.getElementsByClassName('_table-title')[0]?.clientWidth; state.refHeightWidth.tableTitleWidth = tableRef.value.$el.getElementsByClassName('_table-title')[0]?.clientWidth;
// middleHeight // middleHeight
if ((table.rows && table.rows.length > 0) || attrs.hideBottom) { if ((table.rows && table.rows.length > 0) || attrs.hideBottom) {
table.refHeightWidth.middleHeight = tableRef.value.$el.getElementsByClassName('q-table__middle')[0]?.clientHeight; state.refHeightWidth.middleHeight = tableRef.value.$el.getElementsByClassName('q-table__middle')[0]?.clientHeight;
} else { } else {
let scrollHeight = 0; let scrollHeight = 0;
if (table.refHeightWidth.middleScrollWidth - table.refHeightWidth.middleWidth > 0) { if (state.refHeightWidth.middleScrollWidth - state.refHeightWidth.middleWidth > 0) {
scrollHeight = 15; scrollHeight = 15;
} }
table.refHeightWidth.middleHeight = table.refHeightWidth.columnHeadHeight + scrollHeight; state.refHeightWidth.middleHeight = state.refHeightWidth.columnHeadHeight + scrollHeight;
} }
const tableDom = tableRef.value.$el.getElementsByTagName('table')[0]; const tableDom = tableRef.value.$el.getElementsByTagName('table')[0];
if (props.leftColumnStickyNumber > 0) { if (table.stickyNum > 0) {
if (columnTitleState.columnTitleRowNum > 1) { if (columnTitleState.columnTitleRowNum > 1) {
const theadDom = tableDom.getElementsByTagName('thead')[0]; const theadDom = tableDom.getElementsByTagName('thead')[0];
const theadTrDom = theadDom.getElementsByTagName('tr'); const theadTrDom = theadDom.getElementsByTagName('tr');
@ -1385,20 +1458,41 @@ const stickyHeaderColumn = () => {
tableDom.style.setProperty('--row9Height', row9Height + 'px'); tableDom.style.setProperty('--row9Height', row9Height + 'px');
} }
} }
}, 500); }, time);
tableRef.value.$el.getElementsByTagName('table')[0].style.setProperty('--tableHeadBgColor', tableHeadBgColor); tableRef.value.$el.getElementsByTagName('table')[0].style.setProperty('--tableHeadBgColor', tableHeadBgColor);
tableRef.value.$el.getElementsByTagName('table')[0].style.setProperty('--stickyBgColor', stickyBgColor); tableRef.value.$el.getElementsByTagName('table')[0].style.setProperty('--stickyBgColor', stickyBgColor);
tableRef.value.$el.getElementsByTagName('table')[0].style.setProperty('--tableBorderColor', tableBorderColor); tableRef.value.$el.getElementsByTagName('table')[0].style.setProperty('--tableBorderColor', tableBorderColor);
tableRef.value.$el.getElementsByTagName('table')[0].style.setProperty('--tableColumnTitleHeight', table.headerCellHeight + 'px'); tableRef.value.$el.getElementsByTagName('table')[0].style.setProperty('--tableColumnTitleHeight', (denseHeaderComputed.value ? 24 : 48) + 'px');
// if (props.denseHeader || attrs.dense) { let headerPadding = '8px';
if (denseHeaderComputed.value) {
// } headerPadding = '4px';
}
tableRef.value.$el.getElementsByTagName('table')[0].style.setProperty('--tableHeaderPadding', headerPadding);
let bodyPadding = '8px';
if (denseBodyComputed.value) {
bodyPadding = '4px';
}
tableRef.value.$el.getElementsByTagName('table')[0].style.setProperty('--tableBodyPadding', bodyPadding);
tableRef.value.$el.getElementsByTagName('table')[0].style.setProperty('--tableBodyHeight', (denseBodyComputed.value ? 24 : 48) + 'px');
if (denseBottomComputed.value) {
tableRef.value.$el.getElementsByClassName('q-table__bottom')[0].style.setProperty('--tableBottomHeight', 33 + 'px');
tableRef.value.$el.getElementsByClassName('q-table__bottom')[0].style.setProperty('--tableBottomButtonHeight', 24 + 'px');
} else {
tableRef.value.$el.getElementsByClassName('q-table__bottom')[0].style.setProperty('--tableBottomHeight', 50 + 'px');
tableRef.value.$el.getElementsByClassName('q-table__bottom')[0].style.setProperty('--tableBottomButtonHeight', 40 + 'px');
}
}; };
const excludeColumnNum = computed(() => { const excludeColumnNum = computed(() => {
let num = 1; let num = 0;
if (props.sortNo) { if (props.tree) {
return num;
}
if (table.sortNo) {
num += 1;
}
if (table.checkboxSelection) {
num += 1; num += 1;
} }
return num; return num;
@ -1436,7 +1530,7 @@ const handlerStickyChildrenColumn = (item, columns) => {
}; };
const getStickyColumn = () => { const getStickyColumn = () => {
const columns = props.columns.filter((item, index) => { const columns = props.columns.filter((item, index) => {
return index < props.leftColumnStickyNumber; return index < table.stickyNum;
}); });
const arr = []; const arr = [];
columns.forEach((item) => { columns.forEach((item) => {
@ -1444,10 +1538,9 @@ const getStickyColumn = () => {
}); });
return arr; return arr;
}; };
const stickyColumnArr = getStickyColumn();
const moreColumnTitleTableSelectionStyle = computed(() => { const moreColumnTitleTableSelectionStyle = computed(() => {
if (props.leftColumnStickyNumber > 0) { if (table.stickyNum > 0) {
if (props.tree) { if (props.tree) {
return 'z-index: 3;position: sticky;left: 0px;'; return 'z-index: 3;position: sticky;left: 0px;';
} else { } else {
@ -1457,14 +1550,17 @@ const moreColumnTitleTableSelectionStyle = computed(() => {
return ''; return '';
}); });
const moreColumnTitleTableSortNoStyle = computed(() => { const moreColumnTitleTableSortNoStyle = computed(() => {
if (props.sortNo && props.leftColumnStickyNumber > 0) { if (table.checkboxSelection && table.sortNo && table.stickyNum > 0) {
return 'z-index: 3;position: sticky;left: var(--columnWidth-1-1);'; return 'z-index: 3;position: sticky;left: var(--columnWidth-1-1);width: 50px;';
} else if (table.sortNo && table.stickyNum > 0) {
return 'z-index: 3;position: sticky;left: 0px;width: 50px;';
} }
return ''; return '';
}); });
const thStickyLastNameComputed = computed(() => { const thStickyLastNameComputed = computed(() => {
let result = <any>[]; let result = <any>[];
const stickyColumnArr = getStickyColumn();
const lastColumn = getMoreRowColumnTitleIndex(stickyColumnArr[stickyColumnArr.length - 1].name); const lastColumn = getMoreRowColumnTitleIndex(stickyColumnArr[stickyColumnArr.length - 1].name);
if (lastColumn.trIndex === 1) { if (lastColumn.trIndex === 1) {
// 1 // 1
@ -1494,8 +1590,9 @@ const thStyleHandler = (c: any, scope: any) => {
} }
style = c.style; style = c.style;
} }
const stickyColumnArr = getStickyColumn();
if ( if (
props.leftColumnStickyNumber > 0 && table.stickyNum > 0 &&
stickyColumnArr.findIndex((item: any) => { stickyColumnArr.findIndex((item: any) => {
return item.name === c.name; return item.name === c.name;
}) > -1 }) > -1
@ -1604,11 +1701,11 @@ const thStyleHandler = (c: any, scope: any) => {
const tableClassComputed = computed(() => { const tableClassComputed = computed(() => {
const classArr = <string[]>['sticky-header-column-table']; const classArr = <string[]>['sticky-header-column-table'];
if (props.leftColumnStickyNumber && props.leftColumnStickyNumber > 0) { if (table.stickyNum && table.stickyNum > 0) {
if (columnTitleState.columnTitleRowNum > 1) { if (columnTitleState.columnTitleRowNum > 1) {
// //
const stickyColumn = props.columns.filter((item, index) => { const stickyColumn = props.columns.filter((item, index) => {
return index < props.leftColumnStickyNumber; return index < table.stickyNum;
}); });
let tdNum = excludeColumnNum.value; let tdNum = excludeColumnNum.value;
stickyColumn.forEach((item: any, index: number) => { stickyColumn.forEach((item: any, index: number) => {
@ -1621,6 +1718,7 @@ const tableClassComputed = computed(() => {
} }
} }
} else { } else {
console.info('excludeColumnNum======', excludeColumnNum.value);
// //
if (excludeColumnNum.value === 2) { if (excludeColumnNum.value === 2) {
classArr.push('sticky-header-column-table-tr-1' + '-' + 1); classArr.push('sticky-header-column-table-tr-1' + '-' + 1);
@ -1631,7 +1729,7 @@ const tableClassComputed = computed(() => {
classArr.push('sticky-header-column-table-tr-1' + '-' + 1); classArr.push('sticky-header-column-table-tr-1' + '-' + 1);
classArr.push('sticky-header-column-table-td-' + 1); classArr.push('sticky-header-column-table-td-' + 1);
} }
for (let i = 1; i <= props.leftColumnStickyNumber; i++) { for (let i = 1; i <= table.stickyNum; i++) {
classArr.push('sticky-header-column-table-tr-1' + '-' + (i + excludeColumnNum.value)); classArr.push('sticky-header-column-table-tr-1' + '-' + (i + excludeColumnNum.value));
classArr.push('sticky-header-column-table-td-' + (i + excludeColumnNum.value)); classArr.push('sticky-header-column-table-td-' + (i + excludeColumnNum.value));
} }
@ -1699,10 +1797,10 @@ const onDragLeave = (e) => {
}; };
// //
const onDragOver = (e, scope) => { const onDragOver = (e, scope) => {
if (e.offsetY >= table.bodyCellHeight / 2 && dragRowIndex !== scope.rowIndex && e.target.parentNode.parentNode.children.length === scope.rowIndex + 1) { if (e.offsetY >= state.bodyCellHeight / 2 && dragRowIndex !== scope.rowIndex && e.target.parentNode.parentNode.children.length === scope.rowIndex + 1) {
removeDragTopStyle(e); removeDragTopStyle(e);
addDragBottomStyle(e); addDragBottomStyle(e);
} else if (e.offsetY < table.bodyCellHeight / 2 && dragRowIndex !== scope.rowIndex && e.target.parentNode.parentNode.children.length === scope.rowIndex + 1) { } else if (e.offsetY < state.bodyCellHeight / 2 && dragRowIndex !== scope.rowIndex && e.target.parentNode.parentNode.children.length === scope.rowIndex + 1) {
removeDragBottomStyle(e); removeDragBottomStyle(e);
addDragTopStyle(e); addDragTopStyle(e);
} }
@ -1715,7 +1813,7 @@ const onDrop = (e, scope) => {
return; return;
} }
const dragRow = table.rows[dragRowIndex]; const dragRow = table.rows[dragRowIndex];
if (e.offsetY < table.bodyCellHeight / 2 && dragRowIndex !== scope.rowIndex && e.target.parentNode.parentNode.children.length === scope.rowIndex + 1) { if (e.offsetY < state.bodyCellHeight / 2 && dragRowIndex !== scope.rowIndex && e.target.parentNode.parentNode.children.length === scope.rowIndex + 1) {
table.rows.splice(dragRowIndex, 1); table.rows.splice(dragRowIndex, 1);
table.rows.splice(scope.rowIndex - 1, 0, dragRow); table.rows.splice(scope.rowIndex - 1, 0, dragRow);
} else { } else {
@ -1757,7 +1855,7 @@ onMounted(() => {
handlerQueryFormShowField(); handlerQueryFormShowField();
if (props.autoFetchData) { if (props.autoFetchData) {
onRequest({ onRequest({
pagination: table.pagination, pagination: state.pagination,
}); });
} else { } else {
stickyHeaderColumn(); stickyHeaderColumn();
@ -1839,40 +1937,108 @@ defineExpose({
setAddDataUrl, setAddDataUrl,
setEditDataUrl, setEditDataUrl,
setRemoveDataUrl, setRemoveDataUrl,
stickyHeaderColumn,
}); });
const instance = getCurrentInstance(); const instance = getCurrentInstance();
VueTools.expose2Instance(instance); VueTools.expose2Instance(instance);
</script> </script>
<style scoped lang="css"> <style lang="css">
:deep(.q-table__top) { /* :deep(.q-table__top) {
padding: 8px 8px; padding: 8px 8px;
} }
:deep(.q-table th:first-child) { :deep(.q-table tr:first-child th:first-child) {
border-left: 1px solid var(--tableBorderColor); border-left: 1px solid var(--tableBorderColor);
} }
:deep(.q-table tr td:first-child) { :deep(.q-table tr td:first-child) {
border-left: 1px solid var(--tableBorderColor); border-left: 1px solid var(--tableBorderColor);
} }
:deep(.q-table th) { :deep(.q-table__middle .q-table th) {
padding: 7px 8px; padding: var(--tableHeaderPadding) 8px;
background-color: inherit; border-left-width: 0px;
border-right-width: 1px;
border-top-width: 0px;
border-bottom-width: 1px;
}
:deep(.q-table__middle .q-table td) {
height: var(--tableBodyHeight);
padding: var(--tableBodyPadding) 8px;
border-left-width: 0px;
border-right-width: 1px;
border-top-width: 0px;
border-bottom-width: 1px;
}
:deep(.q-table__bottom) {
min-height: var(--tableBottomHeight);
}
:deep(.q-table__control .q-field__control) {
min-height: var(--tableBottomButtonHeight);
}
:deep(.q-field__control q-field__append) {
height: var(--tableBottomButtonHeight);
}
:deep(.q-field__control-container .q-field__native) {
min-height: var(--tableBottomButtonHeight);
padding: 0;
}
:deep(.q-field__control .q-field__marginal) {
height: var(--tableBottomButtonHeight);
} */
.q-table__top {
padding: 8px 8px;
}
.q-table tr:first-child th:first-child {
border-left: 1px solid var(--tableBorderColor);
}
.q-table tr td:first-child {
border-left: 1px solid var(--tableBorderColor);
}
.q-table__middle .q-table th {
padding: var(--tableHeaderPadding) 8px;
border-left-width: 0px; border-left-width: 0px;
border-right-width: 1px; border-right-width: 1px;
border-top-width: 0px; border-top-width: 0px;
border-bottom-width: 1px; border-bottom-width: 1px;
} }
:deep(.q-table td) { .q-table__middle .q-table td {
padding: 7px 8px; height: var(--tableBodyHeight);
background-color: inherit; padding: var(--tableBodyPadding) 8px;
border-left-width: 0px; border-left-width: 0px;
border-right-width: 1px; border-right-width: 1px;
border-top-width: 0px; border-top-width: 0px;
border-bottom-width: 1px; border-bottom-width: 1px;
} }
.q-table__bottom {
min-height: var(--tableBottomHeight);
}
.q-table__control .q-field__control {
min-height: var(--tableBottomButtonHeight);
}
.q-field__control q-field__append {
height: var(--tableBottomButtonHeight);
}
.q-field__control-container .q-field__native {
min-height: var(--tableBottomButtonHeight);
padding: 0;
}
.q-field__control .q-field__marginal {
height: var(--tableBottomButtonHeight);
}
.sticky-header-column-table thead tr { .sticky-header-column-table thead tr {
height: var(--tableColumnTitleHeight); height: var(--tableColumnTitleHeight);
} }

14
io.sc.platform.core.frontend/src/platform/components/toolbar/ChildrenBtn.vue

@ -1,5 +1,5 @@
<template> <template>
<q-item clickable :disable="button[0].enableIf ? !button[0].enableIf(gridProps.selected, gridProps.grid) : false"> <q-item clickable :dense="dense" :disable="button[0].enableIf ? !button[0].enableIf(gridProps.selected, gridProps.grid) : false">
<q-item-section> <q-item-section>
<q-item-label><q-icon v-if="button[0].icon" :name="button[0].icon" left size="20px"></q-icon> {{ button[0].label }}</q-item-label> <q-item-label><q-icon v-if="button[0].icon" :name="button[0].icon" left size="20px"></q-icon> {{ button[0].label }}</q-item-label>
</q-item-section> </q-item-section>
@ -8,16 +8,23 @@
</q-item-section> </q-item-section>
<q-menu anchor="top end" self="top start"> <q-menu anchor="top end" self="top start">
<q-list> <q-list :dense="dense">
<template v-for="(childrenBtn, index) in button" :key="index"> <template v-for="(childrenBtn, index) in button" :key="index">
<template v-if="index === 0 && !childrenBtn.click"></template> <template v-if="index === 0 && !childrenBtn.click"></template>
<q-separator v-else-if="typeof childrenBtn === 'string' && childrenBtn === 'separator'" /> <q-separator v-else-if="typeof childrenBtn === 'string' && childrenBtn === 'separator'" />
<ChildrenBtn v-else-if="Array.isArray(childrenBtn) && childrenBtn.length > 0" :button="childrenBtn"></ChildrenBtn> <ChildrenBtn
v-else-if="Array.isArray(childrenBtn) && childrenBtn.length > 0"
:dense="dense"
:button="childrenBtn"
:grid-props="gridProps"
:button-click="buttonClick"
></ChildrenBtn>
<template v-else> <template v-else>
<q-item <q-item
v-close-popup v-close-popup
clickable clickable
:disable="childrenBtn.enableIf ? !childrenBtn.enableIf(gridProps.selected, gridProps.grid) : false" :disable="childrenBtn.enableIf ? !childrenBtn.enableIf(gridProps.selected, gridProps.grid) : false"
:dense="dense"
@click="buttonClick(childrenBtn)" @click="buttonClick(childrenBtn)"
> >
<q-item-section> <q-item-section>
@ -53,5 +60,6 @@ const props = defineProps({
return () => {}; return () => {};
}, },
}, },
dense: { type: Boolean, default: false },
}); });
</script> </script>

13
io.sc.platform.core.frontend/src/platform/components/toolbar/WToolbar.vue

@ -11,13 +11,14 @@
v-else-if="Array.isArray(btn.data) && btn.data.length > 0" v-else-if="Array.isArray(btn.data) && btn.data.length > 0"
unelevated unelevated
outline outline
:dense="dense"
v-bind="btn.data[0]" v-bind="btn.data[0]"
:split="btn.data[0].click ? true : false" :split="btn.data[0].click ? true : false"
:disable="btn.data[0].enableIf ? !btn.data[0].enableIf(gridProps.selected, gridProps.grid) : false" :disable="btn.data[0].enableIf ? !btn.data[0].enableIf(gridProps.selected, gridProps.grid) : false"
class="class-action-item" class="class-action-item"
@click="buttonClick(btn.data[0])" @click="buttonClick(btn.data[0])"
> >
<q-list> <q-list :dense="dense">
<template v-for="(childrenBtn, childrenIndex) in btn.data" :key="'button_c_' + childrenIndex"> <template v-for="(childrenBtn, childrenIndex) in btn.data" :key="'button_c_' + childrenIndex">
<template v-if="childrenIndex === 0"></template> <template v-if="childrenIndex === 0"></template>
<template v-else> <template v-else>
@ -27,11 +28,13 @@
:button="childrenBtn" :button="childrenBtn"
:grid-props="gridProps" :grid-props="gridProps"
:button-click="buttonClick" :button-click="buttonClick"
:dense="dense"
></ChildrenBtn> ></ChildrenBtn>
<q-item <q-item
v-else v-else
v-close-popup v-close-popup
clickable clickable
:dense="dense"
:disable="childrenBtn.enableIf ? !childrenBtn.enableIf(gridProps.selected) : false" :disable="childrenBtn.enableIf ? !childrenBtn.enableIf(gridProps.selected) : false"
@click="buttonClick(childrenBtn)" @click="buttonClick(childrenBtn)"
> >
@ -48,6 +51,7 @@
:disable="btn.data.enableIf ? !btn.data.enableIf(gridProps.selected, gridProps.grid) : false" :disable="btn.data.enableIf ? !btn.data.enableIf(gridProps.selected, gridProps.grid) : false"
no-wrap no-wrap
outline outline
:dense="dense"
v-bind="btn.data" v-bind="btn.data"
class="class-action-item" class="class-action-item"
@click="buttonClick(btn.data)" @click="buttonClick(btn.data)"
@ -55,8 +59,8 @@
</template> </template>
<!-- moreActions --> <!-- moreActions -->
<q-btn-dropdown v-if="moreActions && moreActions.length > 0" unelevated outline :label="$t('more')" class="class-action-item"> <q-btn-dropdown v-if="moreActions && moreActions.length > 0" unelevated outline :label="$t('more')" :dense="dense" class="class-action-item">
<q-list> <q-list :dense="dense">
<template v-for="(childrenBtn, childrenIndex) in moreActions" :key="'moreAction_' + childrenIndex"> <template v-for="(childrenBtn, childrenIndex) in moreActions" :key="'moreAction_' + childrenIndex">
<q-separator v-if="typeof childrenBtn.data === 'string' && childrenBtn.data === 'separator'" /> <q-separator v-if="typeof childrenBtn.data === 'string' && childrenBtn.data === 'separator'" />
<ChildrenBtn <ChildrenBtn
@ -64,11 +68,13 @@
:button="childrenBtn.data" :button="childrenBtn.data"
:grid-props="gridProps" :grid-props="gridProps"
:button-click="buttonClick" :button-click="buttonClick"
:dense="dense"
></ChildrenBtn> ></ChildrenBtn>
<q-item <q-item
v-else v-else
v-close-popup v-close-popup
clickable clickable
:dense="dense"
:disable="childrenBtn.data.enableIf ? !childrenBtn.data.enableIf(gridProps.selected, gridProps.grid) : false" :disable="childrenBtn.data.enableIf ? !childrenBtn.data.enableIf(gridProps.selected, gridProps.grid) : false"
@click="buttonClick(childrenBtn.data)" @click="buttonClick(childrenBtn.data)"
> >
@ -94,6 +100,7 @@ const props = defineProps({
xGap: { type: Number, default: 4 }, // x xGap: { type: Number, default: 4 }, // x
noIcon: { type: Boolean, default: false }, // icon noIcon: { type: Boolean, default: false }, // icon
align: { type: String, default: 'right' }, // align: { type: String, default: 'right' }, //
dense: { type: Boolean, default: false }, //
buttons: { buttons: {
type: Array, type: Array,
default: () => { default: () => {

6
io.sc.platform.core.frontend/src/platform/components/utils/componentComm.ts

@ -276,7 +276,7 @@ function columnChildrenHandler(item: any, gridColumns: any) {
} else { } else {
columnStyle(item); columnStyle(item);
gridColumns.push({ gridColumns.push({
...{ align: 'left', label: item.name, field: item.name, sortable: true }, ...{ align: 'left', label: item.name, field: item.name, sortable: true, hidden: false },
...item, ...item,
}); });
} }
@ -287,9 +287,7 @@ function columnChildrenHandler(item: any, gridColumns: any) {
export function extractTableColumnsProps(props: any) { export function extractTableColumnsProps(props: any) {
const gridColumns = <any>[]; const gridColumns = <any>[];
if (props.columns && props.columns.length > 0) { if (props.columns && props.columns.length > 0) {
if (props.sortNo && !props.tree) { gridColumns.push({ name: '_sortNo_', align: 'center', label: '序号', field: '_sortNo_', hidden: props.sortNo ? false : true });
gridColumns.push({ name: '_sortNo_', align: 'center', label: '序号', field: '_sortNo_' });
}
props.columns.forEach((item: any) => { props.columns.forEach((item: any) => {
columnChildrenHandler(item, gridColumns); columnChildrenHandler(item, gridColumns);
}); });

112
io.sc.platform.core.frontend/src/views/likm/Grid.vue

@ -3,9 +3,8 @@
<w-grid <w-grid
:title="testGrid.title" :title="testGrid.title"
draggable draggable
:dense="true"
:data-url="testGrid.tableDataUrl" :data-url="testGrid.tableDataUrl"
:checkbox-selection="true" :checkbox-selection="false"
selection="multiple" selection="multiple"
:columns="testGrid.tableColumns" :columns="testGrid.tableColumns"
:toolbar-actions="testGrid.toolbar" :toolbar-actions="testGrid.toolbar"
@ -13,6 +12,7 @@
:editor="testGrid.addEdit" :editor="testGrid.addEdit"
:viewer="testGrid.view" :viewer="testGrid.view"
@selection="selection" @selection="selection"
@update:selected="aaa"
@row-click="rowClick" @row-click="rowClick"
></w-grid> ></w-grid>
</div> </div>
@ -27,6 +27,9 @@ import { IconEnum } from '@/platform/enums';
const selection = (details) => { const selection = (details) => {
// console.info('details====', details); // console.info('details====', details);
}; };
const aaa = (newSelected) => {
console.info('newSelected========', newSelected);
};
const startY = ref(0); const startY = ref(0);
const endY = ref(0); const endY = ref(0);
@ -127,74 +130,57 @@ const testGrid = reactive({
// { label: '', name: 'lastModifyDate', type: 'w-date' }, // { label: '', name: 'lastModifyDate', type: 'w-date' },
], ],
tableColumns: [ tableColumns: [
// { {
// name: 'info', name: 'info',
// label: '', label: '用户信息',
// childrenColumns: [ hidden: true,
childrenColumns: [
{ name: 'loginName', label: '登录名', align: 'right' },
{ name: 'userName', label: '用户名' },
],
},
{
name: 'lxxx',
label: '联系方式',
childrenColumns: [
{ name: 'email', label: '邮箱地址' },
{
name: 'tx',
label: '通讯',
childrenColumns: [
{ name: 'phone', label: '电话' },
{ name: 'mobile', label: '手机号' },
],
},
{ name: 'qq', label: 'QQ' },
],
},
// { name: 'loginName', label: '', align: 'right' }, // { name: 'loginName', label: '', align: 'right' },
// { name: 'userName', label: '' }, // { name: 'userName', label: '' },
// ],
// },
// {
// name: 'lxxx',
// label: '',
// childrenColumns: [
// { name: 'email', label: '' }, // { name: 'email', label: '' },
// {
// name: 'tx',
// label: '',
// childrenColumns: [
// { name: 'phone', label: '' }, // { name: 'phone', label: '' },
// { name: 'mobile', label: '' }, // { name: 'mobile', label: '' },
// ],
// },
// { name: 'qq', label: 'QQ' }, // { name: 'qq', label: 'QQ' },
// ], { name: 'description', label: '描述', width: 400 },
// }, {
// { name: 'description', label: '', width: 400 }, name: 'enable',
// { label: '是否可用',
// name: 'enable', align: 'center',
// label: '', width: 400,
// align: 'center', format: (val, row) => {
// format: (val, row) => {
// return '1<br/>2'; // return '1<br/>2';
// // return { return {
// // _vuecomp_: true, componentType: 'q-icon',
// // type: EnableIcon, attrs: {
// // props: { name: val ? IconEnum.是状态 : IconEnum.否状态,
// // value: val, color: val ? 'green' : 'red',
// // showNoEnable: true, size: 'xs',
// // }, },
// // }; };
// // return { },
// // _vuecomp_: true, },
// // type: 'q-chip', // { name: 'loginName', label: '', align: 'right' },
// // props: { // { name: 'userName', label: '' },
// // label: val ? '' : '',
// // icon: val ? IconEnum. : IconEnum.,
// // color: val ? 'green' : 'red',
// // },
// // };
// // return {
// // componentsType: 'q-icon',
// // attrs: {
// // name: val ? IconEnum. : IconEnum.,
// // color: val ? 'green' : 'red',
// // size: 'sm',
// // },
// // };
// // return {
// // _vuecomp_: true,
// // type: 'w-text',
// // props: {
// // name: 'aaa',
// // label: '',
// // },
// // };
// },
// },
{ name: 'loginName', label: '登录名', align: 'right' },
{ name: 'userName', label: '用户名' },
{ name: 'lastModifier', label: '最后修改人' }, { name: 'lastModifier', label: '最后修改人' },
{ name: 'lastModifyDate', label: '最后修改时间' }, { name: 'lastModifyDate', label: '最后修改时间' },
], ],

41
io.sc.platform.core.frontend/src/views/likm/TreeGrid.vue

@ -6,7 +6,6 @@
draggable draggable
sort-no sort-no
tree tree
:dense="true"
:tree-icon="(row) => {}" :tree-icon="(row) => {}"
:checkbox-selection="true" :checkbox-selection="true"
:data-url="testGrid.dataUrl" :data-url="testGrid.dataUrl"
@ -32,12 +31,12 @@ const { t } = useI18n();
const gridRef = ref(); const gridRef = ref();
const rowClick = (evt, row, rowIndex) => { const rowClick = (evt, row, rowIndex) => {
console.info('evt========', evt); // console.info('evt========', evt);
console.info('row========', row); // console.info('row========', row);
console.info('rowIndex========', rowIndex); // console.info('rowIndex========', rowIndex);
}; };
const selection = (details) => { const selection = (details) => {
console.info('details====', details); // console.info('details====', details);
}; };
const testGrid = { const testGrid = {
title: '菜单列表', title: '菜单列表',
@ -96,7 +95,7 @@ const testGrid = {
{ {
name: 'name', name: 'name',
label: '菜单名称', label: '菜单名称',
width: '50%', width: 500,
format: (val, row) => { format: (val, row) => {
return t(row.name); return t(row.name);
}, },
@ -104,7 +103,6 @@ const testGrid = {
{ {
name: 'icon', name: 'icon',
label: '图标', label: '图标',
width: '50%',
format: (val, row) => { format: (val, row) => {
return { return {
componentType: 'q-icon', componentType: 'q-icon',
@ -115,12 +113,39 @@ const testGrid = {
}; };
}, },
}, },
{ name: 'type', label: '菜单类型' }, // {
// name: 'group',
// label: '',
// childrenColumns: [
// { name: 'type', label: '', width: 500 },
// { name: 'order', label: '' },
// {
// name: 'enable',
// label: '',
// align: 'center',
// width: 200,
// format: (val, row) => {
// return {
// componentType: 'q-icon',
// attrs: {
// name: val ? IconEnum. : IconEnum.,
// color: val ? 'green' : 'red',
// size: 'xs',
// },
// };
// },
// },
// { name: 'lastModifier', label: '' },
// { name: 'lastModifyDate', label: '' },
// ],
// },
{ name: 'type', label: '菜单类型', width: 500 },
{ name: 'order', label: '排序号' }, { name: 'order', label: '排序号' },
{ {
name: 'enable', name: 'enable',
label: '是否可用', label: '是否可用',
align: 'center', align: 'center',
width: 200,
format: (val, row) => { format: (val, row) => {
return { return {
componentType: 'q-icon', componentType: 'q-icon',

Loading…
Cancel
Save