index.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. <template>
  2. <div class="table-page">
  3. <el-table
  4. :key="renderKey"
  5. ref="elTablet"
  6. :row-key="getRowKey"
  7. v-loading="options.loading"
  8. :data="dataSource"
  9. :max-height="options.maxHeight"
  10. :height="options.height"
  11. :stripe="options.stripe"
  12. :border="options.border"
  13. @select="handleSelect"
  14. @select-all="selectAll"
  15. @row-click="handleRowClick"
  16. @selection-change="handleSelectionChange"
  17. @current-change="handleCurrentChange"
  18. highlight-current-row
  19. default-expand-all
  20. :cell-style="cellStyle"
  21. :header-cell-style="{ color: '#515a6e', background: '#f5f5f5' }"
  22. :tree-props="options.treeProps"
  23. :row-style="{ cursor: options.cursor || '' }"
  24. >
  25. <!--selection选择框-->
  26. <el-table-column v-if="options.mutiSelect" type="selection" :reserve-selection="true" style="width: 50px" align="center"> </el-table-column>
  27. <!--序号-->
  28. <el-table-column v-if="options.index" label="序号" type="index" width="100" align="center"> </el-table-column>
  29. <!--数据列-->
  30. <template v-for="(column, index) in columns">
  31. <el-table-column :key="index" :prop="column.prop" :label="column.label" :align="column.align || 'center'" :width="column.width" :fixed="column.fixed" show-overflow-tooltip v-if="!column.isHidden">
  32. <template slot-scope="scope">
  33. <!-- 含有click函数 -->
  34. <template v-if="column.onClick && !column.edit">
  35. <span @click.stop="column.onClick(scope.row, scope.$index, scope)">{{ scope.row[column.prop] }}</span>
  36. </template>
  37. <!-- 带编辑功能列 -->
  38. <template v-else-if="column.edit">
  39. <!-- 编辑状态 -->
  40. <template v-if="scope.row[scope.column.property + 'isShow']">
  41. <el-input :ref="scope.column.property" @blur="handleEditBlur(column, scope)" v-model="scope.row[column.prop]"></el-input>
  42. </template>
  43. <!-- 非编辑状态 -->
  44. <template v-else>
  45. <span class="el-table-edit-text" @click="editCell(scope.row, scope.column)"><i class="el-icon-edit"></i>{{ scope.row[column.prop] }}</span>
  46. </template>
  47. </template>
  48. <!-- 含有render函数 -->
  49. <template v-else-if="column.render">
  50. <RenderDom :row="scope.row" :index="index" :render="column.render" />
  51. </template>
  52. <!-- 有img图片显示 -->
  53. <template v-else-if="column.img">
  54. <img v-if="scope.row[column.prop] && scope.row[column.prop].length > 0" :src="scope.row[column.prop][0]" class="w-img" alt="加载失败" />
  55. <img v-else :src="logo" class="w-img" alt="加载失败" />
  56. </template>
  57. <!-- 字典展示 -->
  58. <template v-else-if="column.dictData">
  59. <span>{{ scope.row[column.prop] | dictFind(dictData, column.dictData, column.dictLabel, column.dictValue) }}</span>
  60. </template>
  61. <!-- 没有render函数且没有图片要显示 -->
  62. <template v-else>
  63. <span>{{ scope.row[column.prop] }}</span>
  64. </template>
  65. <!-- button 操作按钮 btn.statusKey 判断启用的字段 | btn.disableKey 判断禁用的值 | disableKey在启用和禁用时相反-->
  66. <!-- 禁用分两种情况 一种是 disableKey disableKey 是指状态值是 disableKey 的时候禁用 -->
  67. <!-- 另一种是 unDisableKey unDisableKey 是指状态值不是 unDisableKey 的时候禁用 -->
  68. <!-- btn.isChildShow 控制子级是否显示,isParentShow控制父级是否显示 -->
  69. <!-- v-show="hasChildren(scope.row, btn.showType)" -->
  70. <template v-if="column.button">
  71. <template v-for="(btn, i) in column.group">
  72. <el-button
  73. v-show="hasChildren(scope.row, btn.showType)"
  74. v-if="btn.statusKey"
  75. :key="i"
  76. :type="btn.type"
  77. :round="btn.round"
  78. :size="btn.size || 'mini'"
  79. :icon="btn.icon"
  80. :plain="btn.plain"
  81. @click.stop="btn.onClick(scope.row, scope.$index, scope)"
  82. :disabled="unDisabled(scope.row[btn.statusKey], btn.unDisableKey, btn.disableKey)"
  83. >{{ btn.name }}</el-button
  84. >
  85. <el-button
  86. v-show="hasChildren(scope.row, btn.showType)"
  87. v-if="!btn.statusKey"
  88. :key="i"
  89. :type="btn.type"
  90. :round="btn.round"
  91. :size="btn.size || 'mini'"
  92. :icon="btn.icon"
  93. :plain="btn.plain"
  94. @click.stop="btn.onClick(scope.row, scope.$index, scope)"
  95. :disabled="btn.isDisabled"
  96. >{{ btn.name }}</el-button
  97. >
  98. </template>
  99. </template>
  100. <!-- slot 你可以其他常用项 -->
  101. </template>
  102. </el-table-column>
  103. </template>
  104. </el-table>
  105. <!-- 分页 -->
  106. <el-pagination
  107. v-if="pagination"
  108. background
  109. :total="pagination.total"
  110. :page-size="pagination.pageSize"
  111. :page-sizes="[10, 20, 30, 40, 50]"
  112. layout="sizes,total, prev, pager, next, jumper"
  113. @size-change="handleSizeChange"
  114. @current-change="handleIndexChange"
  115. style="padding: 20px; text-align: center"
  116. ></el-pagination>
  117. </div>
  118. </template>
  119. <script>
  120. import { deepClone } from '@/utils'
  121. export default {
  122. name: 'LTable',
  123. components: {
  124. RenderDom: {
  125. functional: true,
  126. props: {
  127. row: Object,
  128. render: Function,
  129. index: Number,
  130. column: {
  131. type: Object,
  132. default: null
  133. }
  134. },
  135. render: (h, data) => {
  136. const params = {
  137. row: data.props.row,
  138. index: data.props.index
  139. }
  140. if (data.props.column) params.column = data.props.column
  141. return data.props.render(h, params)
  142. }
  143. }
  144. },
  145. props: {
  146. dictData: Object, //字典对象
  147. dataSource: Array, // table内容数据
  148. options: Object, // 表格参数控制 maxHeight、stripe 等等...
  149. columns: Array, // 表头
  150. fetch: {
  151. type: Function,
  152. default: function () {}
  153. }, // 获取数据的函数
  154. pagination: Object, // 分页,不传则不显示
  155. typeTable: String,
  156. defaultFetch: {
  157. type: Boolean,
  158. default: true
  159. },
  160. RowKey: {
  161. type: String,
  162. default: 'id'
  163. }
  164. },
  165. computed: {
  166. unDisabled() {
  167. return function (val, unDisableKey, disableKey) {
  168. if (unDisableKey || unDisableKey === 0) {
  169. if (typeof unDisableKey == 'object') {
  170. return !unDisableKey.includes(Number(val))
  171. } else {
  172. return val != unDisableKey
  173. }
  174. }
  175. if (disableKey) {
  176. if (typeof disableKey == 'object') {
  177. return disableKey.includes(Number(val))
  178. } else {
  179. return val == disableKey
  180. }
  181. }
  182. }
  183. }
  184. },
  185. data() {
  186. return {
  187. oldCellData: null,
  188. renderKey: Math.random(),
  189. logo: require('@/assets/logo.png'),
  190. checkedKeys: false,
  191. editStatusMap: {}
  192. }
  193. },
  194. filters: {
  195. dictFind(v, dictData, dictName, dictLabel, dictValue) {
  196. const item = dictData[dictName].find((e) => e[dictValue] == v)
  197. return item ? item[dictLabel] : v
  198. }
  199. },
  200. created() {
  201. if (this.defaultFetch) {
  202. this.options.initTable && this.fetch()
  203. } else {
  204. this.options.initTable
  205. }
  206. },
  207. methods: {
  208. hasChildren(row, showType) {
  209. //父级显示
  210. if (showType && showType == '0') {
  211. //父级判断
  212. if (row.parentId == null || row.parentId == '') {
  213. return true
  214. } else {
  215. return false
  216. }
  217. }
  218. //子级显示
  219. else if (showType && showType == '1') {
  220. //父级判断
  221. if ((row.parentId == null || row.parentId == '') && row.children && row.children.length > 0) {
  222. return false
  223. } else {
  224. return true
  225. }
  226. } else {
  227. return true
  228. }
  229. },
  230. editCell(row, column) {
  231. this.oldCellData = deepClone(row)
  232. this.$set(row, column.property + 'isShow', true)
  233. this.$nextTick(() => {
  234. this.$refs[column.property][0] && this.$refs[column.property][0].focus()
  235. })
  236. },
  237. handleEditBlur(column, scope) {
  238. scope.row[scope.column.property + 'isShow'] = false
  239. column.onChange(scope, this.oldCellData)
  240. },
  241. // table 文本颜色
  242. cellStyle(row, column, rowIndex, columnIndex) {
  243. if (row.column.label == '当前状态' && row.row.status == 1) {
  244. return 'color:#0ED1AA'
  245. } else if (row.column.label == '当前状态' && row.row.status == 2) {
  246. return 'color:#F3384F'
  247. }
  248. },
  249. // pageSize 改变时触发事件
  250. handleSizeChange(size) {
  251. this.pagination.pageSize = size || 10
  252. this.fetch()
  253. },
  254. // currentPage 改变时触发事件
  255. handleIndexChange(current) {
  256. this.pagination.pageIndex = current
  257. this.fetch()
  258. },
  259. handleSelect(selectRows, targetRow) {
  260. // 选中
  261. if (this.isObjectInArray(targetRow, selectRows)) {
  262. this.select(targetRow.children || [], true)
  263. } else {
  264. if (targetRow.children && targetRow.children.length) {
  265. let newTargetRow = this.flattenArray(targetRow.children)
  266. // 两个都选中 1个选中1个未选择 两个都未选中
  267. if (newTargetRow.every((itemB) => selectRows.some((itemA) => this.isEqual(itemA, itemB)))) {
  268. this.select(targetRow.children, false)
  269. } else {
  270. this.select(targetRow.children, true)
  271. this.$refs.elTablet.toggleRowSelection(targetRow, true)
  272. }
  273. }
  274. }
  275. },
  276. // 多选框选择变化触发事件
  277. handleSelectionChange(selection) {
  278. this.$emit('selection-change', selection)
  279. },
  280. // 单选框
  281. handleCurrentChange(selection) {
  282. this.$emit('current-change', selection)
  283. },
  284. // 点击table某一行时触发事件
  285. handleRowClick(row, event, column) {
  286. this.$emit('handleRowClick', row, event, column)
  287. },
  288. // 翻页时,记住上一页的勾选标识
  289. getRowKey(row) {
  290. return this.options.treeProps ? (this.options.rowKey ? row[this.options.rowKey] : row.id || row.value || row.avmatCategoriesCode) : null
  291. },
  292. // 控制 table 子级 全选
  293. selectAll(selection) {
  294. this.checkedKeys = !this.checkedKeys
  295. this.select(this.dataSource, this.checkedKeys)
  296. this.$emit('select-all', selection)
  297. },
  298. toggleRowSelection(row, toggle) {
  299. this.$refs.elTablet.toggleRowSelection(row, toggle)
  300. },
  301. // 控制 table 子级 全选
  302. select(d, c) {
  303. d.forEach((row) => {
  304. this.$refs.elTablet.toggleRowSelection(row, c)
  305. if (row.children && row.children.length > 0) {
  306. this.select(row.children, c)
  307. }
  308. })
  309. },
  310. // 设定某一行为选中行
  311. setCurrentRow(row) {
  312. this.$refs.elTablet.setCurrentRow(row)
  313. },
  314. clearSelection() {
  315. this.checkedKeys = false
  316. this.$refs.elTablet.clearSelection()
  317. },
  318. isObjectInArray(obj, arr) {
  319. return arr.some((item) => {
  320. return Object.keys(obj).every((key) => {
  321. return obj[key] === item[key]
  322. })
  323. })
  324. },
  325. isEqual(objA, objB) {
  326. return JSON.stringify(objA) === JSON.stringify(objB)
  327. },
  328. flattenArray(arr) {
  329. return [].concat(...arr.map((item) => (Array.isArray(item.children) ? this.flattenArray(item.children) : item)))
  330. }
  331. }
  332. }
  333. </script>
  334. <style lang="scss" scoped>
  335. @import './index.scss';
  336. </style>