grid-control.tsx 7.7 KB
Newer Older
1 2
import { GridModel } from '@ibiz-template/model';
import { useGridController, useNamespace } from '@ibiz-template/vue-util';
3
import {
4
  computed,
5 6 7
  defineComponent,
  getCurrentInstance,
  h,
8
  onUnmounted,
9 10 11
  PropType,
  Ref,
  ref,
12
  watch,
13
} from 'vue';
14
import { IModal } from '@ibiz-template/runtime';
15 16 17 18 19 20 21 22 23 24 25
import { AppGridPagination } from '@/components/common';
import {
  useAppGridPagination,
  useITableColumns,
  useITableEvent,
} from './grid-control.util';
import '@ibiz-template/theme/style/components/widgets/grid/grid.scss';

export const GridControl = defineComponent({
  props: {
    modelData: GridModel,
26
    context: { type: Object as PropType<IContext>, required: true },
27 28 29 30 31 32 33 34 35 36
    params: { type: Object as PropType<IParams>, default: () => ({}) },
    /**
     * 表格行数据默认激活模式
     * - 0 不激活
     * - 1 单击激活
     * - 2 双击激活(默认值)
     *
     * @type {(number | 0 | 1 | 2)}
     */
    gridRowActiveMode: { type: Number, default: 2 },
37
    modal: { type: Object as PropType<IModal> },
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
  },
  setup(props) {
    const { proxy } = getCurrentInstance()!;

    const ns = useNamespace('grid');
    const c = useGridController(
      proxy,
      props.modelData!,
      props.context!,
      props.params,
    );

    const [columns] = useITableColumns(c);
    const { onRowClick, onDbRowClick, onSelectionChange, onSortChange } =
      useITableEvent(c);
    const { onPageChange, onPageReset, onPageSizeChange } =
      useAppGridPagination(c);

56 57 58 59 60 61
    const highlight = computed(() => {
      const ctrlParams =
        props.modelData?.source.getPSControlParam()?.ctrlParams;
      return ctrlParams?.HIGHLIGHT !== 'false';
    });

62 63
    let timer: number | null = null;

64 65
    // iView表格单击行选中没有,必须手动调用选中方法
    const onUIRowClick = (data: IData, index: number) => {
66 67 68 69 70 71 72 73 74 75
      if (timer != null) {
        window.clearTimeout(timer);
      }
      timer = window.setTimeout(() => {
        const gridInstance: IData | undefined = proxy.$refs.grid;
        if (gridInstance) {
          const selectedItem = c.selectedData.find(
            item => item.srfkey === data.srfkey,
          );
          if (selectedItem) {
76 77
            gridInstance.clearCurrentRow();
          }
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
          if (gridInstance.toggleSelect) {
            gridInstance.toggleSelect(index);
          }
        }
        onRowClick(data);
      }, 300);
    };

    const onUIDbRowClick = (data: IData) => {
      if (timer != null) {
        window.clearTimeout(timer);
      }
      const gridInstance: IData | undefined = proxy.$refs.grid;
      if (gridInstance) {
        const selectedItem = c.selectedData.find(
          item => item.srfkey === data.srfkey,
        );
        if (!selectedItem) {
          gridInstance.clearCurrentRow();
97 98
        }
      }
99
      onDbRowClick(data);
100 101
    };

102
    // 给到iView table组件的高度
103 104
    const tableHeight = ref(0);

105
    // 表格外层div的引用
106
    const gridRef: Ref<HTMLElement | null> = ref(null);
107 108

    // 表格分页组件的引用
109 110 111 112
    const girdPaginationRef: Ref<InstanceType<
      typeof AppGridPagination
    > | null> = ref(null);

113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
    // 浏览器ResizeObserver对象
    let resizeObserver: ResizeObserver | null = null;

    // 上次监听到的表格外层div高度,一旦发生变化就重新计算
    let lastGridHeight = 0;

    // 计算表格高度(用于固定头部)
    const calcGridHeight = () => {
      // 不是嵌入视图里的表格才去算高度
      if (gridRef.value && props.modal?.mode !== 'EMBED') {
        if (c.model.source.enablePagingBar && girdPaginationRef.value) {
          const gridPage = girdPaginationRef.value.$el as HTMLElement;
          const gridPageHeight =
            gridPage.offsetHeight +
            parseFloat(window.getComputedStyle(gridPage).paddingTop);
          tableHeight.value = gridRef.value.offsetHeight - gridPageHeight;
        } else {
          tableHeight.value = gridRef.value.offsetHeight;
131
        }
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
      }
      // 如果模型配置了高度走配置的
      if (c.model.source.height > 0) {
        tableHeight.value = c.model.source.height;
      }
    };

    watch(gridRef, (newVal, oldVal) => {
      if (newVal && newVal !== oldVal) {
        calcGridHeight();
        if (window.ResizeObserver && gridRef.value) {
          resizeObserver = new ResizeObserver(entries => {
            // 处理组件高度变化
            const height = entries[0].contentRect.height;
            if (height !== lastGridHeight) {
              calcGridHeight();
              lastGridHeight = height;
            }
          });
          resizeObserver.observe(gridRef.value);
152
        }
153 154 155 156 157 158 159 160
      }
    });

    onUnmounted(() => {
      // 在组件销毁前取消 ResizeObserver 的观察
      if (resizeObserver) {
        resizeObserver.disconnect();
      }
161
    });
162

163 164 165 166
    const tableData = computed(() => {
      return [{ hiddenRow: true }, ...c.items];
    });

167 168 169 170
    return {
      c,
      ns,
      columns,
171
      tableData,
172 173
      onDbRowClick,
      onUIRowClick,
174
      onUIDbRowClick,
175 176 177 178 179
      onSelectionChange,
      onSortChange,
      onPageChange,
      onPageSizeChange,
      onPageReset,
180 181 182
      tableHeight,
      gridRef,
      girdPaginationRef,
183
      highlight,
184 185 186 187 188 189 190 191 192 193 194
    };
  },
  render() {
    if (!this.c.complete) {
      return;
    }

    // 绘制作用域插槽
    const columnSlots: IData = {};
    // 表格列自定义
    this.c.model.columns.forEach(column => {
195 196 197
      if (column.source.columnType === 'GROUPGRIDCOLUMN') {
        return;
      }
198 199
      const columnName = column.codeName;
      columnSlots[columnName] = ({ row, index }: IData) => {
200
        const rowController = this.c.rows[index - 1];
201 202 203 204 205 206 207
        if (row.hiddenRow) {
          return (
            <span style='word-break: break-word;white-space: pre-wrap;'>
              隐藏行的列隐藏行的列隐藏行的列隐藏行的列隐藏行的列隐藏行的列隐藏行的列隐藏行的列隐藏行的列隐藏行的列隐藏行的列隐藏行的列
            </span>
          );
        }
208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
        if (rowController) {
          return h(this.c.providers[columnName].component, {
            props: {
              controller: this.c.columns[columnName],
              row: rowController,
            },
            key: row.srfkey + columnName,
          });
        }
      };
    });

    return (
      <control-layout modelData={this.c.model}>
        <div
223
          ref='gridRef'
224 225 226 227 228 229 230 231
          class={[
            this.ns.b(),
            this.ns.is('show-header', !this.c.model.source.hideHeader),
            this.ns.is('enable-page', this.c.model.source.enablePagingBar),
          ]}
        >
          <i-table
            ref={'grid'}
232
            height={this.tableHeight}
233 234
            class={this.ns.b('content')}
            show-header={!this.c.model.source.hideHeader}
235
            highlight-row={this.c.singleSelect && this.highlight}
236
            data={this.tableData}
237 238
            columns={this.columns}
            on-on-row-click={this.onUIRowClick}
239
            on-on-row-dblclick={this.onUIDbRowClick}
240 241
            on-on-selection-change={this.onSelectionChange}
            on-on-sort-change={this.onSortChange}
242
            row-class-name={(row: IData) => (row.hiddenRow ? 'hidden-row' : '')}
243 244 245 246
            scopedSlots={columnSlots}
          ></i-table>
          {this.c.model.source.enablePagingBar && (
            <AppGridPagination
247
              ref='girdPaginationRef'
248 249 250 251 252 253 254 255 256 257 258 259 260
              total={this.c.total}
              curPage={this.c.curPage}
              size={this.c.size}
              on-change={this.onPageChange}
              on-page-size-change={this.onPageSizeChange}
              on-page-reset={this.onPageReset}
            ></AppGridPagination>
          )}
        </div>
      </control-layout>
    );
  },
});