|
@@ -1,585 +0,0 @@
|
|
|
-<script>
|
|
|
-export default {
|
|
|
- name: "SuperTable",
|
|
|
- props: {
|
|
|
- // 数据
|
|
|
- value: {
|
|
|
- type: [Array],
|
|
|
- require: true,
|
|
|
- },
|
|
|
- // 字典
|
|
|
- dict: {
|
|
|
- type: [Object],
|
|
|
- require: true,
|
|
|
- },
|
|
|
- // 分页
|
|
|
- page: {
|
|
|
- type: [Object],
|
|
|
- require: false,
|
|
|
- },
|
|
|
- // 模板
|
|
|
- columns: {
|
|
|
- type: [Array],
|
|
|
- require: true,
|
|
|
- },
|
|
|
- // 是否显示序号
|
|
|
- index: {
|
|
|
- type: Boolean,
|
|
|
- default: false,
|
|
|
- },
|
|
|
- // 是否显示单选
|
|
|
- radio: {
|
|
|
- type: Boolean,
|
|
|
- default: false,
|
|
|
- },
|
|
|
- // 是否显示多选
|
|
|
- checkbox: {
|
|
|
- type: Boolean,
|
|
|
- default: false,
|
|
|
- },
|
|
|
- // 是否显示分页
|
|
|
- pagination: {
|
|
|
- type: Boolean,
|
|
|
- default: false,
|
|
|
- },
|
|
|
- // 是否列操作
|
|
|
- convenitentOperation: {
|
|
|
- type: Boolean,
|
|
|
- default: false,
|
|
|
- },
|
|
|
- // 是否禁止选择
|
|
|
- selectable: {
|
|
|
- type: Function,
|
|
|
- default: () => {},
|
|
|
- },
|
|
|
- //
|
|
|
- storageKey: {
|
|
|
- type: String,
|
|
|
- },
|
|
|
- showSummary:{
|
|
|
- type:Boolean,
|
|
|
- default:false,
|
|
|
- },
|
|
|
-
|
|
|
- },
|
|
|
- components: {
|
|
|
- ElDictTag: () => import("@/components/DictTag/index.vue"),
|
|
|
- ElDraggable: () => import("@/components/draggable/index.vue"),
|
|
|
- ElFilePreview: () => import("@/components/file-preview/index.vue"),
|
|
|
- ElComputedInput: () => import("@/components/computed-input/index.vue"),
|
|
|
- ElPopoverSelectV2: () => import("@/components/popover-select-v2/index.vue"),
|
|
|
- ElPopoverMultipleSelectV2: () =>
|
|
|
- import("@/components/popover-select-v2/multiple.vue"),
|
|
|
- ElComputedInputV2: () => import("@/components/computed-input-v2/index.vue"),
|
|
|
- ElPopoverTreeSelect: () =>
|
|
|
- import("@/components/popover-tree-select/index.vue"),
|
|
|
- ButtonHide: () => import("./hide.vue"),
|
|
|
- ButtonFreeze: () => import("./freeze.vue"),
|
|
|
- IconHide: () => import("./once/hide.vue"),
|
|
|
- IconSort: () => import("./once/sort.vue"),
|
|
|
- IconFreeze: () => import("./once/freeze.vue"),
|
|
|
- IconFilter: () => import("./once/filters.vue"),
|
|
|
- },
|
|
|
- data() {
|
|
|
- const { columns, storageKey } = this.$props;
|
|
|
- const localColumns = localStorage.getItem(storageKey);
|
|
|
- const innerColumns =
|
|
|
- storageKey && localColumns
|
|
|
- ? JSON.parse(localColumns)
|
|
|
- : columns.map(({ item, attr }) => ({
|
|
|
- attr,
|
|
|
- item: { hidden: true, ...item },
|
|
|
- }));
|
|
|
- return {
|
|
|
- innerColumns: innerColumns,
|
|
|
- rowKey: "id",
|
|
|
- // 选择
|
|
|
- selectData: [],
|
|
|
- selectState: false,
|
|
|
- // 过滤
|
|
|
- filterData: [],
|
|
|
- filterState: false,
|
|
|
- };
|
|
|
- },
|
|
|
- computed: {
|
|
|
- innerValue: {
|
|
|
- get() {
|
|
|
- if (this.filterState) {
|
|
|
- return this.filterData;
|
|
|
- } else if (this.selectState) {
|
|
|
- return this.selectData;
|
|
|
- } else {
|
|
|
- return this.$props.value;
|
|
|
- }
|
|
|
- },
|
|
|
- set(value) {
|
|
|
- this.$emit("input", value);
|
|
|
- },
|
|
|
- },
|
|
|
- showColumns: {
|
|
|
- get() {
|
|
|
- return this.innerColumns.filter(({ item }) => item.hidden);
|
|
|
- },
|
|
|
- set() {},
|
|
|
- },
|
|
|
- filterRules: {
|
|
|
- get() {
|
|
|
- return Object.fromEntries(
|
|
|
- this.innerColumns
|
|
|
- .filter(({ item }) => item.filter && !!item.filter.length)
|
|
|
- .map(({ item }) => [item.key, item.filter])
|
|
|
- );
|
|
|
- },
|
|
|
- set() {},
|
|
|
- },
|
|
|
- },
|
|
|
- watch: {
|
|
|
- filterRules: {
|
|
|
- handler: function (newValue) {
|
|
|
- function multiFilter(array, filters) {
|
|
|
- const filterKeys = Object.keys(filters);
|
|
|
- // filters all elements passing the criteria
|
|
|
- return array.filter((item) => {
|
|
|
- // dynamically validate all filter criteria
|
|
|
- return filterKeys.every((key) => {
|
|
|
- //ignore when the filter is empty Anne
|
|
|
- if (!filters[key].length) return true;
|
|
|
- return !!~filters[key].indexOf(item[key]);
|
|
|
- });
|
|
|
- });
|
|
|
- }
|
|
|
- this.filterState = JSON.stringify(newValue) !== "{}";
|
|
|
- this.filterData = multiFilter(this.$props.value, newValue);
|
|
|
- },
|
|
|
- },
|
|
|
- value:{
|
|
|
- handler: function (newValue) {
|
|
|
- if(this.value.length > 0){
|
|
|
- this.$refs.superTable&& this.$refs.superTable.clearSelection();
|
|
|
- }
|
|
|
- },
|
|
|
- immediate: true,
|
|
|
- deep:true
|
|
|
- }
|
|
|
- },
|
|
|
- methods: {
|
|
|
- //
|
|
|
- onSelectionChange(value) {
|
|
|
- this.selectData = value;
|
|
|
- this.$emit("row-select", this.selectData);
|
|
|
- },
|
|
|
- //
|
|
|
- onRowClick(row, column, event) {
|
|
|
- const { radio, checkbox } = this.$props;
|
|
|
- // 单选
|
|
|
- if (radio) {
|
|
|
- this.$emit("row-select", [row]);
|
|
|
- }
|
|
|
- // 多选
|
|
|
- if (checkbox) {
|
|
|
- this.$refs.superTable.toggleRowSelection(
|
|
|
- this.innerValue.find((item) => item.id === row.id)
|
|
|
- );
|
|
|
- }
|
|
|
- },
|
|
|
- // 宽度
|
|
|
- onWidth(newProp, oldProp, column) {
|
|
|
- this.innerColumns = this.innerColumns.map(({ item, attr }) => ({
|
|
|
- attr,
|
|
|
- item: {
|
|
|
- ...item,
|
|
|
- width: item.key === column.property ? newProp : item.width,
|
|
|
- },
|
|
|
- }));
|
|
|
- if (this.$props.storageKey) {
|
|
|
- localStorage.setItem(
|
|
|
- this.$props.storageKey,
|
|
|
- JSON.stringify(this.innerColumns)
|
|
|
- );
|
|
|
- }
|
|
|
- },
|
|
|
- // 冻结
|
|
|
- onHide(prop) {
|
|
|
- this.$nextTick(() => {
|
|
|
- this.$refs.superTable.doLayout();
|
|
|
- if (this.$props.storageKey) {
|
|
|
- localStorage.setItem(
|
|
|
- this.$props.storageKey,
|
|
|
- JSON.stringify(this.innerColumns)
|
|
|
- );
|
|
|
- }
|
|
|
- });
|
|
|
- },
|
|
|
- // 排序
|
|
|
- onSort(prop) {
|
|
|
- const { key, sort } = prop;
|
|
|
- this.$nextTick(() => {
|
|
|
- this.$refs.superTable.sort(key, sort);
|
|
|
- this.$refs.superTable.doLayout();
|
|
|
- if (this.$props.storageKey) {
|
|
|
- localStorage.setItem(
|
|
|
- this.$props.storageKey,
|
|
|
- JSON.stringify(this.innerColumns)
|
|
|
- );
|
|
|
- }
|
|
|
- });
|
|
|
- },
|
|
|
- // 冻结
|
|
|
- onFreeze() {
|
|
|
- this.$nextTick(() => {
|
|
|
- this.$refs.superTable.doLayout();
|
|
|
- if (this.$props.storageKey) {
|
|
|
- localStorage.setItem(
|
|
|
- this.$props.storageKey,
|
|
|
- JSON.stringify(this.innerColumns)
|
|
|
- );
|
|
|
- }
|
|
|
- });
|
|
|
- },
|
|
|
- // 过滤
|
|
|
- onFilter() {
|
|
|
- this.$nextTick(() => {
|
|
|
- this.$refs.superTable.doLayout();
|
|
|
- if (this.$props.storageKey) {
|
|
|
- localStorage.setItem(
|
|
|
- this.$props.storageKey,
|
|
|
- JSON.stringify(this.innerColumns)
|
|
|
- );
|
|
|
- }
|
|
|
- });
|
|
|
- },
|
|
|
- onFilters(value) {
|
|
|
- const {
|
|
|
- item: { key },
|
|
|
- attr: { dictName },
|
|
|
- } = value;
|
|
|
- let dataList = [];
|
|
|
- const dict = this.dict.type[dictName];
|
|
|
- dataList = Array.from(
|
|
|
- new Set(this.innerValue.map((item) => item[key]).filter((item) => item))
|
|
|
- ).map((item) => ({
|
|
|
- text: dictName
|
|
|
- ? (dict.find((dictItem) => dictItem.value == item) || {}).label
|
|
|
- : item,
|
|
|
- value: item,
|
|
|
- }));
|
|
|
- return dataList;
|
|
|
- },
|
|
|
- // 继承el-table的Method
|
|
|
- extendMethod() {
|
|
|
- const refMethod = Object.entries(this.$refs["superTable"]);
|
|
|
- for (const [key, value] of refMethod) {
|
|
|
- if (!(key.includes("$") || key.includes("_"))) {
|
|
|
- this[key] = value;
|
|
|
- }
|
|
|
- }
|
|
|
- },
|
|
|
- getSummaries({ columns, data }){
|
|
|
-
|
|
|
- const means = [] // 合计
|
|
|
- columns.forEach((column, columnIndex) => {
|
|
|
- if (columnIndex === 0) {
|
|
|
- means.push('合计')
|
|
|
- } else {
|
|
|
- const values = data.map(item => Number(item[column.property]));
|
|
|
-
|
|
|
- let sumColumn = this.showColumns.filter(({item,attr}) => attr.isSummary && item.key === column.property);
|
|
|
-
|
|
|
- // 合计
|
|
|
- // if (!values.every(value => isNaN(value))) {
|
|
|
- if (sumColumn.length) {
|
|
|
- means[columnIndex] = values.reduce((prev, curr) => {
|
|
|
- const value = Number(curr);
|
|
|
- if (!isNaN(value)) {
|
|
|
- return prev + curr;
|
|
|
- } else {
|
|
|
- return prev;
|
|
|
- }
|
|
|
- }, 0);
|
|
|
- means[columnIndex] = means[columnIndex].toFixed(2);
|
|
|
- } else {
|
|
|
- means[columnIndex] = '';
|
|
|
- }
|
|
|
- }
|
|
|
- })
|
|
|
- // sums[index] = sums[index] && sums[index].toFixed(2); // 保留2位小数,解决小数合计列
|
|
|
- return [means]
|
|
|
-
|
|
|
- }
|
|
|
- },
|
|
|
- created() {},
|
|
|
- mounted() {
|
|
|
- this.extendMethod();
|
|
|
- },
|
|
|
- updated() {
|
|
|
- this.$nextTick(()=>{
|
|
|
- this.$refs.superTable.doLayout();
|
|
|
- })
|
|
|
- },
|
|
|
- destroyed() {},
|
|
|
-};
|
|
|
-</script>
|
|
|
-
|
|
|
-<template>
|
|
|
- <div class="el-super-table">
|
|
|
- <ux-grid
|
|
|
- border
|
|
|
- row-key
|
|
|
- use-virtual
|
|
|
- show-overflow
|
|
|
- keep-source
|
|
|
- height="auto"
|
|
|
- ref="superTable"
|
|
|
- v-bind="$attrs"
|
|
|
- v-on="$listeners"
|
|
|
- :data="innerValue"
|
|
|
- :show-summary="showSummary"
|
|
|
- :summary-method="getSummaries"
|
|
|
- :highlight-current-row="radio"
|
|
|
- @row-click="onRowClick"
|
|
|
- @header-dragend="onWidth"
|
|
|
- @selection-change="onSelectionChange"
|
|
|
- style="flex: 1"
|
|
|
- >
|
|
|
- <!-- <el-table
|
|
|
- border
|
|
|
- height="auto"
|
|
|
- ref="superTable"
|
|
|
- v-bind="$attrs"
|
|
|
- v-on="$listeners"
|
|
|
- :row-key="rowKey"
|
|
|
- :data="innerValue"
|
|
|
- :show-summary="showSummary"
|
|
|
- :summary-method="getSummaries"
|
|
|
- :highlight-current-row="radio"
|
|
|
- @row-click="onRowClick"
|
|
|
- @header-dragend="onWidth"
|
|
|
- @selection-change="onSelectionChange"
|
|
|
- style="flex: 1"
|
|
|
- > -->
|
|
|
- <!-- 多选 -->
|
|
|
- <ux-table-column
|
|
|
- v-if="checkbox"
|
|
|
- :column-key="rowKey"
|
|
|
- fixed
|
|
|
- width="60"
|
|
|
- align="center"
|
|
|
- type="checkbox"
|
|
|
- reserve-selection
|
|
|
- >
|
|
|
- </ux-table-column>
|
|
|
- <!-- 序号 -->
|
|
|
- <ux-table-column
|
|
|
- v-if="index"
|
|
|
- :resizable="false"
|
|
|
- fixed
|
|
|
- width="50"
|
|
|
- title="序号"
|
|
|
- align="center"
|
|
|
- class="is-index"
|
|
|
- type="index"
|
|
|
- >
|
|
|
- <!-- <template slot-scope="scope">
|
|
|
- {{ scope.$index + 1 }}
|
|
|
- </template> -->
|
|
|
- </ux-table-column>
|
|
|
- <ux-table-column
|
|
|
- v-for="({ item, attr }, index) in showColumns"
|
|
|
- :key="item.key + index"
|
|
|
- :field="item.key"
|
|
|
- :title="item.title"
|
|
|
- :fixed="item.fixed"
|
|
|
- :width="item.width || 200"
|
|
|
- show-overflow-tooltip
|
|
|
- >
|
|
|
- <template slot="header" slot-scope="scope">
|
|
|
- <template>
|
|
|
- <span v-if="item.require" style="color: #ff4949">*</span>
|
|
|
- <span
|
|
|
- :style="{
|
|
|
- color:
|
|
|
- item.sort ||
|
|
|
- item.fixed ||
|
|
|
- (item.filter && !!item.filter.length)
|
|
|
- ? '#1890ff'
|
|
|
- : '',
|
|
|
- }"
|
|
|
- >
|
|
|
- {{ item.title }}
|
|
|
- </span>
|
|
|
- <template>
|
|
|
- <icon-sort
|
|
|
- v-if="item.sortabled"
|
|
|
- v-model="item.sort"
|
|
|
- @sort="onSort(item)"
|
|
|
- ></icon-sort>
|
|
|
- <icon-freeze
|
|
|
- v-if="item.fixedabled"
|
|
|
- v-model="item.fixed"
|
|
|
- @freeze="onFreeze"
|
|
|
- ></icon-freeze>
|
|
|
- <icon-filter
|
|
|
- v-if="item.filterabled"
|
|
|
- v-model="item.filter"
|
|
|
- :filters="onFilters({ item, attr })"
|
|
|
- @filter="onFilter"
|
|
|
- ></icon-filter>
|
|
|
- <icon-hide
|
|
|
- v-if="item.hiddenabled"
|
|
|
- v-model="item.hidden"
|
|
|
- @hide="onHide"
|
|
|
- ></icon-hide>
|
|
|
- </template>
|
|
|
- </template>
|
|
|
- </template>
|
|
|
- <template slot-scope="scope">
|
|
|
- <slot :name="item.key" v-bind="scope" :item="item" :attr="attr">
|
|
|
- <template v-if="attr.is">
|
|
|
- <component
|
|
|
- v-if="attr.is === 'el-dict-tag'"
|
|
|
- v-bind="attr"
|
|
|
- :size="$attrs.size"
|
|
|
- :value="scope.row[item.key]"
|
|
|
- :options="dict.type[attr.dictName]"
|
|
|
- ></component>
|
|
|
- <component
|
|
|
- v-else-if="attr.is === 'el-popover-select-v2'"
|
|
|
- v-bind="attr"
|
|
|
- v-model="scope.row[item.key]"
|
|
|
- :title="item.title"
|
|
|
- :size="$attrs.size"
|
|
|
- :source.sync="scope.row"
|
|
|
- >
|
|
|
- </component>
|
|
|
- <component
|
|
|
- v-else-if="attr.is === 'el-popover-multiple-select-v2'"
|
|
|
- v-bind="attr"
|
|
|
- v-model="scope.row[item.key]"
|
|
|
- :title="item.title"
|
|
|
- :size="$attrs.size"
|
|
|
- :source.sync="scope.row"
|
|
|
- >
|
|
|
- </component>
|
|
|
- <component
|
|
|
- v-else-if="attr.is === 'el-select'"
|
|
|
- v-bind="attr"
|
|
|
- v-model="scope.row[item.key]"
|
|
|
- :size="$attrs.size"
|
|
|
- >
|
|
|
- <template>
|
|
|
- <el-option
|
|
|
- v-for="item in dict.type[attr.dictName]"
|
|
|
- :key="item.value"
|
|
|
- :label="item.label"
|
|
|
- :value="item.value"
|
|
|
- >
|
|
|
- </el-option>
|
|
|
- </template>
|
|
|
- </component>
|
|
|
- <component
|
|
|
- v-else
|
|
|
- v-bind="attr"
|
|
|
- v-model="scope.row[item.key]"
|
|
|
- :size="$attrs.size"
|
|
|
- style="width: 100%"
|
|
|
- >
|
|
|
- </component
|
|
|
- ></template>
|
|
|
- <template v-else>
|
|
|
- <component v-if="attr.formatter" is="span">{{
|
|
|
- attr.formatter(scope.row)
|
|
|
- }}</component>
|
|
|
- <component v-else is="span">{{
|
|
|
- scope.row[item.key] || "--"
|
|
|
- }}</component>
|
|
|
- </template>
|
|
|
- </slot>
|
|
|
- </template>
|
|
|
- </ux-table-column>
|
|
|
- <slot></slot>
|
|
|
- <!-- </el-table> -->
|
|
|
- </ux-grid>
|
|
|
- <div
|
|
|
- style="
|
|
|
- height: 50px;
|
|
|
- display: flex;
|
|
|
- justify-content: space-between;
|
|
|
- align-items: center;
|
|
|
- "
|
|
|
- :style="{
|
|
|
- height: checkbox || pagination ? '50px' : '0px',
|
|
|
- }"
|
|
|
- >
|
|
|
- <div class="mr-4">
|
|
|
- <!-- <template v-if="checkbox">
|
|
|
- <el-button
|
|
|
- v-if="selectState"
|
|
|
- size="mini"
|
|
|
- @click="selectState = !selectState"
|
|
|
- >
|
|
|
- 所有列
|
|
|
- </el-button>
|
|
|
- <el-button
|
|
|
- v-else
|
|
|
- :disabled="!selectData.length"
|
|
|
- size="mini"
|
|
|
- @click="selectState = !selectState"
|
|
|
- >
|
|
|
- 选择列
|
|
|
- {{ selectData.length ? ` :${selectData.length}` : "" }}
|
|
|
- </el-button>
|
|
|
- </template> -->
|
|
|
- <template v-if="convenitentOperation">
|
|
|
- <button-hide v-model="innerColumns" @change="onHide"></button-hide>
|
|
|
- </template>
|
|
|
- </div>
|
|
|
- <pagination
|
|
|
- v-if="pagination"
|
|
|
- v-show="!selectState"
|
|
|
- :total="page.total"
|
|
|
- :page.sync="page.pageNum"
|
|
|
- :limit.sync="page.pageSize"
|
|
|
- @pagination="$emit('pagination', { ...$event })"
|
|
|
- style="height: 32px; padding: 0 !important; flex: 1; overflow-x: auto"
|
|
|
- />
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-</template>
|
|
|
-
|
|
|
-<style lang="scss" scoped>
|
|
|
-.el-super-table {
|
|
|
- position: relative;
|
|
|
- flex: 1;
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- overflow: auto;
|
|
|
-}
|
|
|
-::v-deep.el-super-table .el-table__header .cell {
|
|
|
- word-break: keep-all;
|
|
|
- white-space: nowrap;
|
|
|
- .icon-sort {
|
|
|
- display: none;
|
|
|
- }
|
|
|
- &:hover .icon-sort {
|
|
|
- display: inline-block;
|
|
|
- }
|
|
|
- .icon-freeze {
|
|
|
- display: none;
|
|
|
- }
|
|
|
- &:hover .icon-freeze {
|
|
|
- display: inline-block;
|
|
|
- }
|
|
|
- .icon-filter {
|
|
|
- display: none;
|
|
|
- }
|
|
|
- &:hover .icon-filter {
|
|
|
- display: inline-block;
|
|
|
- }
|
|
|
- .icon-hide {
|
|
|
- display: none;
|
|
|
- }
|
|
|
- &:hover .icon-hide {
|
|
|
- display: inline-block;
|
|
|
- }
|
|
|
-}
|
|
|
-</style>
|