index.vue 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. <template>
  2. <div
  3. v-loading="loading"
  4. element-loading-text="拼命加载中"
  5. element-loading-spinner="el-icon-loading"
  6. element-loading-background="rgba(0, 0, 0, 0.8)"
  7. class="table-wrapper"
  8. >
  9. <el-table
  10. ref="table"
  11. v-el-table-infinite-scroll="load"
  12. :data="dealedTableData"
  13. :header-cell-class-name="headerCellClass"
  14. :span-method="tableSpanMethod"
  15. :tree-props="treeProps"
  16. :row-key="rowKeyTree"
  17. :show-summary="showSummary"
  18. :summary-method="getSummaries"
  19. height="100%"
  20. stripe
  21. fit
  22. border
  23. >
  24. <el-table-column
  25. v-for="col in filteredTableCols"
  26. :key="col.columnName"
  27. :prop="col.columnName"
  28. :label="col.columnLabel"
  29. :width="col.width"
  30. :show-overflow-tooltip="showOverflowTooltip"
  31. >
  32. <template #header>
  33. <el-tooltip
  34. :content="col.columnDescribe || col.columnLabel"
  35. placement="top"
  36. >
  37. <TableHeaderCell
  38. :label="col.columnLabel"
  39. :filter-options="tableDataFilters[col.columnName]"
  40. :filter-values.sync="filterValues[col.columnName]"
  41. filter-style="arrow"
  42. :sortable="!!col.needSort"
  43. :sort-rule.sync="tableDataSortRules[col.columnName]"
  44. />
  45. </el-tooltip>
  46. </template>
  47. </el-table-column>
  48. </el-table>
  49. </div>
  50. </template>
  51. <script>
  52. import TableHeaderCell from '../TableHeaderCell'
  53. import { setTableFilters } from '@/utils/table'
  54. import { Query } from '@/api/dataIntegration'
  55. export default {
  56. name: 'SimpleTable',
  57. components: { TableHeaderCell },
  58. props: {
  59. queryId: {
  60. type: [String, Number],
  61. required: true
  62. },
  63. queryString: {
  64. type: String,
  65. default: ''
  66. },
  67. // 是否显示树形表格
  68. isTree: {
  69. type: Boolean,
  70. default: false
  71. },
  72. // 树形props
  73. treeProps: {
  74. type: Object,
  75. default: function () {
  76. return { children: 'children', hasChildren: 'hasChildren' }
  77. }
  78. },
  79. // 树形标识id
  80. rowKeyTree: {
  81. type: String,
  82. default: 'companyID'
  83. },
  84. // 是否显示合计行
  85. showSummary: {
  86. type: Boolean,
  87. default: false
  88. },
  89. // 不换行,溢出隐藏
  90. showOverflowTooltip: {
  91. type: Boolean,
  92. default: false
  93. }
  94. },
  95. data() {
  96. return {
  97. loading: false,
  98. page: 0,
  99. noMore: false,
  100. tableCols: [], // 表头数据
  101. tableData: [], // 表格数据
  102. tableDataFilters: {}, // 表头-下拉数据
  103. filterValues: {}, // 表头-下拉-选中数据
  104. tableDataSortRules: {}, // 表头-排序
  105. tableGroups: [], // 表格分组规则
  106. spanArr: [] // 表格分组数据缓存
  107. }
  108. },
  109. computed: {
  110. filteredTableCols() {
  111. return this.tableCols.filter(col => col.needShow)
  112. },
  113. dealedTableData() {
  114. const filtered = this.tableData.filter(item => {
  115. let flag = true
  116. Object.entries(this.filterValues).forEach(([key, arr]) => {
  117. if (arr.length && !arr.includes(item[key])) {
  118. flag = false
  119. }
  120. })
  121. return flag
  122. })
  123. const sortRules = Object.entries(this.tableDataSortRules).reduce(
  124. (pre, [key, value]) => {
  125. if (value) {
  126. pre[0].push(key)
  127. value = value === 'ascending' ? 'asc' : 'desc'
  128. pre[1].push(value)
  129. }
  130. return pre
  131. },
  132. [[], []]
  133. )
  134. return this._.orderBy(filtered, sortRules[0], sortRules[1])
  135. }
  136. },
  137. watch: {
  138. queryString: {
  139. handler() {
  140. this.resetTable()
  141. this.queryTableData()
  142. },
  143. immediate: true
  144. },
  145. dealedTableData: {
  146. handler(arr) {
  147. const spanArr = []
  148. let pos = 0
  149. arr.forEach((item, index, arr) => {
  150. if (index === 0) {
  151. spanArr.push(1)
  152. } else {
  153. if (this.tableGroups.every(prop => arr[index][prop] === arr[index - 1][prop])) {
  154. spanArr[pos] += 1
  155. spanArr.push(0)
  156. } else {
  157. spanArr.push(1)
  158. pos = index
  159. }
  160. }
  161. })
  162. this.spanArr = spanArr
  163. },
  164. deep: true
  165. }
  166. },
  167. updated() {
  168. this.$refs['table']?.doLayout()
  169. },
  170. methods: {
  171. load() {
  172. if (!this.isTree) {
  173. if (this.noMore || this.loading) {
  174. return
  175. }
  176. this.queryTableData()
  177. }
  178. },
  179. resetTable() {
  180. this.page = 0
  181. this.noMore = false
  182. this.tableData = []
  183. },
  184. initTableData() {
  185. this.tableDataFilters = {}
  186. this.filteredTableCols.forEach(col => {
  187. this.tableDataFilters[col.columnName] = []
  188. if (col.needGroup) {
  189. this.tableGroups.push(col.columnName)
  190. }
  191. })
  192. setTableFilters(this.tableData, this.tableDataFilters)
  193. },
  194. // 给表头单元格加上 ascending 或 descending 使用 element 自带的排序箭头变色
  195. headerCellClass({ row, column, rowIndex, columnIndex }) {
  196. const classes = []
  197. const rule = this.tableDataSortRules[column.property]
  198. if (rule) {
  199. classes.push(rule)
  200. }
  201. return classes.join(' ')
  202. },
  203. // 分组
  204. tableSpanMethod({ row, column, rowIndex, columnIndex }) {
  205. if (this.tableGroups.includes(column.property)) {
  206. const _row = this.spanArr[rowIndex]
  207. const _col = _row > 0 ? 1 : 0
  208. return {
  209. rowspan: _row,
  210. colspan: _col
  211. }
  212. }
  213. },
  214. // 合计
  215. getSummaries(param) {
  216. const { columns, data } = param
  217. const sums = []
  218. columns.forEach((column, index) => {
  219. this.tableColsCopy.forEach(p => {
  220. if (column.property === p.columnName && p.needCount) {
  221. const values = data.map(item => Number(item[column.property]))
  222. if (!values.every(value => isNaN(value))) {
  223. sums[index] = values.reduce((prev, curr) => {
  224. const value = Number(curr)
  225. if (!isNaN(value)) {
  226. return prev + curr
  227. } else {
  228. return prev
  229. }
  230. }, 0)
  231. sums[index] += ''
  232. }
  233. }
  234. })
  235. })
  236. return sums
  237. },
  238. async queryTableData() {
  239. this.loading = true
  240. try {
  241. const {
  242. code,
  243. returnData: { columnSet, listValues }
  244. } = await Query({
  245. id: this.queryId,
  246. needPage: ++this.page,
  247. dataContent: this.queryString ? { whereString: this.queryString } : []
  248. })
  249. if (Number(code) === 0) {
  250. if (listValues.length === 0) {
  251. this.page--
  252. this.noMore = true
  253. }
  254. this.tableCols = columnSet
  255. this.$emit('get-column-set', columnSet)
  256. this.tableData.push(...listValues)
  257. this.initTableData()
  258. } else {
  259. this.page--
  260. this.$message.error('获取表格数据失败')
  261. }
  262. } catch (error) {
  263. console.log('出错了', error.message || error)
  264. }
  265. this.loading = false
  266. }
  267. }
  268. }
  269. </script>
  270. <style lang="scss" scoped>
  271. .table-wrapper {
  272. width: 100%;
  273. height: 100%;
  274. ::v-deep .el-table {
  275. width: 100%;
  276. .cell {
  277. padding: 0;
  278. text-align: center;
  279. font-size: 14px;
  280. font-family: Helvetica, 'Microsoft YaHei';
  281. letter-spacing: 0;
  282. }
  283. .el-table__header-wrapper {
  284. .cell {
  285. font-weight: bold;
  286. color: #101116;
  287. > .el-checkbox {
  288. display: none;
  289. }
  290. }
  291. }
  292. }
  293. }
  294. </style>