data-table.vue 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. <template>
  2. <div id="data-table">
  3. <el-form :model="searchInfo" :inline="true" style="padding:0.9rem 1.875rem ;" size="mini" v-if="useFilter">
  4. <el-form-item v-for="(item, index) in filterList" :key="index">
  5. <template v-if="item.filter === 'select'">
  6. <el-select v-model="searchInfo[item.prop]" size="mini" clearable filterable :placeholder="`请选择${item.label}`" @clear="toClear(item.prop)">
  7. <slot name="options" v-bind="{ item }"></slot>
  8. </el-select>
  9. </template>
  10. <template v-else-if="item.filter === 'date'">
  11. <el-date-picker
  12. v-model="searchInfo[item.prop]"
  13. value-format="yyyy-MM-dd"
  14. format="yyyy-MM-dd"
  15. type="daterange"
  16. range-separator="-"
  17. start-placeholder="开始日期"
  18. end-placeholder="结束日期"
  19. clearable
  20. >
  21. </el-date-picker>
  22. </template>
  23. <template v-else>
  24. <el-input v-model="searchInfo[item.prop]" clearable size="mini" :placeholder="`请输入${item.label}`" @clear="toClear(item.prop)"></el-input>
  25. </template>
  26. </el-form-item>
  27. <el-form-item>
  28. <el-button type="primary" size="mini" @click="filterSearch">查询</el-button>
  29. </el-form-item>
  30. </el-form>
  31. <el-table
  32. ref="table"
  33. row-key="id"
  34. :data="data"
  35. border
  36. stripe
  37. size="mini"
  38. :max-height="height !== null ? height : ''"
  39. @select="handleSelectionChange"
  40. @select-all="handleSelectAll"
  41. v-bind="options"
  42. :show-summary="useSum"
  43. @row-click="rowClick"
  44. >
  45. <el-table-column type="selection" width="55" v-if="select" prop="id" :reserve-selection="true" :show-overflow-tooltip="true"> </el-table-column>
  46. <template v-for="(item, index) in fields">
  47. <template v-if="item.custom">
  48. <el-table-column :key="index" align="center" :label="item.label" v-bind="item.options" :show-overflow-tooltip="true">
  49. <template v-slot="{ row }">
  50. <slot name="custom" v-bind="{ item, row }"></slot>
  51. </template>
  52. </el-table-column>
  53. </template>
  54. <template v-else>
  55. <el-table-column
  56. :key="index"
  57. align="center"
  58. :label="item.label"
  59. :prop="item.prop"
  60. :formatter="toFormatter"
  61. sortable
  62. v-bind="item.options"
  63. :show-overflow-tooltip="true"
  64. >
  65. </el-table-column>
  66. </template>
  67. </template>
  68. <template v-if="opera.length > 0">
  69. <el-table-column label="操作" align="center">
  70. <template v-slot="{ row, $index }">
  71. <template v-for="(item, index) in opera">
  72. <template v-if="display(item, row)">
  73. <el-tooltip v-if="item.icon" :key="index" effect="dark" :content="item.label" placement="bottom">
  74. <el-button
  75. :key="index"
  76. type="text"
  77. :icon="item.icon || ''"
  78. size="mini"
  79. @click="handleOpera(row, item.method, item.confirm, item.methodZh, item.label, $index)"
  80. ></el-button>
  81. </el-tooltip>
  82. <el-button v-else :key="index" type="text" size="mini" @click="handleOpera(row, item.method, item.confirm, item.methodZh, item.label, $index)">
  83. {{ item.label }}
  84. </el-button>
  85. </template>
  86. </template>
  87. </template>
  88. </el-table-column>
  89. </template>
  90. </el-table>
  91. <el-row type="flex" align="middle" justify="end" style="padding-top:1rem" v-if="usePage">
  92. <el-col :span="24" style="text-align:right;">
  93. <el-pagination
  94. background
  95. layout=" total, prev, pager, next"
  96. :page-sizes="[10, 15, 20, 50, 100]"
  97. :total="total"
  98. :page-size="limit"
  99. :current-page.sync="currentPage"
  100. @current-change="changePage"
  101. @size-change="sizeChange"
  102. >
  103. </el-pagination>
  104. </el-col>
  105. </el-row>
  106. </div>
  107. </template>
  108. <script>
  109. import _ from 'lodash';
  110. import dataForm from '@/components/form.vue';
  111. export default {
  112. name: 'data-table',
  113. props: {
  114. fields: { type: Array, required: true },
  115. data: { type: Array, required: true },
  116. opera: { type: Array, default: () => [] },
  117. toFormat: null,
  118. height: null,
  119. select: { type: Boolean, default: false },
  120. selected: { type: Array, default: () => [] },
  121. usePage: { type: Boolean, default: true },
  122. total: { type: Number, default: 0 },
  123. options: null,
  124. useSum: { type: Boolean, default: false },
  125. filter: { type: Array, default: () => [] },
  126. },
  127. components: {},
  128. data: () => ({
  129. pageSelected: [],
  130. currentPage: 1,
  131. limit: _.get(this, `$limit`, undefined) !== undefined ? this.$limit : process.env.VUE_APP_LIMIT * 1 || 10,
  132. searchInfo: {},
  133. useFilter: true,
  134. filterList: [],
  135. }),
  136. created() {},
  137. computed: {},
  138. methods: {
  139. toFormatter(row, column, cellValue, index) {
  140. let this_fields = this.fields.filter(fil => fil.prop === column.property);
  141. if (this_fields.length > 0) {
  142. let format = _.get(this_fields[0], `format`, false);
  143. if (format) {
  144. let res;
  145. if (_.isFunction(format)) {
  146. res = format(cellValue);
  147. } else {
  148. res = this.toFormat({
  149. model: this_fields[0].prop,
  150. value: cellValue,
  151. });
  152. }
  153. return res;
  154. } else return cellValue;
  155. }
  156. },
  157. handleOpera(data, method, confirm = false, methodZh, label, index) {
  158. let self = true;
  159. if (_.isFunction(methodZh)) {
  160. methodZh = methodZh(data);
  161. } else if (!_.isString(methodZh)) {
  162. methodZh = label;
  163. self = false;
  164. }
  165. if (confirm) {
  166. this.$confirm(self ? methodZh : `您确认${methodZh}该数据?`, '提示', {
  167. confirmButtonText: '确定',
  168. cancelButtonText: '取消',
  169. type: 'warning',
  170. })
  171. .then(() => {
  172. this.$emit(method, { data, index });
  173. })
  174. .catch(() => {});
  175. } else {
  176. this.$emit(method, { data, index });
  177. }
  178. },
  179. handleSelectionChange(selection, row) {
  180. // console.log(selection);
  181. // console.log(row);
  182. //根据row是否再pageSelected中,判断是添加还是删除
  183. let res = [];
  184. if (this.pageSelected.find(i => i.id === row.id)) {
  185. res = this.pageSelected.filter(f => f.id !== row.id);
  186. } else {
  187. this.pageSelected.push(row);
  188. res = this.pageSelected;
  189. }
  190. this.$set(this, `pageSelected`, res);
  191. this.$emit(`handleSelect`, _.uniqBy(res, 'id'));
  192. },
  193. handleSelectAll(selection) {
  194. //处于没全选状态,选择之后一定是全选,只有处于全选状态时,才会反选(全取消)
  195. // console.log(selection);
  196. let res = [];
  197. if (selection.length > 0) {
  198. //全选
  199. res = _.uniqBy(this.pageSelected.concat(selection), 'id');
  200. } else {
  201. //全取消
  202. res = _.differenceBy(this.pageSelected, this.data, 'id');
  203. }
  204. this.$set(this, `pageSelected`, res);
  205. this.$emit(`handleSelect`, res);
  206. },
  207. initSelection() {
  208. this.$nextTick(() => {
  209. this.$refs.table.clearSelection();
  210. this.selected.forEach(info => {
  211. let d = this.data.filter(p => p.id === info.id);
  212. if (d.length > 0) this.$refs.table.toggleRowSelection(d[0]);
  213. });
  214. });
  215. },
  216. selectReset() {
  217. this.$refs.table.clearSelection();
  218. },
  219. display(item, row) {
  220. let display = _.get(item, `display`, true);
  221. if (display === true) return true;
  222. else {
  223. let res = display(row);
  224. return res;
  225. }
  226. },
  227. //
  228. changePage(page) {
  229. this.$emit('query', { skip: (page - 1) * this.limit, limit: this.limit, ...this.searchInfo });
  230. },
  231. sizeChange(limit) {
  232. this.limit = limit;
  233. this.currentPage = 1;
  234. this.$emit('query', { skip: 0, limit: this.limit, ...this.searchInfo });
  235. },
  236. getFilterList() {
  237. let res = this.fields.filter(f => _.get(f, 'filter', false));
  238. this.$set(this, `useFilter`, res.length > 0);
  239. res.map(i => {
  240. if (i.filter === 'date' && this.searchInfo[i.porp] === undefined) this.$set(this.searchInfo, i.prop, []);
  241. });
  242. res = [...res, ...this.filter];
  243. this.$set(this, `filterList`, res);
  244. },
  245. filterSearch() {
  246. this.currentPage = 1;
  247. this.$emit('query', { skip: 0, limit: this.limit, ...this.searchInfo });
  248. },
  249. rowClick(row, column, event) {
  250. this.$emit(`rowClick`, row);
  251. },
  252. toClear(prop) {
  253. delete this.searchInfo[prop];
  254. },
  255. },
  256. watch: {
  257. selected: {
  258. handler(val) {
  259. if (val.length > 0) {
  260. this.pageSelected = val;
  261. this.initSelection();
  262. }
  263. },
  264. immediate: true,
  265. },
  266. data: {
  267. handler(val, oval) {
  268. if (this.select) {
  269. this.initSelection();
  270. }
  271. },
  272. },
  273. fields: {
  274. handler(val, oval) {
  275. if (val) this.getFilterList();
  276. },
  277. immediate: true,
  278. },
  279. },
  280. };
  281. </script>
  282. <style lang="less" scoped></style>