BasicTable.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  1. <template>
  2. <div ref="wrapRef" :class="getWrapperClass">
  3. <BasicForm
  4. submitOnReset
  5. v-bind="getFormProps"
  6. v-if="getBindValues.useSearchForm"
  7. :tableAction="tableAction"
  8. @register="registerForm"
  9. @submit="handleSearchInfoChange"
  10. @advanced-change="redoHeight"
  11. >
  12. <template #[replaceFormSlotKey(item)]="data" v-for="item in getFormSlotKeys">
  13. <slot :name="item" v-bind="data || {}"></slot>
  14. </template>
  15. </BasicForm>
  16. <!-- antd v3 升级兼容,阻止数据的收集,防止控制台报错 -->
  17. <!-- https://antdv.com/docs/vue/migration-v3-cn -->
  18. <a-form-item-rest>
  19. <Table
  20. ref="tableElRef"
  21. v-bind="getBindValues"
  22. :rowClassName="getRowClassName"
  23. v-show="getEmptyDataIsShowTable"
  24. @resizeColumn="handleResizeColumn"
  25. @change="handleTableChange"
  26. >
  27. <template #[item]="data" v-for="item in Object.keys($slots)" :key="item">
  28. <slot :name="item" v-bind="data || {}"></slot>
  29. </template>
  30. <template #headerCell="{ column }">
  31. <HeaderCell :column="column" />
  32. </template>
  33. <!-- 增加对antdv3.x兼容 -->
  34. <template #bodyCell="data">
  35. <slot name="bodyCell" v-bind="data || {}"></slot>
  36. </template>
  37. </Table>
  38. </a-form-item-rest>
  39. </div>
  40. </template>
  41. <script lang="ts">
  42. import type { BasicTableProps, TableActionType, SizeType, ColumnChangeParam } from './types/table';
  43. import { defineComponent, ref, computed, unref, toRaw, inject, watchEffect } from 'vue';
  44. import { Table } from 'ant-design-vue';
  45. import { BasicForm, useForm } from '/@/components/Form/index';
  46. import { PageWrapperFixedHeightKey } from '/@/components/Page';
  47. import expandIcon from './components/ExpandIcon';
  48. import HeaderCell from './components/HeaderCell.vue';
  49. import { InnerHandlers } from './types/table';
  50. import { usePagination } from './hooks/usePagination';
  51. import { useColumns } from './hooks/useColumns';
  52. import { useDataSource } from './hooks/useDataSource';
  53. import { useLoading } from './hooks/useLoading';
  54. import { useRowSelection } from './hooks/useRowSelection';
  55. import { useTableScroll } from './hooks/useTableScroll';
  56. import { useCustomRow } from './hooks/useCustomRow';
  57. import { useTableStyle } from './hooks/useTableStyle';
  58. import { useTableHeader } from './hooks/useTableHeader';
  59. import { useTableExpand } from './hooks/useTableExpand';
  60. import { createTableContext } from './hooks/useTableContext';
  61. import { useTableFooter } from './hooks/useTableFooter';
  62. import { useTableForm } from './hooks/useTableForm';
  63. import { useDesign } from '/@/hooks/web/useDesign';
  64. import { omit } from 'lodash-es';
  65. import { basicProps } from './props';
  66. import { isFunction } from '/@/utils/is';
  67. import { warn } from '/@/utils/log';
  68. export default defineComponent({
  69. components: {
  70. Table,
  71. BasicForm,
  72. HeaderCell,
  73. },
  74. props: basicProps,
  75. emits: [
  76. 'fetch-success',
  77. 'fetch-error',
  78. 'selection-change',
  79. 'register',
  80. 'row-click',
  81. 'row-dbClick',
  82. 'row-contextmenu',
  83. 'row-mouseenter',
  84. 'row-mouseleave',
  85. 'edit-end',
  86. 'edit-cancel',
  87. 'edit-row-end',
  88. 'edit-change',
  89. 'expanded-rows-change',
  90. 'change',
  91. 'columns-change',
  92. 'table-redo',
  93. ],
  94. setup(props, { attrs, emit, slots, expose }) {
  95. const tableElRef = ref(null);
  96. const tableData = ref<Recordable[]>([]);
  97. const wrapRef = ref(null);
  98. const innerPropsRef = ref<Partial<BasicTableProps>>();
  99. const { prefixCls } = useDesign('basic-table');
  100. const [registerForm, formActions] = useForm();
  101. const getProps = computed(() => {
  102. return { ...props, ...unref(innerPropsRef) } as BasicTableProps;
  103. });
  104. const isFixedHeightPage = inject(PageWrapperFixedHeightKey, false);
  105. watchEffect(() => {
  106. unref(isFixedHeightPage) &&
  107. props.canResize &&
  108. warn("'canResize' of BasicTable may not work in PageWrapper with 'fixedHeight' (especially in hot updates)");
  109. });
  110. const { getLoading, setLoading } = useLoading(getProps);
  111. const { getPaginationInfo, getPagination, setPagination, setShowPagination, getShowPagination } = usePagination(getProps);
  112. const { getRowSelection, getRowSelectionRef, getSelectRows, clearSelectedRowKeys, getSelectRowKeys, deleteSelectRowByKey, setSelectedRowKeys } =
  113. useRowSelection(getProps, tableData, emit);
  114. const {
  115. handleTableChange: onTableChange,
  116. getDataSourceRef,
  117. getDataSource,
  118. getRawDataSource,
  119. setTableData,
  120. updateTableDataRecord,
  121. deleteTableDataRecord,
  122. insertTableDataRecord,
  123. findTableDataRecord,
  124. fetch,
  125. getRowKey,
  126. reload,
  127. getAutoCreateKey,
  128. updateTableData,
  129. } = useDataSource(
  130. getProps,
  131. {
  132. tableData,
  133. getPaginationInfo,
  134. setLoading,
  135. setPagination,
  136. validate: formActions.validate,
  137. clearSelectedRowKeys,
  138. },
  139. emit
  140. );
  141. function handleTableChange(...args) {
  142. onTableChange.call(undefined, ...args);
  143. emit('change', ...args);
  144. // 解决通过useTable注册onChange时不起作用的问题
  145. const { onChange } = unref(getProps);
  146. onChange && isFunction(onChange) && onChange.call(undefined, ...args);
  147. }
  148. const { getViewColumns, getColumns, setCacheColumnsByField, setColumns, getColumnsRef, getCacheColumns } = useColumns(
  149. getProps,
  150. getPaginationInfo
  151. );
  152. const { getScrollRef, redoHeight } = useTableScroll(getProps, tableElRef, getColumnsRef, getRowSelectionRef, getDataSourceRef);
  153. const { customRow } = useCustomRow(getProps, {
  154. setSelectedRowKeys,
  155. getSelectRowKeys,
  156. clearSelectedRowKeys,
  157. getAutoCreateKey,
  158. emit,
  159. });
  160. const { getRowClassName } = useTableStyle(getProps, prefixCls);
  161. const { getExpandOption, expandAll, collapseAll } = useTableExpand(getProps, tableData, emit);
  162. const handlers: InnerHandlers = {
  163. onColumnsChange: (data: ColumnChangeParam[]) => {
  164. emit('columns-change', data);
  165. // support useTable
  166. unref(getProps).onColumnsChange?.(data);
  167. },
  168. };
  169. const { getHeaderProps } = useTableHeader(getProps, slots, handlers);
  170. const { getFooterProps } = useTableFooter(getProps, getScrollRef, tableElRef, getDataSourceRef);
  171. const { getFormProps, replaceFormSlotKey, getFormSlotKeys, handleSearchInfoChange } = useTableForm(getProps, slots, fetch, getLoading);
  172. const getBindValues = computed(() => {
  173. const dataSource = unref(getDataSourceRef);
  174. let propsData: Recordable = {
  175. // ...(dataSource.length === 0 ? { getPopupContainer: () => document.body } : {}),
  176. ...attrs,
  177. customRow,
  178. //树列表展开使用AntDesignVue默认的加减图标 author:scott date:20210914
  179. //expandIcon: slots.expandIcon ? null : expandIcon(),
  180. ...unref(getProps),
  181. ...unref(getHeaderProps),
  182. scroll: unref(getScrollRef),
  183. loading: unref(getLoading),
  184. tableLayout: 'fixed',
  185. rowSelection: unref(getRowSelectionRef),
  186. rowKey: unref(getRowKey),
  187. columns: toRaw(unref(getViewColumns)),
  188. pagination: toRaw(unref(getPaginationInfo)),
  189. dataSource,
  190. footer: unref(getFooterProps),
  191. ...unref(getExpandOption),
  192. };
  193. if (slots.expandedRowRender) {
  194. propsData = omit(propsData, 'scroll');
  195. }
  196. propsData = omit(propsData, ['class', 'onChange']);
  197. return propsData;
  198. });
  199. console.log(777, getBindValues);
  200. const getWrapperClass = computed(() => {
  201. const values = unref(getBindValues);
  202. return [
  203. prefixCls,
  204. attrs.class,
  205. {
  206. [`${prefixCls}-form-container`]: values.useSearchForm,
  207. [`${prefixCls}--inset`]: values.inset,
  208. },
  209. ];
  210. });
  211. const getEmptyDataIsShowTable = computed(() => {
  212. const { emptyDataIsShowTable, useSearchForm } = unref(getProps);
  213. if (emptyDataIsShowTable || !useSearchForm) {
  214. return true;
  215. }
  216. return !!unref(getDataSourceRef).length;
  217. });
  218. function setProps(props: Partial<BasicTableProps>) {
  219. innerPropsRef.value = { ...unref(innerPropsRef), ...props };
  220. }
  221. const tableAction: TableActionType = {
  222. reload,
  223. getSelectRows,
  224. clearSelectedRowKeys,
  225. getSelectRowKeys,
  226. deleteSelectRowByKey,
  227. setPagination,
  228. setTableData,
  229. updateTableDataRecord,
  230. deleteTableDataRecord,
  231. insertTableDataRecord,
  232. findTableDataRecord,
  233. redoHeight,
  234. setSelectedRowKeys,
  235. setColumns,
  236. setLoading,
  237. getDataSource,
  238. getRawDataSource,
  239. setProps,
  240. getRowSelection,
  241. getPaginationRef: getPagination,
  242. getColumns,
  243. getCacheColumns,
  244. emit,
  245. updateTableData,
  246. setShowPagination,
  247. getShowPagination,
  248. setCacheColumnsByField,
  249. expandAll,
  250. collapseAll,
  251. getSize: () => {
  252. return unref(getBindValues).size as SizeType;
  253. },
  254. };
  255. createTableContext({ ...tableAction, wrapRef, getBindValues });
  256. expose(tableAction);
  257. emit('register', tableAction, formActions);
  258. return {
  259. tableElRef,
  260. getBindValues,
  261. getLoading,
  262. registerForm,
  263. handleSearchInfoChange,
  264. getEmptyDataIsShowTable,
  265. handleTableChange,
  266. getRowClassName,
  267. wrapRef,
  268. tableAction,
  269. redoHeight,
  270. handleResizeColumn: (w, col) => {
  271. col.width = w;
  272. },
  273. getFormProps: getFormProps as any,
  274. replaceFormSlotKey,
  275. getFormSlotKeys,
  276. getWrapperClass,
  277. columns: getViewColumns,
  278. };
  279. },
  280. });
  281. </script>
  282. <style lang="less">
  283. @border-color: #cecece4d;
  284. @ventSpace: zxm;
  285. @prefix-cls: ~'@{namespace}-basic-table';
  286. [data-theme='dark'] {
  287. .@{ventSpace}-table-tbody > tr:hover.@{ventSpace}-table-row-selected > td,
  288. .@{ventSpace}-table-tbody > tr.@{ventSpace}-table-row-selected td {
  289. background-color: #262626;
  290. }
  291. .@{prefix-cls} {
  292. //表格选择工具栏样式
  293. .alert {
  294. background-color: #323232;
  295. border-color: #424242;
  296. }
  297. }
  298. }
  299. .@{prefix-cls} {
  300. max-width: 100%;
  301. &-row__striped {
  302. td {
  303. background-color: @app-content-background;
  304. }
  305. }
  306. &-form-container {
  307. padding: 10px;
  308. .@{ventSpace}-form {
  309. padding: 12px 10px 6px 10px;
  310. margin-bottom: 8px;
  311. background-color: @component-background;
  312. border-radius: 2px;
  313. }
  314. }
  315. .@{ventSpace}-tag {
  316. margin-right: 0;
  317. }
  318. .@{ventSpace}-table-wrapper {
  319. padding: 6px;
  320. background-color: @component-background;
  321. border-radius: 2px;
  322. .@{ventSpace}-table-title {
  323. min-height: 40px;
  324. // padding: 0 0 8px 0 !important;
  325. }
  326. .@{ventSpace}-table.@{ventSpace}-table-bordered .@{ventSpace}-table-title {
  327. border: none !important;
  328. }
  329. }
  330. .@{ventSpace}-table {
  331. width: 100%;
  332. overflow-x: hidden;
  333. &-title {
  334. display: flex;
  335. padding: 8px 6px;
  336. border-bottom: none;
  337. justify-content: space-between;
  338. align-items: center;
  339. }
  340. //定义行颜色
  341. .trcolor {
  342. background-color: rgba(255, 192, 203, 0.31);
  343. color: red;
  344. }
  345. //.ant-table-tbody > tr.ant-table-row-selected td {
  346. //background-color: fade(@primary-color, 8%) !important;
  347. //}
  348. }
  349. .@{ventSpace}-pagination {
  350. margin: 10px 0 0 0;
  351. }
  352. .@{ventSpace}-table-footer {
  353. padding: 0;
  354. .@{ventSpace}-table-wrapper {
  355. padding: 0;
  356. }
  357. table {
  358. border: none !important;
  359. }
  360. .@{ventSpace}-table-content {
  361. overflow-x: hidden !important;
  362. // height: 100px;
  363. // max-height: calc(100% - 20px) !important;
  364. overflow-y: scroll !important;
  365. }
  366. td {
  367. padding: 12px 8px;
  368. }
  369. }
  370. //表格选择工具栏样式
  371. .alert {
  372. height: 38px;
  373. background-color: #e6f7ff;
  374. border-color: #91d5ff;
  375. }
  376. &--inset {
  377. .@{ventSpace}-table-wrapper {
  378. padding: 0;
  379. }
  380. }
  381. }
  382. </style>
  383. <style lang="less" scoped>
  384. @ventSpace: zxm;
  385. :deep(.@{ventSpace}-select-dropdown) {
  386. top: 36px !important;
  387. }
  388. </style>