CommonTable.vue 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. <template>
  2. <div class="tablePaganations">
  3. <!-- <a-config-provider :locale="locale"> -->
  4. <a-table
  5. id="commonTable" class="ant-table-striped" bordered size="small" height="1000px" :loading="isLoading"
  6. :data-source="dataSource" :columns="columns" :row-key="(record) => record.id" :scroll="{ y: yScroll }"
  7. :pagination="havePage ? pagination : false" :row-class-name="(_record, index) => (index % 2 === 1 ? 'table-striped' : null)
  8. " :row-selection="isSelect
  9. ? {
  10. type: selectType === 'radio' ? 'radio' : 'checkbox',
  11. selectedRowKeys: state.selectedRowKeys,
  12. onSelect: selectEvent,
  13. onSelectAll: selectAllEvent,
  14. hideSelectAll: hideSelectAll,
  15. }
  16. : null
  17. " :custom-row="isCustomRowClick ? customRowClick : null" @change="tableChange"
  18. @resize-column="handleResizeColumn"
  19. >
  20. <template v-for="(item, index) in renderArr" #[item]="scope" :key="index">
  21. <slot :name="item" :scope="scope" v-bind="scope || {}" />
  22. </template>
  23. </a-table>
  24. <!-- </a-config-provider> -->
  25. </div>
  26. </template>
  27. <script setup>
  28. import {
  29. useSlots,
  30. ref,
  31. reactive,
  32. defineProps,
  33. defineEmits,
  34. defineExpose,
  35. watch,
  36. onMounted,
  37. } from 'vue';
  38. import { getTableScroll } from '../common/tableScroll.js';
  39. // import zhCN from 'ant-design-vue/lib/locale-provider/zh_CN';
  40. // const locale = ref(zhCN);
  41. const props = defineProps({
  42. // 表格数据
  43. dataSource: {
  44. type: Object,
  45. required: true,
  46. },
  47. // 表头数据
  48. columns: {
  49. type: Object,
  50. required: true,
  51. },
  52. // 是否可选择
  53. isSelect: {
  54. type: Boolean,
  55. },
  56. // 表格loading
  57. isLoading: {
  58. type: Boolean,
  59. },
  60. // 数据总数
  61. total: {
  62. type: Number,
  63. default: 0,
  64. },
  65. // 是否分页
  66. havePage: {
  67. type: Boolean,
  68. default: true,
  69. },
  70. // 是否隐藏全选
  71. hideSelectAll: {
  72. type: Boolean,
  73. default: false,
  74. },
  75. // 单选多选
  76. selectType: {
  77. type: String,
  78. default: 'checkbox',
  79. },
  80. // 分页在右上角
  81. topRight: {
  82. type: Boolean,
  83. default: false,
  84. },
  85. // 表格距底部高度
  86. extraHeight: {
  87. type: Number,
  88. default: undefined,
  89. },
  90. // 选择的key值
  91. selectedKeys: {
  92. type: Array,
  93. default: () => [],
  94. },
  95. // 是否自定义行点击
  96. isCustomRowClick: {
  97. type: Boolean,
  98. default: false,
  99. },
  100. // 自定义默认数量
  101. defaultPageSize: {
  102. type: Number,
  103. default: 20,
  104. },
  105. });
  106. const emit = defineEmits(['getPager', 'getSorter', 'getSelected', 'customRowClick']);
  107. // 分页配置
  108. const pagination = reactive({
  109. showQuickJumper: true,
  110. current: 1,
  111. pageSize: props.defaultPageSize, // 默认每页显示数量
  112. showSizeChanger: true, // 显示可改变每页数量
  113. pageSizeOptions: ['10', '20', '50', '100', '200', '500'], // 每页数量选项值
  114. showTotal: (total, range) =>
  115. range[0] + '-' + range[1] + '条' + ' 共' + total + '条', // 显示总数
  116. onShowSizeChange: (current, pageSize) => showSizeChange(current, pageSize),
  117. onChange: (current, pageSize) => changePage(current, pageSize), //点击页码事件
  118. total: props.total,
  119. position: props.topRight ? ['topRight'] : ['bottomRight'],
  120. });
  121. const yScroll = ref(400); //默认滚动高度
  122. const extraHeight = ref(undefined); //表格距离底部值
  123. // 最后一次排序信息
  124. const lastSorter = reactive({ field: '', order: '' });
  125. // 选择的数据
  126. const state = reactive({
  127. selectedRows: [],
  128. selectedRowKeys: [],
  129. });
  130. onMounted(() => {
  131. if (!props.havePage) {
  132. extraHeight.value = 30;
  133. } else {
  134. extraHeight.value = props.extraHeight;
  135. }
  136. if (props.extraHeight) {
  137. extraHeight.value = props.extraHeight;
  138. }
  139. onResizeTable();
  140. window.onresize = () => {
  141. onResizeTable();
  142. };
  143. });
  144. // 表格位置
  145. const onResizeTable = () => {
  146. yScroll.value = getTableScroll({
  147. extraHeight: extraHeight.value,
  148. id: 'commonTable',
  149. });
  150. };
  151. //点击页码事件
  152. const changePage = (current, size) => {
  153. pagination.current = current;
  154. emit('getPager', pagination.current, size);
  155. };
  156. // 改变每页数量时更新显示
  157. const showSizeChange = (current, pageSize) => {
  158. setTimeout(() => {
  159. pagination.current = 1;
  160. emit('getPager', pagination.current, pageSize);
  161. });
  162. pagination.pageSize = pageSize;
  163. };
  164. // 回到第一页
  165. const backFirstPage = () => {
  166. pagination.current = 1;
  167. emit('getPager', pagination.current, pagination.pageSize);
  168. };
  169. // 伸缩列
  170. const handleResizeColumn = (w, col) => {
  171. col.width = w;
  172. };
  173. // 选择每一项操作
  174. const selectEvent = (record, selected) => {
  175. if (props.selectType === 'radio') {
  176. state.selectedRows = [record];
  177. state.selectedRowKeys = [record.id];
  178. } else {
  179. if (selected) {
  180. state.selectedRows.push(record);
  181. state.selectedRowKeys.push(record.id);
  182. } else {
  183. let index = state.selectedRowKeys.indexOf(record.id);
  184. if (index >= 0) {
  185. state.selectedRows.splice(index, 1);
  186. state.selectedRowKeys.splice(index, 1);
  187. }
  188. }
  189. }
  190. emit('getSelected', state);
  191. };
  192. // 点击以后全选当前分页数据
  193. const selectAllEvent = (selected, selectedRows, changeRows) => {
  194. if (selected) {
  195. changeRows.forEach(item => {
  196. state.selectedRows.push(item);
  197. state.selectedRowKeys.push(item.id);
  198. });
  199. } else {
  200. changeRows.forEach(item => {
  201. let index = state.selectedRowKeys.indexOf(item.id);
  202. if (index >= 0) {
  203. state.selectedRows.splice(index, 1);
  204. state.selectedRowKeys.splice(index, 1);
  205. }
  206. });
  207. }
  208. emit('getSelected', state);
  209. };
  210. // 清空选择
  211. const clear = () => {
  212. state.selectedRowKeys = [];
  213. state.selectedRows = [];
  214. emit('getSelected', state);
  215. };
  216. // 获取排序信息
  217. const tableChange = (pagination, filters, sorter) => {
  218. // pagination, filters 变化时也会触发所以对sorter进行判断限制执行
  219. if (Object.keys(sorter).length > 0) {
  220. if (sorter.field != lastSorter.field && sorter.order != lastSorter.order) {
  221. lastSorter.field = sorter.field;
  222. lastSorter.order = sorter.order;
  223. emit('getSorter', sorter);
  224. }
  225. if (sorter.field != lastSorter.field && sorter.order == lastSorter.order) {
  226. lastSorter.field = sorter.field;
  227. lastSorter.order = sorter.order;
  228. emit('getSorter', sorter);
  229. }
  230. if (sorter.field == lastSorter.field && sorter.order != lastSorter.order) {
  231. lastSorter.field = sorter.field;
  232. lastSorter.order = sorter.order;
  233. emit('getSorter', sorter);
  234. }
  235. }
  236. };
  237. // 自定义行点击
  238. const customRowClick = record => {
  239. return {
  240. onDblclick() {
  241. emit('customRowClick', record);
  242. },
  243. };
  244. };
  245. // 暴露出方法
  246. defineExpose({ backFirstPage, clear });
  247. // 监听total变化
  248. watch(
  249. props,
  250. newData => {
  251. pagination.total = newData.total;
  252. extraHeight.value = newData.extraHeight;
  253. },
  254. { immediate: true, deep: true },
  255. );
  256. watch(
  257. () => props.selectedKeys,
  258. newData => {
  259. state.selectedRowKeys = newData;
  260. state.selectedRows = newData.map(item => props.dataSource.find(data => data.id === item));
  261. emit('getSelected', state);
  262. console.log(state.selectedRows);
  263. },
  264. { immediate: true, deep: true },
  265. );
  266. // 插槽的实例
  267. const slots = useSlots();
  268. const renderArr = Object.keys(slots);
  269. </script>
  270. <style scoped>
  271. .tablePaganations {
  272. width: 100%;
  273. /* margin-top: 8px; */
  274. }
  275. .ant-table-striped :deep(.table-striped) td {
  276. background-color: #fafafa;
  277. }
  278. </style>